aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt109
-rw-r--r--ChangeLog2336
-rw-r--r--Checklist4
-rw-r--r--Makefile.am36
-rw-r--r--Makefile.in78
-rw-r--r--NEWS117
-rw-r--r--README_d/ChangeLog8
-rw-r--r--README_d/README.cmake100
-rw-r--r--README_d/README.macosx9
-rw-r--r--TODO162
-rw-r--r--aclocal.m41
-rw-r--r--array.c117
-rw-r--r--awk.h387
-rw-r--r--awkgram.c2993
-rw-r--r--awkgram.y902
-rw-r--r--awklib/Makefile.am9
-rw-r--r--awklib/Makefile.in120
-rw-r--r--awklib/eg/lib/have_mpfr.awk9
-rw-r--r--awklib/eg/lib/intdiv.awk20
-rw-r--r--awklib/eg/prog/pi.awk18
-rw-r--r--builtin.c837
-rw-r--r--cint_array.c68
-rw-r--r--cmake/ChangeLog12
-rw-r--r--cmake/Toolchain_clang.cmake19
-rw-r--r--cmake/Toolchain_generic.cmake21
-rw-r--r--cmake/Toolchain_mingw32.cmake23
-rw-r--r--cmake/Toolchain_s390.cmake20
-rw-r--r--cmake/auk.icobin0 -> 5190 bytes
-rwxr-xr-xcmake/basictest553
-rwxr-xr-xcmake/configure58
-rw-r--r--cmake/configure.cmake309
-rwxr-xr-xcmake/docmaker100
-rw-r--r--cmake/package.cmake71
-rw-r--r--cmd.h14
-rw-r--r--command.c71
-rw-r--r--command.y93
-rwxr-xr-xcompile9
-rwxr-xr-xconfig.guess37
-rwxr-xr-xconfig.rpath2
-rwxr-xr-xconfig.sub33
-rw-r--r--configh.in15
-rwxr-xr-xconfigure1119
-rw-r--r--configure.ac122
-rw-r--r--custom.h14
-rw-r--r--debug.c412
-rwxr-xr-xdepcomp41
-rw-r--r--doc/CMakeLists.txt95
-rw-r--r--doc/ChangeLog434
-rw-r--r--doc/Makefile.am34
-rw-r--r--doc/Makefile.in77
-rw-r--r--doc/awkcard.in41
-rw-r--r--doc/gawk.1170
-rw-r--r--doc/gawk.info3504
-rw-r--r--doc/gawk.texi2106
-rw-r--r--doc/gawktexi.in2007
-rw-r--r--doc/gawkworkflow.info1980
-rw-r--r--doc/gawkworkflow.texi2158
-rw-r--r--doc/it/ChangeLog7
-rw-r--r--doc/it/api-figura1.eps536
-rw-r--r--doc/it/api-figura1.fig40
-rw-r--r--doc/it/api-figura1.pdfbin0 -> 9120 bytes
-rw-r--r--doc/it/api-figura1.pngbin0 -> 5747 bytes
-rw-r--r--doc/it/api-figura1.txt24
-rw-r--r--doc/it/api-figura2.eps517
-rw-r--r--doc/it/api-figura2.fig26
-rw-r--r--doc/it/api-figura2.pdfbin0 -> 11596 bytes
-rw-r--r--doc/it/api-figura2.pngbin0 -> 5768 bytes
-rw-r--r--doc/it/api-figura2.txt12
-rw-r--r--doc/it/api-figura3.eps526
-rw-r--r--doc/it/api-figura3.fig29
-rw-r--r--doc/it/api-figura3.pdfbin0 -> 11914 bytes
-rw-r--r--doc/it/api-figura3.pngbin0 -> 5734 bytes
-rw-r--r--doc/it/api-figura3.txt13
-rwxr-xr-xdoc/it/compila_originale.sh16
-rwxr-xr-xdoc/it/compila_smallprint.sh19
-rw-r--r--doc/it/epsf.tex653
-rw-r--r--doc/it/flusso-elaborazione.eps420
-rw-r--r--doc/it/flusso-elaborazione.fig37
-rw-r--r--doc/it/flusso-elaborazione.pdfbin0 -> 9672 bytes
-rw-r--r--doc/it/flusso-elaborazione.pngbin0 -> 6300 bytes
-rw-r--r--doc/it/flusso-elaborazione.txt11
-rw-r--r--doc/it/gawktexi.in45878
-rw-r--r--doc/it/lflashlight-small.xpic20
-rw-r--r--doc/it/lflashlight.eps135
-rw-r--r--doc/it/lflashlight.pdf56
-rw-r--r--doc/it/margini.texi7
-rw-r--r--doc/it/programma-generico.eps228
-rw-r--r--doc/it/programma-generico.fig25
-rw-r--r--doc/it/programma-generico.pdfbin0 -> 5313 bytes
-rw-r--r--doc/it/programma-generico.pngbin0 -> 4151 bytes
-rw-r--r--doc/it/programma-generico.txt4
-rw-r--r--doc/it/rflashlight-small.xpic26
-rw-r--r--doc/it/rflashlight.eps141
-rw-r--r--doc/it/rflashlight.pdf57
-rw-r--r--doc/it/sidebar.awk67
-rw-r--r--doc/it/texinfo.tex11231
-rw-r--r--doc/it/txi-it.tex84
-rw-r--r--doc/it/vettore-elementi.eps159
-rw-r--r--doc/it/vettore-elementi.fig27
-rw-r--r--doc/it/vettore-elementi.pdfbin0 -> 7009 bytes
-rw-r--r--doc/it/vettore-elementi.pngbin0 -> 1032 bytes
-rw-r--r--doc/it/vettore-elementi.txt4
-rw-r--r--doc/texinfo.tex3849
-rw-r--r--doc/wordlist9
-rw-r--r--doc/wordlist2178
-rw-r--r--eval.c186
-rw-r--r--ext.c180
-rw-r--r--extension/CMakeLists.txt84
-rw-r--r--extension/ChangeLog343
-rw-r--r--extension/Makefile.am17
-rw-r--r--extension/Makefile.in77
-rw-r--r--extension/build-aux/ChangeLog18
-rwxr-xr-xextension/build-aux/compile9
-rwxr-xr-xextension/build-aux/config.guess37
-rwxr-xr-xextension/build-aux/config.rpath2
-rwxr-xr-xextension/build-aux/config.sub33
-rwxr-xr-xextension/build-aux/depcomp41
-rwxr-xr-xextension/build-aux/install-sh4
-rw-r--r--extension/configure.ac4
-rw-r--r--extension/filefuncs.c50
-rw-r--r--extension/fnmatch.c19
-rw-r--r--extension/fork.c32
-rw-r--r--extension/gawkfts.c3
-rw-r--r--extension/inplace.c22
-rw-r--r--extension/ordchr.c38
-rw-r--r--extension/readdir.c18
-rw-r--r--extension/readdir_test.c343
-rw-r--r--extension/readfile.c35
-rw-r--r--extension/revoutput.c10
-rw-r--r--extension/revtwoway.c13
-rw-r--r--extension/rwarray.c73
-rw-r--r--extension/rwarray0.c30
-rw-r--r--extension/stack.c10
-rw-r--r--extension/testext.c268
-rw-r--r--extension/time.c14
-rw-r--r--extras/ChangeLog3
-rw-r--r--extras/Makefile.am29
-rw-r--r--extras/Makefile.in529
-rw-r--r--extras/gawk.csh11
-rw-r--r--extras/gawk.sh31
-rw-r--r--field.c709
-rw-r--r--floatcomp.c10
-rw-r--r--floatmagic.h12
-rw-r--r--gawkapi.c416
-rw-r--r--gawkapi.h301
-rw-r--r--gawkmisc.c26
-rw-r--r--gettext.h11
-rw-r--r--helpers/ChangeLog44
-rwxr-xr-xhelpers/test-build.sh52
-rw-r--r--helpers/testdfa.c417
-rw-r--r--helpers/testnet.c8
-rwxr-xr-xhelpers/update-branches.sh37
-rwxr-xr-xinstall-sh4
-rw-r--r--int_array.c120
-rw-r--r--interpret.h210
-rw-r--r--io.c676
-rw-r--r--m4/ChangeLog12
-rw-r--r--m4/arch.m437
-rw-r--r--m4/isc-posix.m424
-rw-r--r--main.c154
-rw-r--r--mbsupport.h10
-rw-r--r--missing_d/ChangeLog14
-rw-r--r--missing_d/getaddrinfo.c19
-rw-r--r--missing_d/getaddrinfo.h2
-rw-r--r--missing_d/snprintf.c10
-rw-r--r--mpfr.c269
-rw-r--r--msg.c16
-rw-r--r--node.c234
-rw-r--r--nonposix.h13
-rw-r--r--old-extension/ChangeLog17
-rw-r--r--old-extension/bindarr.c17
-rw-r--r--old-extension/fileop.c12
-rw-r--r--old-extension/sparr.c14
-rw-r--r--old-extension/spec_array.c22
-rw-r--r--pc/ChangeLog35
-rw-r--r--pc/Makefile11
-rw-r--r--pc/Makefile.tst360
-rw-r--r--pc/config.h31
-rw-r--r--pc/config.sed12
-rw-r--r--pc/gawkmisc.pc58
-rw-r--r--pc/popen.c2
-rw-r--r--po/CMakeLists.txt133
-rw-r--r--po/ChangeLog10
-rw-r--r--po/POTFILES.in19
-rw-r--r--po/it.po1699
-rw-r--r--po/pt_BR.gmobin0 -> 77514 bytes
-rw-r--r--posix/ChangeLog9
-rw-r--r--posix/gawkmisc.c25
-rw-r--r--profile.c559
-rw-r--r--protos.h14
-rw-r--r--re.c159
-rw-r--r--replace.c12
-rw-r--r--str_array.c131
-rw-r--r--support/CMakeLists.txt34
-rw-r--r--support/ChangeLog59
-rw-r--r--support/Makefile.am61
-rw-r--r--support/Makefile.in643
-rw-r--r--support/dfa.c (renamed from dfa.c)2630
-rw-r--r--support/dfa.h (renamed from dfa.h)46
-rw-r--r--support/getopt.c (renamed from getopt.c)0
-rw-r--r--support/getopt.h (renamed from getopt.h)0
-rw-r--r--support/getopt1.c (renamed from getopt1.c)0
-rw-r--r--support/getopt_int.h (renamed from getopt_int.h)0
-rw-r--r--support/intprops.h453
-rw-r--r--support/localeinfo.c113
-rw-r--r--support/localeinfo.h54
-rw-r--r--support/random.c (renamed from random.c)104
-rw-r--r--support/random.h (renamed from random.h)10
-rw-r--r--support/regcomp.c (renamed from regcomp.c)23
-rw-r--r--support/regex.c (renamed from regex.c)2
-rw-r--r--support/regex.h (renamed from regex.h)64
-rw-r--r--support/regex_internal.c (renamed from regex_internal.c)6
-rw-r--r--support/regex_internal.h (renamed from regex_internal.h)2
-rw-r--r--support/regexec.c (renamed from regexec.c)10
-rw-r--r--support/verify.h284
-rw-r--r--support/xalloc.h (renamed from xalloc.h)21
-rw-r--r--symbol.c166
-rw-r--r--test/CMakeLists.txt90
-rw-r--r--test/ChangeLog450
-rw-r--r--test/Makefile.am306
-rw-r--r--test/Makefile.in518
-rw-r--r--test/Maketests197
-rw-r--r--test/README6
-rw-r--r--test/anchor.awk33
-rw-r--r--test/anchor.in3
-rw-r--r--test/anchor.ok6
-rw-r--r--test/apiterm.awk8
-rw-r--r--test/apiterm.in1
-rw-r--r--test/apiterm.ok3
-rw-r--r--[-rwxr-xr-x]test/arrayind1.awk1
-rw-r--r--test/arrayind2.awk8
-rw-r--r--test/arrayind2.ok2
-rw-r--r--test/arrayind3.awk19
-rw-r--r--test/arrayind3.ok2
-rw-r--r--test/arrdbg.awk17
-rw-r--r--test/badargs.ok1
-rw-r--r--test/clos1way6.awk7
-rw-r--r--test/clos1way6.ok3
-rw-r--r--test/dbugeval2.awk4
-rw-r--r--test/dbugeval2.in3
-rw-r--r--test/dbugeval2.ok7
-rw-r--r--test/dbugtypedre1.awk1
-rw-r--r--test/dbugtypedre1.in4
-rw-r--r--test/dbugtypedre1.ok17
-rw-r--r--test/dbugtypedre2.awk1
-rw-r--r--test/dbugtypedre2.in4
-rw-r--r--test/dbugtypedre2.ok15
-rw-r--r--test/dumpvars.ok2
-rw-r--r--test/errno.awk10
-rw-r--r--test/errno.in3
-rw-r--r--test/errno.ok3
-rw-r--r--test/fldterm.awk10
-rw-r--r--test/fldterm.in1
-rw-r--r--test/fldterm.ok2
-rw-r--r--test/forcenum.awk6
-rw-r--r--test/forcenum.ok7
-rw-r--r--test/fpat6.awk8
-rw-r--r--test/fpat6.in13
-rw-r--r--test/fpat6.ok44
-rw-r--r--test/fwtest3.awk7
-rw-r--r--test/fwtest3.ok13
-rw-r--r--test/fwtest4.awk1
-rw-r--r--test/fwtest4.in (renamed from test/fwtest3.in)0
-rw-r--r--test/fwtest4.ok1
-rw-r--r--test/fwtest5.awk2
-rw-r--r--test/fwtest5.in4
-rw-r--r--test/fwtest5.ok4
-rw-r--r--test/fwtest6.awk4
-rw-r--r--test/fwtest6.in1
-rw-r--r--test/fwtest6.ok3
-rw-r--r--test/fwtest7.awk2
-rw-r--r--test/fwtest7.in1
-rw-r--r--test/fwtest7.ok1
-rw-r--r--test/fwtest8.awk2
-rw-r--r--test/fwtest8.in1
-rw-r--r--test/fwtest8.ok2
-rw-r--r--test/getfile.awk35
-rw-r--r--test/getfile.ok17
-rw-r--r--test/gsubind.awk9
-rw-r--r--test/gsubind.ok3
-rw-r--r--test/id.ok3
-rw-r--r--test/ignrcas4.awk7
-rw-r--r--test/ignrcas4.ok2
-rw-r--r--test/intarray.awk19
-rw-r--r--test/intarray.ok0
-rw-r--r--test/lintexp.awk9
-rw-r--r--test/lintexp.ok2
-rw-r--r--test/lintindex.awk10
-rw-r--r--test/lintindex.ok4
-rw-r--r--test/lintint.awk9
-rw-r--r--test/lintint.ok2
-rw-r--r--test/lintlength.awk6
-rw-r--r--test/lintlength.ok2
-rw-r--r--test/lintset.awk5
-rw-r--r--test/lintset.ok1
-rw-r--r--test/mbprintf5.awk1
-rw-r--r--test/mbprintf5.in3
-rw-r--r--test/mbprintf5.ok3
-rw-r--r--test/memleak.awk20
-rw-r--r--test/memleak.ok1
-rw-r--r--test/mktime.awk3
-rw-r--r--test/mktime.in1
-rw-r--r--test/mktime.ok1
-rw-r--r--test/mpfrmemok1.ok2
-rw-r--r--test/mpfrsqrt.awk6
-rw-r--r--test/mpfrstrtonum.awk5
-rw-r--r--test/mpfrstrtonum.ok2
-rw-r--r--test/mpgforcenum.awk5
-rw-r--r--test/mpgforcenum.ok1
-rw-r--r--test/noeffect.awk1
-rw-r--r--test/noeffect.ok1
-rw-r--r--test/nonfatal1.awk6
-rw-r--r--test/nonfatal1.ok2
-rw-r--r--test/nonfatal2.awk5
-rw-r--r--test/nonfatal2.ok1
-rw-r--r--test/nonfatal3.awk6
-rw-r--r--test/nonfatal3.ok1
-rw-r--r--test/patsplit.ok3
-rw-r--r--[-rwxr-xr-x]test/poundbang.awk0
-rw-r--r--test/printfchar.awk7
-rw-r--r--test/printfchar.ok1
-rw-r--r--test/profile10.awk42
-rw-r--r--test/profile10.ok40
-rw-r--r--test/profile4.ok18
-rw-r--r--test/profile5.ok13038
-rw-r--r--test/profile7.awk2
-rw-r--r--test/profile7.ok6
-rw-r--r--test/profile8.ok30
-rw-r--r--test/profile9.awk9
-rw-r--r--test/profile9.ok14
-rw-r--r--test/rand.ok2
-rw-r--r--test/randtest.ok0
-rwxr-xr-xtest/randtest.sh113
-rw-r--r--test/rebuild.awk5
-rw-r--r--test/rebuild.in1
-rw-r--r--test/rebuild.ok2
-rw-r--r--test/rwarray.awk16
-rw-r--r--test/shadowbuiltin.awk10
-rw-r--r--test/shadowbuiltin.ok2
-rw-r--r--test/sourcesplit.ok1
-rw-r--r--test/status-close.awk14
-rw-r--r--test/status-close.ok6
-rw-r--r--test/strftfld.awk3
-rw-r--r--test/strftfld.in1
-rw-r--r--test/strftfld.ok1
-rw-r--r--test/strnum2.awk18
-rw-r--r--test/strnum2.ok4
-rw-r--r--test/strtonum1.awk5
-rw-r--r--test/strtonum1.ok2
-rw-r--r--test/symtab6.ok2
-rw-r--r--test/symtab8.ok2
-rw-r--r--test/testext.ok12
-rw-r--r--test/timeout.awk26
-rw-r--r--test/timeout.ok12
-rw-r--r--test/typedregex1.awk296
-rw-r--r--test/typedregex1.ok37
-rw-r--r--test/typedregex2.awk11
-rw-r--r--test/typedregex2.ok4
-rw-r--r--test/typedregex3.awk11
-rw-r--r--test/typedregex3.ok4
-rw-r--r--test/typeof1.awk9
-rw-r--r--test/typeof1.ok7
-rw-r--r--test/typeof2.awk20
-rw-r--r--test/typeof2.ok6
-rw-r--r--test/typeof3.awk19
-rw-r--r--test/typeof3.ok9
-rw-r--r--test/typeof4.awk13
-rw-r--r--test/typeof4.ok1
-rw-r--r--test/typeof5.awk10
-rw-r--r--test/typeof5.in1
-rw-r--r--test/typeof5.ok4
-rw-r--r--vms/ChangeLog22
-rw-r--r--vms/descrip.mms30
-rw-r--r--vms/vms_gawk.c2
-rw-r--r--vms/vmsbuild.com18
375 files changed, 102283 insertions, 17752 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..0214708c
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,109 @@
+#
+# CMakeLists.txt --- CMake input file for gawk
+#
+# Copyright (C) 2013
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with CMake to produce Makefile
+
+cmake_minimum_required (VERSION 2.6)
+project (gawk C)
+
+include(cmake/configure.cmake)
+
+set (EXTRA_LIBS "")
+
+if (${HAVE_MPFR})
+ set (EXTRA_LIBS ${EXTRA_LIBS} mpfr gmp)
+endif ()
+if (${HAVE_LIBREADLINE})
+ set (EXTRA_LIBS ${EXTRA_LIBS} readline)
+endif ()
+if (${DYNAMIC})
+ set (EXTRA_LIBS ${EXTRA_LIBS} ${CMAKE_DL_LIBS} )
+endif ()
+
+include_directories(${CMAKE_SOURCE_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/support)
+
+if(WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
+ # This is enough to build with MinGW in a native Windows environment
+ # and also with a cross-compiler on OpenSuSE 12.2.
+ # On Ubuntu 12.04 patches to gawk's source code are needed:
+ # - insert #include <windows.h> at the top of awk.h
+ # - remove function execvp from pc/gawkmisc.pc
+ DefineConfigHValue(HAVE_SETENV 1)
+ DefineConfigHValue(HAVE_USLEEP 1)
+ DefineConfigHValue(STDC_HEADERS 1)
+ DefineConfigHValue(HAVE_STRINGIZE 1)
+ include_directories(${CMAKE_SOURCE_DIR}/missing_d)
+ DefineConfigHValue(HAVE_MKSTEMP 1)
+ set (EXTRA_LIBS ${EXTRA_LIBS} ws2_32)
+ # TODO: Eli Zaretskii remined me that the generated
+ # settings in config.h should be the same as those in
+ # pc/config.h. With these settings and DYNAMIC=1
+ # it looks like functions in dynamic libs (extensions) can
+ # be invoked on Windows.
+ DefineConfigHValue(HAVE_GETSYSTEMTIMEASFILETIME 1)
+ set (GAWK_SOURCES ${GAWK_SOURCES} regex.c pc/getid.c pc/gawkmisc.pc pc/popen.c)
+ include_directories(${CMAKE_SOURCE_DIR}/pc)
+endif()
+
+add_subdirectory(support)
+
+set (GAWK_SOURCES ${GAWK_SOURCES}
+ array.c
+ builtin.c
+ cint_array.c
+ command.c
+ debug.c
+ eval.c
+ ext.c
+ field.c
+ floatcomp.c
+ gawkapi.c
+ gawkmisc.c
+ int_array.c
+ io.c
+ main.c
+ mpfr.c
+ msg.c
+ node.c
+ profile.c
+ re.c
+ replace.c
+ str_array.c
+ symbol.c
+ version.c
+)
+
+add_executable (gawk ${GAWK_SOURCES} ${BISON_awkgram_OUTPUTS})
+target_link_libraries (gawk m support ${EXTRA_LIBS})
+install(PROGRAMS ${CMAKE_BINARY_DIR}/gawk${CMAKE_EXECUTABLE_SUFFIX} DESTINATION bin)
+
+# Beware: before building the extension, -DGAWK gets undefined.
+add_subdirectory(extension)
+enable_testing()
+add_subdirectory(test)
+add_subdirectory(doc)
+include(InstallRequiredSystemLibraries)
+set(CPACK_PACKAGING_INSTALL_PREFIX /usr)
+include(cmake/package.cmake)
diff --git a/ChangeLog b/ChangeLog
index 4c34f193..b4f65ac9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,513 @@
(do_run): Treat fatal_tag_valid as an int.
* msg.c (fatal_tag_valid): Change type to int.
+2017-07-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawapi.h: Bring descriptive comments up to date, minor edits.
+ * io.c: Add some initial comments to functions where they were missing.
+
+2017-07-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawkapi.h, gawkapi.c: Typo fixes in comments.
+
+2017-06-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkmisc.c (xmalloc): Remove function now in support/xalloc.h.
+
+2017-06-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ Make pretty-printing include parentheses that were explicitly
+ in the source code. Thanks to Hermann Peifer for the bug report.
+
+ * awk.h (OPCODE): Add Op_parens.
+ * awkgram.y [Grammar]: If pretty-printing, add Op_parens ot end of
+ list for parenthesized expression.
+ * eval.c (optypetab): Add Op_parens.
+ * interpret.h (r_interpret): Ditto.
+ * profile.c (pprint): Ditto. For ?:, don't parenthesize it.
+ (pp_parenthesize): If string starts with left paren, return early.
+ (parenthesize): Don't call div_on_left_mul_on_right.
+ (div_on_left_mul_on_right): Remove function.
+ (pp_concat): Don't add parentheses if expressions already have them.
+ * NEWS: Updated.
+
+2017-06-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Replace malloc/memset combinations with calloc by using the new ezalloc
+ macro.
+ * awkgram.y (yyerror, do_add_srcfile, funcuse): Replace emalloc+memset
+ with ezalloc.
+ * cint_array.c (cint_lookup, cint_copy, tree_lookup, tree_copy,
+ leaf_lookup, leaf_copy): Ditto.
+ * command.y (mk_cmdarg): Ditto.
+ * debug.c (add_item): Ditto.
+ * eval.c (setup_frame): Ditto.
+ * field.c (set_record): Ditto.
+ * gawkapi.c (api_flatten_array_typed): Ditto.
+ * int_array.c (int_copy, grow_int_table): Ditto.
+ * io.c (init_awkpath, iop_alloc): Ditto.
+ * node.c (str2wstr): Ditto.
+ * re.c (make_regexp): Ditto.
+ * str_array.c (str_copy, grow_table): Ditto.
+ * symbol.c (make_params, new_context): Ditto.
+
+2017-06-19 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (ezalloc): Add new macro to allocate memory initialized to zero.
+ (ezalloc_real): New inline function to call calloc.
+ * gawkapi.h (ezalloc): Add new API macro to allocate memory initialized
+ to zero.
+
+2017-06-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (mbc_char_count): Fix code to correctly traverse
+ the string. Thanks to Hermann Peifer for the bug report.
+ * config.guess, config.sub: Update to latest from GNULIB.
+ * gettext.h: Pull in a few nice changes from GNULIB version.
+
+2017-05-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * NEWS: Mention PROCINFO["argv"].
+
+2017-05-24 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (set_FIELDWIDTHS): Add check to protect against blank
+ characters after a `:' skip separator.
+ Fix field number in error message, thanks to a bug report
+ from Michal Jaegermann.
+
+2017-05-23 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (set_FIELDWIDTHS): Simplify the logic and consistentify
+ use of UINT_MAX. Make sure that negative value after : is caught.
+
+2017-05-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * field.c (fw_parse_field): Stop upon hitting the end of the
+ record; this enables correct counting of the number of fields.
+ (set_FIELDWIDTHS): Add `*' at end as meaning ``all the rest
+ of the data on the line.'' Allow skip:* as well.
+ * NEWS: Update information about FIELDWIDTHS.
+
+2017-05-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (add_lint): Make ``no effect'' check smarter about
+ reporting line numbers.
+
+2017-05-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (nextc): Fix to change of 2017-04-24 such that
+ @include works in multibyte locales. Thanks to Hermann
+ Peifer for the bug report.
+
+2017-04-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkgram.y (make_regnode): Fix bug -- we should not set valref to 1
+ when creating a node of type Node_regex, since valref is appropriate
+ only for Node_val nodes. This fixes a bug introduced in commit
+ 687e6594. Also, add an assert to make it clear that this function
+ supports only Node_regex and Node_dynregex.
+ * awk.h (NODE): Restore sref to the `val' subportion, since it is not
+ really needed for Node_regex, now that the bug in make_regnode has
+ been fixed.
+ (valref): Restore macro definition.
+
+2017-04-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (NODE): Additional cleanups. Removed `aq' and `param_list'
+ elements from various unions and removed 'nextp' and
+ `a_opaque' defines. None of these were in use.
+ Rework the comment for valref, per suggestion from
+ Andrew Schorr.
+
+2017-04-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (nextc): Adjust so that 3.1.x behavior is restored
+ whereby --source arguments are concatenated. Thanks to
+ "Neil R. Ormos" <ormos-gnulists17@ormos.org> for the report.
+
+2017-04-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (NODE): Put the `val' subportion back the way it
+ was and move valref (formerly sref) out of the unions
+ entirely. This was the real problem. Rework the corresponding
+ commentary.
+ [valref]: Removed the macro definition.
+
+2017-04-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac: Make letter case usage in the various
+ AC_ARG_ENABLE messages consistent with the rest of configure
+ output.
+ (--disable-mpfr): Add this option to make it easier
+ to check compiles without MPFR. Motivated by:
+ * awk.h (NODE): Rearrange the layout of the 'val' subportion
+ of the union to fix alignment problems when compiling without
+ MPFR. The problem only happened on 64-bit compiles, not
+ 32-bit compiles.
+
+2017-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_intdiv): Use DEREF on the arguments.
+ Thanks to Andrew Schorr for finding the problem.
+ * mpfr.c (do_mpfr_intdiv): Return -1 if numerator or denominator
+ are not valid numbers. Unref various bits first.
+
+2017-04-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * mpfr.c (mpg_format_val): Set STRCUR flag when we're done.
+ Fixes a memory leak. Thanks to valgrind for the report.
+
+ * builtin.c (do_dcgettext): Move declaration of reslen to
+ outside the ifdefs. Thanks to Hermann Peifer for the report.
+
+2017-04-12 Manuel Collado <m-collado@users.sourceforge.net>
+
+ Fix the FPAT bug reported by Ed Morton in the gawk-bug mailing list.
+
+ * awk.h (Regexp): Remove the non_empty flag.
+ * field.c (fpat_parse_field): Restructure the code to reduce complexity
+ and document the new structure.
+
+ * field.c (fpat_parse_field): Further restructuring to avoid
+ invalid reads as reported by valgrind.
+
+2017-04-10 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (enum opcodeval): For the avoidance of doubt, specify that
+ Op_illegal must equal zero.
+ * symbol.c (bcfree): Improve clarity by setting opcode to Op_illegal
+ instead of 0.
+ (free_bc_mempool): Improve clarity by comparing opcode to Op_illegal
+ instead of to 0.
+
+ * field.c (set_FIELDWIDTHS): Set use_chars to awk_true, since its
+ type is awk_bool_t.
+
+2017-04-10 Arnold D. Robbins <arnold@skeeve.com>
+
+ * symbol.c (free_bc_mempool): Change `first' from int to bool.
+
+2017-04-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (fw_parse_field): Edit comment about resetting shift state.
+ * gawkapi.h (awk_fieldwidth_info_t): Make white space more uniform.
+
+2017-04-08 Eli Zaretskii <eliz@gnu.org>
+
+ * main.c (usage, copyleft) [__MINGW32__]:
+ * io.c (non_fatal_flush_std_file, close_io) [__MINGW32__]: Call
+ w32_maybe_set_errno to correctly set errno to EPIPE when appropriate.
+
+ * awk.h (die_via_sigpipe) [__MINGW32__]: MinGW-specific definition.
+
+2017-04-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (INSTRUCTION_POOL): Redefine as an array of structures so we
+ can track allocated blocks.
+ * symbol.c (pools): Make it a pointer to avoid copying.
+ (struct instruction_block): Define structure to hold a block of
+ allocated instructions.
+ (bcfree): Update to use new INSTRUCTION_POOL definition.
+ (bcalloc): Allocate an instruction by searching first on the free
+ list, second for free space in the current block, or third by
+ allocating a new block.
+ (set_context): Update to reflect that pools is now a pointer.
+ (free_bc_mempool): New helper function to free a pool of a certain size.
+ (fre_bcpool): Call free_bc_mempool for each pool.
+
+2017-04-04 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (INSTRUCTION): Add pool_size member.
+ [MAX_INSTRUCTION_ALLOC]: New macro.
+ (INSTRUCTION_POOL): New type.
+ (struct context): Use INSTRUCTION_POOL.
+ * array.c (assoc_list): Reorg the code a bit to make sure
+ to alway free the INSTRUCTIONs allocated for calling a
+ user-supplied sorting function. Based on code by
+ Andrew Schorr.
+ * symbol.c (free_bcpool): Rework to use an INSTRUCTION_POOL.
+ (bcfree, bcalloc): Rework to use separate chains in
+ the instruction pool.
+ (set_context): Update appropriately.
+
+2017-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * field.c (parse_field_func_t): New typedef. Used as needed.
+ (fw_parse_field): Edit comment about resetting shift state.
+ (set_parser): Fix leading comment's style and type of argument.
+ (set_FIELDWIDTHS): Improve the fatal error message.
+ * gawkapi.h: Minor edits in some comments.
+
+2017-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ Cause EPIPE errors to stdout to generate a real SIGPIPE.
+
+ * awk.h (die_via_sigpipe): New macro.
+ * builtin.c (efwrite): Use it.
+ * io.c (non_fatal_flush_std_file): Ditto.
+ * main.c (usage): Ditto.
+
+2017-03-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * io.c (flush_io): Use r_fatal and r_warning for messagefunc
+ in the loop.
+
+2017-03-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (efwrite): Exit successfully upon EPIPE, as SIGPIPE
+ done. Improve error messages upon failure to write.
+ (do_fflush): Update ERRNO for non-fatal flush failures.
+ * io.c (non_fatal_flush_std_file): Update ERRNO when flush is
+ non-fatal.
+ (flush_io): If a redirect is marked non-fatal, only warning,
+ not fatal message.
+
+2017-03-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * config.sub: Updated again.
+
+2017-03-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * NEWS: Document new PROCINFO["FS"] value of "API".
+
+2017-03-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * NEWS: Document new FIELDWIDTHS skip capability and API input parser
+ field parsing enhancement.
+
+2017-03-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_input_buf_t): Update get_record comment regarding the
+ new field_width argument.
+
+2017-03-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_fieldwidth_info_t): Define new structure to contain
+ API field parsing info, replacing the previous awk_input_field_info_t
+ array.
+ (awk_fieldwidth_info_size): Define macro to calculate size of the
+ variable-length awk_fieldwidth_info_t structure.
+ (awk_input_buf_t): Update get_record prototype to update the type
+ of the final field_width argument from 'const awk_input_field_info_t **'
+ to 'const awk_fieldwidth_info_t **'.
+ * awk.h (set_record): Change 3rd argument from
+ 'const awk_input_field_info_t *' to 'const awk_fieldwidth_info_t *'.
+ * io.c (inrec, do_getline_redir, do_getline): Change field_width type
+ from 'const awk_input_field_info_t *' to
+ 'const awk_fieldwidth_info_t *'.
+ (get_a_record): Change field_width argument type from
+ 'const awk_input_field_info_t **' to 'const awk_fieldwidth_info_t **'.
+ * field.c (api_parser_override): Define new boolean to track whether
+ API parsing is currently overriding default parsing behavior.
+ (api_fw): Change type from 'const awk_input_field_info_t *'
+ to 'const awk_fieldwidth_info_t *'.
+ (FIELDWIDTHS): Change type from 'int *' to 'awk_fieldwidth_info_t *'.
+ (set_record): Use new boolean api_parser_override to track whether
+ API parsing override is in effect, since we can no longer discern
+ this from the value of parse_field -- FIELDWIDTHS parsing uses the
+ same function.
+ (calc_mbslen): New function to calculate the length of a multi-byte
+ string.
+ (fw_parse_field): Enhance to support the awk_fieldwidth_info_t
+ structure instead of simply using an array of integer field widths.
+ (api_parse_field): Remove function no longer needed since fw_parse_field
+ now supports both FIELDWIDTHS and API parsing.
+ (set_parser): Use api_parser_override instead of comparing parse_field
+ to api_parse_field.
+ (set_FIELDWIDTHS): Enhance to use new awk_fieldwidth_info_t structure
+ and parse new skip prefix for each field.
+ (current_field_sep): Use api_parser_override flag instead of comparing
+ to api_parse_field.
+ (current_field_sep_str): Ditto.
+
+2017-03-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ Improve handling of EPIPE. Problems reported by
+ Alexandre Ferrieux <alexandre.ferrieux@orange.com>
+ and David Kerns <david.t.kerns@gmail.com>.
+
+ * awk.h (ignore_sigpipe, set_sigpipe_to_default,
+ non_fatal_flush_std): Declare new functions.
+ (ignore_sigpipe, set_sigpipe_to_default,
+ non_fatal_flush_std): New macros.
+ * builtin.c (do_fflush): When nonfatal not in force, flush
+ of stdout/stderr and EPIPE exits, simulating SIGPIPE, as
+ in nawk/mawk. Flush of other redirections with EPIPE now
+ also fatals.
+ (do_system): Use ignore_sipipe and set_sigpipe_to_default
+ instead of uglier inline ifdefed code.
+ * main.c (main): Ditto.
+ * io.c (redirect_string, two_way_open, gawk_popen): Ditto.
+ (flush_io): Use non_fatal_flush_std for stdout and stderr.
+
+ Unrelated:
+
+ * config.guess, config.rpath, config.sub, install-sh:
+ Sync with GNULIB.
+
+2017-03-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac: Some cleanups.
+
+2017-03-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_input_field_info_t): Define new structure to contain
+ API field parsing info.
+ (awk_input_buf_t): Update get_record prototype to use an array of
+ awk_input_field_info_t instead of integers.
+ * awk.h (set_record): Change 3rd argument from 'const int *' to
+ 'const awk_input_field_info_t *'.
+ * field.c (api_fw): Now points to an array of awk_input_field_info_t
+ instead of integers.
+ (set_record): Change 3rd argument to point to an array of
+ awk_input_field_info_t.
+ (api_parse_field): Update parsing logic to use awk_input_field_info_t
+ structures instead of an array of integers.
+ * io.c (inrec, do_getline_redir, do_getline): Change field_width type
+ from 'const int *' to 'const awk_input_field_info_t *'.
+ (get_a_record): Change field_width argument type from 'const int **'
+ to 'const awk_input_field_info_t **'.
+
+2017-03-09 Arnold D. Robbins <arnold@skeeve.com>
+
+ * field.c: Minor style edits.
+
+2017-03-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (normal_parse_field): Renamed from save_parse_field to reflect
+ better its purpose. Added a comment to explain more clearly what's
+ going on.
+ (set_record, set_parser): Rename save_parse_field to normal_parse_field.
+
+2017-03-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_input_buf_t): Remove field_width array and instead
+ add it as a 6th argument to the get_record function. This should
+ not break existing code, since it's fine to ignore the additional
+ argument. Document the behavior of the field_width argument.
+ * io.c (inrec): Pass pointer to field_width array to get_a_record,
+ and then hand it off to set_record.
+ (do_getline_redir): If not reading into a variable, pass pointer to
+ field_width array to get_a_record and then hand it off to set_record.
+ (do_getline): Ditto.
+ (get_a_record): Add a 4th field_width argument to pass through to
+ the API get_record method.
+
+2017-03-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (set_record): Add a new argument containing a field-width
+ array returned by an API parser.
+ (field_sep_type): Add new enum value Using_API.
+ (current_field_sep_str): Declare new function.
+ * field.c (save_parse_field): New static variable to save the
+ parse_field value in cases where it's overridden by API parsing.
+ (api_fw): New static variable to hold pointer to API parser fieldwidth
+ array.
+ (set_record): Add new field-width array argument. If present, API
+ parsing will override the default parsing mechanism.
+ (api_parse_field): New field parser using field widths supplied by the
+ API. This is very similar to the existing fw_parse_field function.
+ (get_field): Fix typo in comment.
+ (set_parser): New function to set default parser and check whether
+ there's an API parser override in effect. Update PROCINFO["FS"] if
+ something has changed.
+ (set_FIELDWIDTHS): Use set_parser and stop updating PROCINFO["FS"].
+ (set_FS): Ditto.
+ (set_FPAT): Ditto.
+ (current_field_sep): Return Using_API when using the API field parsing
+ widths.
+ (current_field_sep_str): New function to return the proper string
+ value for PROCINFO["FS"].
+ * gawkapi.h (awk_input_buf_t): Add field_width array to enable the
+ parser get_record function to supply field widths to override the
+ default gawk field parsing mechanism.
+ * io.c (inrec): Pass iop->public.field_width to set_record as the
+ 3rd argument to enable API field parsing overrides.
+ (do_getline_redir, do_getline): Ditto.
+ * main.c (load_procinfo): Use new current_field_sep_str function
+ instead of switching on the return value from current_field_sep.
+
+2017-02-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (boolval): Return bool instead of int.
+ * eval.c (eval_condition): Same.
+ * io.c (pty_vs_pipe): Same
+ Thanks to Andrew Schorr for pointing these out.
+
+2017-02-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * NEWS: Document that mktime now takes an optional utc-flag argument.
+ * awkgram.y (tokentab): Modify mktime entry to indicate that it may
+ accept two arguments.
+ * builtin.c (mktime_tz): New function to run mktime in an arbitrary
+ time zone. Code was copied from the Linux timegm man page.
+ (do_mktime): Add support for new optional 2nd argument utc-flag by
+ using the new mktime_tz function.
+ (do_strftime): Change do_gmt type from int to bool.
+
+2017-02-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_typeof): Handle arguments that have
+ the NULL_FIELD flag set.
+
+2017-02-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkgram.y (set_profile_text): Improve code clarity by using emalloc
+ to allocate the string instead of abusing estrdup.
+
+2017-02-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (set_profile_next): Allocate an extra byte at the
+ end for the NUL in case we add a sign. Thanks to Andrew Schorr
+ for making me look at this code.
+
+ And later in the same day:
+
+ * awkgram.y (set_profile_next): Undo previous change, since estrdup
+ handles it, but updated the comments.
+
+2017-02-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (mbc_char_count): Remove spurious multiplies by
+ gawk_mb_cur_max. Thanks to Andrew Schorr for making me look
+ at this code.
+
+ Unrelated:
+
+ * awkgram.y (make_profile_number): Renamed to ...
+ (set_profile_next): New function. All calls adjusted. Also improved
+ use at MPFR number case.
+
+2017-01-28 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (inetfile): Replace strncmp with memcmp in a few places, now
+ that we are checking string length beforehand.
+
+2017-01-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (redirect_string): Check explen positive before accessing *str.
+ In lintwarn message, use explen string length. Pass length to inetfile.
+ (devopen): Pass name length to inetfile.
+ Stop assuming that remoteport is NUL-terminated.
+ (two_way_open): Pass name length to inetfile.
+ (inetfile): Stop assuming NUL string termination; add checks to avoid
+ string overrun.
+
+2017-01-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (str_terminate_f): New helper function for terminating a string
+ NODE.
+ (str_terminate): Macro wrapper to call str_terminate_f.
+ (str_restore): New macro to restore the string.
+ * builtin.c (do_strftime): Use str_terminate and str_restore.
+ (do_dcgettext): Ditto, and remove saved_end flag since equivalent
+ to testing (t2 != NULL). Fix overrun bug in calculating result
+ length when !ENABLE_NLS.
+ (do_dcngettext, do_bindtextdomain): Use str_terminate and str_restore.
+ * interpret.h (Op_arrayfor_init, Op_indirect_func_call): Ditto.
+ * str_array.c (env_remove): Ditto.
+
2017-01-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
* interpret.h [UNFIELD]: Fix condition for assignment from
@@ -23,6 +530,118 @@
Thanks to Rafael Fontenelle <rafaelff@gnome.org> and to
Eli Zaretskii <eliz@gnu.org>.
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (do_dcgettext): First argument also needs protection
+ from string overrun.
+ (do_dcngettext): Need to terminate string1 and string2 also,
+ and replace strlen(the_result), which could overrun.
+ (do_bindtextdomain): Terminate both string args, and eliminate
+ saved_end boolean which is redundant with (t2 != NULL).
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * interpret.h (Op_arrayfor_init): Protect against string overrun
+ on sorting method.
+ (Op_indirect_func_call): Terminate function name.
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * str_array.c (env_remove): Terminate string before calling unsetenv.
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * node.c (is_hex): Add a new argument pointing to the end of the string
+ so we can check for string overrun.
+ (r_force_number): Pass string end to is_hex.
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (get_numbase): Add string length argument so we can operate
+ on unterminated strings.
+ * awkgram.y: Call get_numbase with string length, and fix off-by-one
+ error in length passed to nondec2awknum: should be strlen(tokstart)-1
+ based on surrounding code.
+ * builtin.c (do_strtonum): Pass string length to get_numbase.
+ (nondec2awknum): Check string length before accessing characters.
+ * mpfr.c (force_mpnum): Pass string length to get_numbase.
+ * node.c (r_force_number): Pass string length to get_numbase.
+ (get_numbase): Add string length argument and honor it.
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (do_strftime): If format argument is passed, we need
+ to terminate it in case it's a field variable.
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * node.c (r_format_val): Before we free s->stptr, make sure that it
+ was malloced.
+ (wstr2str): Add comment explaining why it's safe to free n->stptr
+ without doing any checks.
+ * mpfr.c (mpg_format_val): Ditto. And no need to reset the STRCUR flag
+ that we just checked.
+
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (enum block_id): Remove BLOCK_INVALID, since it serves no
+ useful purpose and seems to slow things down a bit.
+ * node.c (nextfree): Remove first invalid entry.
+
+2017-01-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (BLOCK): Remove typedef. BLOCK was used for 2 different
+ purposes: to contain a block allocation list header, and to hold
+ each individual allocated item. This was confusing, because the "size"
+ field was set only in the header, but not in each element.
+ (struct block_header): The block header contains a pointer to the first
+ element and the element size.
+ (struct block_item): Represent a single allocated item. This contains
+ only a pointer to the next element. This reduces the minimum allocated
+ item size from 2 pointers to 1 (16 bytes to 8 bytes on x86_64).
+ (nextfree): Change array item type from BLOCK to struct block_header.
+ (getblock, freeblock): Change cast from 'BLOCK' to 'struct block_item'.
+ * node.c (nextfree): Now an array of 'struct block_header' instead of
+ BLOCK. Switch the ordering to put the next pointer before the size.
+ (more_blocks): Replace 'BLOCK' with 'struct block_item', and add
+ an assert to ensure that the allocation size is at least as large
+ as 'struct block_item', i.e. 1 pointer.
+
+2017-01-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (numtype_choose): New backend macro used to implement
+ various macros whose calculations depend on how a number is
+ actually represented. This improves readability and should give
+ a small performance improvement when not using extended precision.
+ (get_number_ui, get_number_si, get_number_d, get_number_uj, iszero):
+ Rewrite using new numtype_choose macro.
+
+2017-01-04 Arnold Robbins <arnold@skeeve.com>
+
+ Trade space for time for programs that toggle IGNORECASE a lot.
+ Brings 25% to 39% speedup. NODE does not actually grow in size.
+
+ * awk.h (NODE::preg): Now an array of size two.
+ [CASE]: Flag no longer needed, so removed.
+ (IGNORECASE): Change type from int to bool.
+ * awkgram.y (make_regnode): Build two copies of the compiled regexp,
+ one without ignorecase, and one with.
+ * io.c (RS_re): Array replacing RS_re_yes_case and RS_re_no_case.
+ (set_RS): Use RS_re[IGNORECASE] as appropriate. Free and recompute
+ as needed.
+ * main.c (IGNORECASE): Change type from int to bool.
+ * re.c (re_update): Simplify the code. No need to check CASE flag
+ any longer. Recompute only if text of regexp changed.
+ * symbol.c (free_bc_internal): Adjust to free both elements of
+ m_re_reg.
+
+2017-01-18 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * interpret.h (r_interpret): Increase robustness of the optimization
+ logic in Op_assign_concat -- check that the node has MALLOC set,
+ and make sure to wipe all flags other than MALLOC, STRING, STRCUR,
+ and possibly WSTRCUR. Use STFMT_UNUSED define.
+
2017-01-15 Andrew J. Schorr <aschorr@telemetry-investments.com>
* interpret.h (r_interpret): Fix bug in Op_assign_concat reported
@@ -30,6 +649,311 @@
not updating the node correctly by setting STRING and STRCUR flags
and setting stfmt.
+2017-01-04 Arnold Robbins <arnold@skeeve.com>
+
+ * config.guess, config.sub, compile, depcomp: Sync from latest
+ in GNULIB.
+
+2016-12-27 Juergen Kahrs <Juergen.Kahrs@googlemail.com>
+
+ * CMakeLists.txt: Updated after adding support library.
+
+2016-12-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac (GNUPG_CHECK_MPFR): Don't call on PowerPC
+ Macintosh. C99 and the last version of MPFR that works on
+ that platform don't get along. Sigh.
+
+2016-12-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+ * intprops.h: New file.
+ * Makefile.am (base_sources): Add intprops.h.
+
+ Unrelated. Import GNULIB fix for regex: fix integer-overflow
+ bug in never-used code.
+ Problem reported by Clément Pit–Claudel in:
+ http://lists.gnu.org/archive/html/emacs-devel/2016-12/msg00654.html
+ Fix by Paul Eggert <eggert@cs.ucla.edu>:
+
+ * regex_internal.h: Include intprops.h.
+ * regexec.c (re_search_2_stub): Use it to avoid undefined
+ behavior on integer overflow.
+
+ Unrelated. Set up a support directory for externally obtained
+ support files.
+
+ * Makefile.am (base_sources, EXTRA_DIST): Edit lists.
+ (SUBDIRS): Get ordering right.
+ (LDADD): Add support/libsupport.a.
+ (DEFS): Add -I for support directory.
+ * dfa.c, dfa.h, getopt.c, getopt.h, getopt1.c, getopt_int.h,
+ intprops.h, localeinfo.c, localeinfo.h, random.c, random.h,
+ regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h,
+ regexec.c, verify.h, xalloc.h: Moved to support.
+
+ Unrelated: Totally break binary compatibility in the API
+ after merging in API min/max changes and REGEX and STRNUM
+ support in the API:
+
+ * gawkapi.c (valtype2str): New function.
+ (node_to_awk_value): Minor simplification in a switch.
+ (api_flatten_array): Removed.
+ (api_flatten_array_typed): Use valtype2str in error message.
+ (api_impl): Reorder functions to group related ones together again.
+ * gawkapi.h (awk_valtype_t): Reorder enum values.
+ (struct gawk_api): Remove api_flatten_array field. Reorder
+ functions to group related ones together again.
+
+2016-12-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawkapi.h (api_add_ext_func): Add comment about point to
+ awk_ext_func_t not being const but gawk doesn't use it.
+ * * interpret.h (Op_ext_builtin): Simplify code, check only
+ if do_lint and ! f->suppress_lint and num_args > max_expected.
+
+2016-12-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawkapi.h (awk_ext_func_t): Put max back before min. Restores
+ source compatibility, although there will be compile warnings
+ because of the 3rd argument for the C function being missing.
+ * interpret.h (Op_ext_builtin): Used size_t instead of int for
+ the various variables. Add a check that max expected > 0.
+
+2016-12-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ MAJOR BREAKING API CHANGE.
+
+ * awk.h (INSTRUCTION): Update extension function pointer to
+ take 3rd argument of pointer to struct awk_ext_func.
+ * gawkapi.c (api_add_ext_func): Update third arg to not be const.
+ * gawkapi.h (awk_ext_func_t): Put min before max. Add suppress_lint
+ and data pointer.
+ [gawk_api_major_version]: Update to 2.
+ [gawk_api_minor_version]: Reset to 0.
+ (api_add_ext_func): Update third arg to not be const.
+ * interpret.h (Op_ext_symbol): Revise lint check.
+
+2016-12-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (INSTRUCTION): Replace min_required and max_expected
+ with a pointer to the extension functions awk_ext_func_t struct.
+ * ext.c (make_builtin): Store a pointer to the extension function
+ struct into the INSTRUCTION instead of the min and max.
+ * gawkapi.h (awk_ext_func): Use size_t instead of unsigned short.
+ Put min second, which preserves source code compatibility.
+ * interpret.h (Op_ext_builtin): Use the pointer for the info
+ directly. If lint and max_expected > 0 and args > max_expected
+ print a message and set max_expected to zero so we only print once
+ per function. Remove special case of both min and max being zero.
+ (Op_ext_func): Adjust creation of the data structures.
+
+2016-12-11 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+
+2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Add API support for strnum values.
+ * gawkapi.c (awk_value_to_node): Add AWK_STRNUM.
+ (assign_string): Add a type argument so we can use this for AWK_STRING
+ or AWK_STRNUM.
+ (node_to_awk_value): When AWK_NUMBER is requested, a regex value
+ should return false, as per the header file documentation.
+ Add support for AWK_STRNUM requests. When AWK_REGEX is requested,
+ implement the cases properly instead of always returning true.
+ Fix AWK_SCALAR logic. For AWK_UNDEFINED, rewrite using a switch
+ and support AWK_STRNUM.
+ (api_sym_update): Add AWK_STRNUM.
+ (api_sym_update_scalar): Add optimized support for updating AWK_STRNUM.
+ (valid_subscript_type): Add AWK_STRNUM.
+ (api_create_value): Add AWK_STRNUM.
+ * gawkapi.h (awk_valtype_t): Add AWK_STRNUM.
+ (strnum_value): New macro.
+ (Value fetching table): Updated.
+
+2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.c (assign_regex): Do not call assign_string, since we
+ know that a REGEX value is not an unterminated field string.
+ * gawkapi.h (make_regex): Delete macro.
+ (make_const_regex, make_malloced_regex): Add new macros to replace
+ make_regex with necessary memory management support.
+
+2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (fixtype): Remove conditional checking if the node type
+ is Node_val. This is already covered by the assert, and if it's not
+ true, we have serious bugs.
+ * builtin.c (do_typeof): Do not treat Node_var the same way as
+ Node_val, since they are different beasts. In reality, the argument
+ to this function will never have type Node_var.
+
+2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_element_t): Remove obsolete comment claiming that
+ the index will always be a string.
+ (gawk_api_t): Add new api_flatten_array_typed function and indicate
+ that api_flatten_array has been superseded.
+ (flatten_array_typed): New macro to call api_flatten_array_typed.
+ (flatten_array): Redefine using the new flatten_array_typed macro.
+ * gawkapi.c (api_flatten_array_typed): New function renamed from
+ api_flatten_array to flatten an array with the types requested by the
+ caller. Also update the comments and error messages.
+ (api_flatten_array): Now a wrapper around api_flatten_array_typed.
+ (api_impl): Add new api_flatten_array_typed hook.
+
+2016-12-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ Add minimum required and maximum expected number of arguments
+ to the API.
+
+ * awk.h (INSTRUCTION): Add new members min_required and max_expected.
+ * ext.c (make_builtin): Store values from extension function struct
+ into the INSTRUCTION.
+ * gawkapi.h (awk_ext_func): Add min_required args. Make both it and
+ max_expected_args into unsigned short to match type in INSTRUCTION.
+ * interpret.h (Op_ext_builtin): Store min_required and max_expected
+ in instructions. Add checking code and lint checks.
+ (Op_ext_func): Copy min_required and max_expected from function info.
+
+
+2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (r_make_string_type): New inline function to create strings
+ of any type, currently AWK_STRING or AWK_REGEX.
+ (r_make_string): Now a wrapper around r_make_string_type.
+ (make_regex): Convert from an inline function to a macro that
+ calls r_make_string_type.
+
+2016-11-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with fixes in GNULIB.
+
+ Unrelated:
+
+ * gawkapi.h (make_regex): New function.
+
+2016-11-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ Add support for typed regex variables to the API.
+
+ * awk.h (make_typed_regex): Declare function.
+ * awkgram.y (typed_regexp): Call make_typed_regex instead of
+ using inline code.
+ * gawkapi.h (AWK_REGEX): New value type.
+ (regex_value): New macro.
+ (Value fetching table): Updated.
+ * gawkapi.c (awk_value_to_node, node_to_awk_value, api_sym_update,
+ api_sym_update_scalar, valid_subscript_type, api_create_value):
+ Add support for AWK_REGEX.
+ (assign_regex): New function.
+ (api_flatten_array): Adjust comment.
+ * node.c (make_typed_regex): New function; moved code from grammar.
+
+2016-11-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ Remove redundant flag from dfa:
+
+ * dfa.c (dfasyntax): Use RE_ICASE instead of DFA_CASE_FOLD.
+ * dfa.h (DFA_CASE_FOLD): Removed.
+ * re.c (make_regexp): Use RE_ICASE for regex and dfa. Yay!
+
+ Unrelated: Don't have to recompute syntax stuff every time
+ we compile a regexp.
+
+ * dfa.c (dfacopysyntax): New function.
+ (dfaalloc): Zero out the newly allocated memory.
+ * dfa.h (dfacopysyntax): Declare it.
+ * re.c (make_regexp): Declare two static dfaregs, one for
+ with and without ignorecase. Compute the syntax once for each,
+ then use dfacopysyntax to copy the settings when compiling
+ a regexp.
+
+2016-11-28 Arnold D. Robbins <arnold@skeeve.com>
+
+ Make gawk compile on HP-UX 11.33.
+
+ * debug.c (serialize_list): Renamed from `serialize'.
+ (unserialize_list): Renamed from `unserialize', for consistency.
+
+ Unrelated:
+
+ * dfa.c: Sync with GNULIB. Twice in one day.
+
+2016-11-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+
+2016-11-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ General cleanup for zero termination of strings.
+
+ * array.c (do_delete): Use %.*s.
+ (value_info): Get length and use %.*s.
+ (asort_actual): Save and restore character after end.
+ * awkgram.y (split_comment): Use make_string, not make_str_node.
+ * builtin.c (do_fflush): Use %.*s.
+ (locale_category_from_argument, do_dcgettext, do_dcngettext,
+ do_bindtextdomain): Save and restore character after end.
+ * debug.c (do_info, print_array, print_subscript, do_print_var,
+ do_set_var, display, do_watch, print_watch_item, serialize_subscript,
+ do_print_f): Use %.*s.
+ * eval.c (cmp_nodes, fmt_index): Save and restore character after end.
+ * interpret.h (r_interpret): Fix compuation for concatenation of
+ wide strings.
+ * io.c (is_non_fatal_redirect): Add length parameter; save and
+ restore character after last. Adjust all other declarations and calls.
+ (do_close): Save and restore character after end.
+ * mpfr.c (ieee_fmts): Adjust table indentation.
+ (do_mpfr_strtonum): Clear wide string members of the union.
+ * msg.c (err): Use %.*s.
+
+2016-11-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h [USER_INPUT]: Renamed from MAYBE_NUM.
+ * builtin.c, eval.c, field.c, int_array.c, io.c, main.c,
+ mpfr.c, node.c: Change all uses.
+
+2016-11-15 Arnold D. Robbins <arnold@skeeve.com>
+
+ Finish reworking typed regexes.
+
+ * awk.h (typed_re): Replaces tre_reg.
+ * awkgram.y (typed_regexp production): Node_val points to a regular
+ Node_regex and also has string value and length.
+ (make_regnode): Simplified back to its original form.
+ * builtin.c (call_sub, call_match, call_split_func): For REGEX,
+ get n->typed_re.
+ * field.c (do_split, do_patsplit): Ditto, for separator regexp.
+ * profile.c (pprint): Op_match_rec, handle REGEX correctly.
+ * re.c (re_update): If REGEX, get t->typed_re->re_reg.
+
+2016-11-15 Arnold D. Robbins <arnold@skeeve.com>
+
+ Start reworking typed regexes.
+
+ * awk.h (Node_typedregex): Nuked.
+ [REGEX]: New flag.
+ (tre_reg): New member in val part of NODE union.
+ (force_string, force_number, fixtype): Remove use of Node_typedregex.
+ * awkgram.y (grammer): Use REGEX flag instead of node type.
+ (valinfo); Ditto.
+ (make_regnode): Adjust creation based on node type.
+ * builtin.c (do_length, do_print, call_sub, call_match,
+ call_split_func, do_typeof): Adjust code.
+ * debug.c (watchpoint_triggered, initialize_watch_item,
+ print_memory): Adjust code.
+ * eval.c (nodetypes): Remove Node_typedregex.
+ (flags2str): Add REGEX.
+ (setup_frame): Adjust code after removal of Node_typedregex.
+ * interpret.h (r_interpret): Adjust code after removal
+ of Node_typedregex.
+ * profile.c (pp_typed_regex): Renamed from pp_strong_regex.
+ (pp_string_or_strong_regex): Renamed from pp_string_or_strong_regex.
+ (pprint): Adjust code after removal of Node_typedregex.
+ * re.c (re_update): Adjust code after removal of Node_typedregex.
+
2016-11-04 Eli Zaretskii <eliz@gnu.org>
* builtin.c (efwrite) [__MINGW32__]: Call w32_maybe_set_errno if
@@ -37,11 +961,17 @@
* nonposix.h (w32_maybe_set_errno) [__MINGW32__]: Add prototype.
+2016-11-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ * eval.c (flags2str): Add NO_EXT_SET and NUMCONSTSTR.
+
2016-10-31 Arnold D. Robbins <arnold@skeeve.com>
Fix valgrind issues.
* io.c (init_awkpath): Need to allocate max_path+3 pointers.
+ * awkgram.y (make_profile_number): Need to add STRCUR flag and
+ set n->stfmt to STFMT_UNUSED. See the comment in the code.
2016-10-26 Arnold D. Robbins <arnold@skeeve.com>
@@ -53,12 +983,77 @@
null elements represent the current directory. Sheesh.
Bug reported by "Jun T." <takimoto-j@kba.biglobe.ne.jp>.
+ Disallow negative arguments to the bitwise functions.
+
+ * NEWS: Document this.
+ * builtin.c (do_lshift, do_rshift, do_and, do_or, do_xor, do_compl):
+ Make negative arguments a fatal error.
+ * mpfr.c (do_mpfr_compl, get_intval): Ditto.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+ * mpfr.c: Replace Unicode sequences with ASCII.
+ * cint_array.c: Ditto.
+
+2016-10-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y: Typo fix in call to add_sign_to_num.
+
+2016-10-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (enum opcodeval): Add Op_unary_plus.
+ * awkgram.y (add_sign_to_num): New routine to put in a sign on
+ profiling constants. Call it as necessary.
+ In unary plus production, use new opcode, or set up a
+ constant as for unary minus.
+ (negate_num): Call add_sign_to_num instead of doing it directly.
+ * eval.c (optypetab): Add entry for Op_unary_plus.
+ * interpret.h (r_interpret): Add case for Op_unary_plus.
+ * profile.c (pprint, prec_level, is_scalar): Ditto.
+
+2016-10-13 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+
+2016-10-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (make_profile_number): Allocate an extra byte for the
+ string, so there's room for a minus if necessary. Store '\0'
+ in the right place.
+ (negate_num): Use memmove to shift the string up and then
+ insert a minus, instead of doing a fresh alloc + copy + free.
+
+2016-10-11 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (NUMCONSTSTR): New flag value.
+ * awkgram.y (make_profile_number): New function. Use it
+ wherever we make a number. This calls make_number and then, if
+ pretty printing, save the original string value and sets NUMCONSTSTR.
+ (negate_num): If NUNCONSTSTR set, update the saved string value.
+ * profile.c (pp_number): Assert NUMCONSSTR set, use that value.
+ Remove previous code.
+
2016-09-24 Eli Zaretskii <eliz@gnu.org>
* debug.c (restart) [__MINGW32__]: Cast 2nd argument of execvp to
avoid compiler warnings about prototype mismatch. Reported by
Marc de Bourget <marcdebourget@gmail.com>.
+2016-09-09 Norihiro Tanaka <noritnk@kcn.ne.jp>
+
+ * awk.h (struct Regexp): Remove member has_anchor. All uses removed.
+ * re.c (make_regexp, research): Use dfa matcher for regex with anchor.
+
+2016-09-09 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with grep.
+
+2016-09-08 Paul Eggert <eggert@cs.ucla.edu>
+
+ * dfa.c, dfa.h: Sync with grep.
+ * re.c (make_regexp): Adjust to DFA API changes.
+
2016-09-08 Arnold D. Robbins <arnold@skeeve.com>
* command.y: Update license text to version 3. Oops.
@@ -69,6 +1064,65 @@
GPLv3+ and with correct FSF address. Thanks to
David Kaspar <dkaspar@redhat.com> for pointing out the need.
+2016-09-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with grep.
+
+2016-09-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ Merge grep's now thread-safe dfa. Wheee.
+
+ * dfa.h, dfa.c: Sync with grep.
+ * localeinfo.h, localeinfo.c, verify.h: New files.
+ * Makefile.am (base_sources): Adjust.
+ * awk.h (using_utf8): Declare new function.
+ * node.c (str2wstr): Use using_utf8 instead of now-gone dfa function.
+ * re.c: Include "localeinfo.h".
+ (localeinfo): New static variable.
+ (make_regexp): Adjust call to dfa_syntax.
+ (resetup): Call init_localeinfo on localeinfo. Remove call to
+ now-gone function dfa_init.
+ (using_utf8): New function.
+
+2016-08-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac (fwrite_unlocked): Check for it.
+ * awk.h (fwrite): Define to fwrite_unlocked if we have it.
+ * NEWS: Make note of speed improvement.
+
+2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ POSIX now says use strcmp for == and !=. Thanks to Chet Ramey
+ for pointing me at the change. Make it so:
+
+ * awk.h (cmp_nodes): New 3rd param indicating strcmp, not strcoll.
+ * debug.c (cmp_val): Update call to cmp_nodes.
+ * eval.c (cmp_nodes): New 3rd param indicating strcmp, not strcoll.
+ Adjust code and all callers.
+ (scalar_cmp_t): New enum type. Used in ...
+ (cmp_scalars): ... in order to call cmp_nodes correctly.
+ * interpret.h: Use the enum type in calls to cmp_scalars.
+ * re.c (re_update): Adjust call to cmp_nodes.
+
+2016-08-25 Norihiro Tanaka <noritnk@kcn.ne.jp>
+
+ * awk.h (struct Regexp): Remove dfa. Now dfareg instead of it. All
+ referers changed.
+ * re.c (research): Arrange caller of dfaexec and research.
+ * (avoid_dfa): Removed. All callers changed.
+ * awk.h (avoid_dfa): Removed.
+
+ Other changes by Arnold Robbins:
+
+ * awk.h (struct Regexp): Change various boolean members to bool.
+ (RE_NO_FLAGS): New #define.
+ * interpret.h: Use RE_NO_FLAGS instead of zero.
+ * re.c (research): Prettify the logic a little bit.
+
+2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with grep.
+
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.4: Release tar ball made.
@@ -91,6 +1145,12 @@
* dfa.c: Sync with grep.
+2016-08-15 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * int_array.c (is_integer): Fix merge of stable changes to remove
+ obsolete string formatting check that has been superseded by
+ the new standard_integer_string check.
+
2016-08-14 Arnold D. Robbins <arnold@skeeve.com>
* re.c (make_regexp): Only call dfasyntax if actually using
@@ -117,6 +1177,28 @@
force_number to parse the string, but this is disabled due to possible
negative performance impact.
+2016-08-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ Remove typed regexes until they can be done properly.
+
+ * NEWS: Updated.
+ * awk.h (enum nodevals): Remove Node_typedregex.
+ (force_string, force_number): Remove check for Node_typedregex.
+ * awkgram.y (TYPED_REGEXP): Remove token.
+ (grammar): Remove productions related to typed regexps.
+ (yylex): Don't find a typed regex or return it.
+ (valinfo): Remove code for Node_typedregex.
+ * builtin.c (do_length, do_print, call_sub, call_match,
+ call_split_func, do_typeof): Remove code for Node_typedregex.
+ * debug.c (watchpoint_triggered, print_memory): Remove code
+ for Node_typedregex.
+ * eval.c (nodetypes, setup_frame): Remove code for Node_typedregex.
+ * interpret.h (r_interpret): Remove code for Node_typedregex.
+ * profile.c (pprint): Remove code for Node_typedregex.
+ (pp_strong_regex): Removed.
+ (pp_string_or_strong_regex): Remove code for Node_typedregex.
+ * re.c (re_update): Remove code for Node_typedregex.
+
2016-08-01 Arnold D. Robbins <arnold@skeeve.com>
* README, NEWS: Mark DJGPP port as unsupported.
@@ -150,6 +1232,17 @@
should not be mapped to upper case. Fixes inconsistencies between
dfa and regex in some single bytes locales; notably el_GR.iso88597.
+2016-07-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ Make result of close on a pipe match result of system.
+ Thanks to Mike Brennan for the encouragement.
+
+ * awk.h (sanitize_exit_status): Declare routine.
+ * builtin.c (sanitize_exit_status): New routine.
+ (do_system): Use it.
+ * io.c (close_rp): Use it on pclose result.
+ (gawk_pclose): Use it.
+
2016-07-23 Andrew J. Schorr <aschorr@telemetry-investments.com>
* builtin.c (do_print): Improve logic for formatting
@@ -190,10 +1283,192 @@
* eval.c (set_LINT): Reset lintfunc to `warning' for LINT="invalid".
Thanks to Andy Schorr for the report.
+2016-07-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h: Restore previous comment about unterminated strings, since
+ I am removing the string termination patches from field.c
+ (free_api_string_copies): Declare new gawkapi function.
+ * builtin.c (do_mktime, do_system): Restore temporary string
+ termination to protect against unterminated field values.
+ (nondec2awknum): Remove comment about unnecessary termination.
+ * eval.c (posix_compare): Restore temporary string termination.
+ * field.c (databuf): Remove struct, no longer needed.
+ (set_field): Remove memcpy for string termination, since we will support
+ unterminated field string values.
+ (rebuild_record): Ditto. Also no need to allocate space for terminated
+ string copies.
+ (allocate_databuf): Remove function, since memory management can again
+ be done inside set_record.
+ (set_record): Restore inline buffer management logic.
+ (reset_record): Remove calls to allocate_databuf, since we no longer
+ need space for making terminated copies of field strings.
+ * gawkapi.c (free_api_string_copies): New function to free strings
+ that we made to provide terminated copies to API functions.
+ (assign_string): New function to convert a string to an awk_value,
+ making sure to copy it if we need to terminate it.
+ (node_to_awk_value): Use assign_string to return string values with
+ NUL termination protection.
+ * int_array.c (is_integer): Restore temporary string termination.
+ * interpret.h (Op_push_i): Ditto.
+ (Op_ext_builtin): After external function returns, call
+ free_api_string_copies to free temporary string copies.
+ * mpfr.c (force_mpnum): Restore temporary string termination.
+ * node.c (r_force_number, get_ieee_magic_val): Ditto.
+
2016-07-08 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c: Sync with GNU grep.
+ Unrelated:
+
+ * builtin.c (do_print): Coding style change. (This change obsoleted
+ by earlier changes in the fixtype branch.)
+
+2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h: Modify comments to indicate that MAYBE_NUM will now be
+ left enabled to indicate strnum values by the NUMBER|MAYBE_NUM
+ combination, whereas STRING|MAYBE_NUM indicates a potential strnum.
+ (fixtype): Modify MAYBE_NUM test to avoid calling force_number if
+ NUMCUR is already set.
+ * builtin.c (do_typeof): Call fixtype to resolve argument type.
+ This forces parsing of numeric strings, so there's a performance
+ penalty, but we must do this to give a correct result. The meaning
+ of "strnum" changes from "potential strnum" to "actual strnum".
+ * eval.c (set_TEXTDOMAIN): Remove some dead code left over from last
+ patch.
+ * int_array.c (is_integer): When a MAYBE_NUM is converted successfully
+ to a NUMBER, leave the MAYBE_NUM flag enabled.
+ * mpfr.c (mpg_force_number): Ditto.
+ * node.c (r_force_number): Ditto.
+
+2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h: Modify stptr comment to indicate that all strings are now
+ NUL-terminated.
+ * builtin.c (do_mktime): Remove unnecessary logic to terminate
+ the string with '\0' temporarily.
+ (do_system) Ditto.
+ (nondec2awknum): Add a comment about termination.
+ * eval.c (posix_compare): Remove logic to terminate strings temporarily.
+ (set_ORS): No need to terminate ORS, since the string node is already
+ terminated. What gave us the right to modify that node anyway?
+ (fmt_index): Remove code to terminate string. This seems to have been
+ invalid anyway, since we don't own that memory.
+ (set_TEXTDOMAIN): Do not terminate TEXTDOMAIN string, since the node
+ is already terminated. We didn't have the right to modify that node
+ anyway.
+ * gawkapi.c (node_to_awk_value): Add assert checks to confirm that the
+ string is NUL-terminated.
+ * gawkapi.h: Modify awk_string comment to indicate that strings are
+ always terminated with '\0'.
+ * int_array.c (isinteger): Remove unnecessary logic to terminate string
+ with '\0' temporarily.
+ * interpret.h (Op_push_i): Ditto.
+ * io.c (nextfile): Remove string termination. We didn't own that memory
+ anyway.
+ * mpfr.c (force_mpnum): Remove unnecessary logic to terminate the
+ string with '\0' temporarily.
+ * node.c (r_force_number): Remove NUL termination around strtod call,
+ since we already know that there is either a white space or '\0'
+ character there. Either one will stop strtod.
+ (get_ieee_magic_val): Ditto.
+ * profile.c (pp_number): No need to terminate string returned by
+ r_format_val.
+
+2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * interpret.h (Op_field_spec): Now that all $n field values are
+ NUL-terminated, there is no reason to call dupnode for $n where n > 0.
+ This saves malloc and copying overhead, thereby more than offsetting the
+ performance hit of the additional copying and NUL-termination in the
+ last patch to field.c. It also eliminates repeated parsing in cases
+ where $n, for n > 1, was accessed more than once in a numeric context,
+ so the new approach should be a performance win.
+
+2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Make sure that all field values, and therefore all strings inside gawk,
+ are terminated with a '\0' character!
+
+ * field.c (databuf): New static struct to hold info about our buffer to
+ contain the field string values.
+ (allocate_databuf): New function to make sure the databuf is large
+ enough to hold $0 and copies of $1 through $NF.
+ (set_field): Copy $n into free space previously allocated in databuf
+ and add a '\0' at the end.
+ (rebuild_record): Call allocate_databuf to ensure sufficient space
+ for copying non-malloced field values. When copying field values,
+ use databuf to create a NUL-terminated copy.
+ (purge_record): New function extracted from reset_record to initialize
+ $1 through $NF to null values.
+ (set_record): Buffer management moved to new allocate_databuf function.
+ Call purge_record instead of reset_record, since reset_record contains
+ some extra logic not needed in this case.
+ (reset_record): Call purge_record to do most of the work, and call
+ allocate_databuf to make sure we have a big enough buffer to contain
+ copies of the $1 through $NF.
+
+2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h: Renumber flags to remove gap created when FIELD was removed.
+
+2016-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (rebuild_record): Need to set MALLOC flag if we allocate
+ memory for a residual field node with valref > 1.
+
+2016-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (rebuild_record): Do not bother to create new field nodes
+ to replace malloc'ed nodes when rebuilding $0.
+
+2016-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (FIELD): Remove unnecessary flag.
+ (MALLOC): Move definition to join the others, and improve the comment.
+ * array.c (value_info): Replace FIELD test with MALLOC test.
+ * eval.c (flags2str): Remove FIELD flag.
+ * field.c (init_fields): Remove FIELD bit from Null_field->flags.
+ (set_field): Remove FIELD bit from flags.
+ (rebuild_record): Test against MALLOC instead of FIELD. If a field
+ node has valref > 1, we should make a copy, although I don't think
+ it is valid for this to happen.
+ (set_record): Remove FIELD bit from flags.
+ * interpret.h (UNFIELD): Add comment, and test MALLOC flag instead of
+ FIELD. Remove probably buggy code to disable the FIELD flag when
+ valref is 1; that would have created a node where neither the FIELD
+ nor MALLOC flag was set, which seems invalid.
+ * node.c (r_dupnode): Remove code disabling FIELD flag.
+
+2016-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (force_string_fmt): New inline function to get the string
+ representation in a requested format.
+ (force_string): Reimplement as a macro using force_string_fmt function.
+ (force_string_ofmt): New macro to get a value's OFMT representation.
+ * builtin.c (do_print): Use new force_string_ofmt macro instead of
+ duplicating the logic inline.
+
+2016-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * str_array.c (str_lookup): There is no need to worry about the
+ MAYBE_NUM flag, since the code has been patched to make sure to
+ preserve the string value of strnum values, and the integer array
+ code should no longer mistakenly claim a strnum integer with a
+ nonstandard string representation.
+
+2016-07-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (rebuild_record): Revert warning message regarding flags,
+ since I'm not yet totally confident that it is invalid to have FIELD
+ and MALLOC set at the same time.
+
+2016-07-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * field.c (rebuild_record): Do not turn off the STRING flag when
+ copying a FIELD node, and issue a warning if MALLOC is enabled.
+
2016-07-01 Arnold D. Robbins <arnold@skeeve.com>
* array.c (value_info): Print something reasonable when stfmt
@@ -214,6 +1489,86 @@
* awkgram.y (dump_vars): Allow "-" to mean print to stdout.
Thanks to Hermann Peifer for the reports.
+2016-06-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * node.c (r_force_number): Coding style change.
+
+2016-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (STFMT_UNUSED): New define indicating that the string
+ representation does not depend on CONVFMT or OFMT.
+ (force_string): Use STFMT_UNUSED to improve code clarity.
+ * array.c (value_info): Fix stfmt logic.
+ * builtin.c (do_print): Use STFMT_UNUSED to improve code clarity.
+ * field.c (set_record): Ditto.
+ * gawkapi.c (api_sym_update_scalar): Ditto.
+ * int_array.c (is_integer): Check stfmt equals STFMT_UNUSED before
+ bothering to inspect the string.
+ * mpfr.c (mpg_format_val): Use STFMT_UNUSED to improve code clarity.
+ Remove buggy cast to char in stfmt assignment.
+ * node.c (r_format_val): Ditto.
+ * str_array.c (str_lookup): Use STFMT_UNUSED to improve code clarity.
+ * symbol.c (check_param_names): Ditto.
+
+2016-06-29 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * node.c (r_force_number): Optimize by trimming leading and trailing
+ white space before we inspect the string contents.
+ (get_ieee_magic_val): Must terminate the string with '\0' before
+ calling strtod.
+
+2016-06-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_string): Add comment about the potential lack of
+ NUL-termination.
+
+2016-06-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h: Add a comment regarding the potential lack of NUL-termination
+ for Node_val strings.
+
+2016-06-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * node.c (r_format_val): Do not free stptr unless STRCUR is set.
+ This is safer than testing for non-NULL stptr, since, for example,
+ pp_number copies a node and calls r_format_val, but does not bother
+ to set stptr to NULL beforehand.
+
+2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * node.c (r_force_number): When checking for trailing spaces, protect
+ against running off the end of the string.
+ * mpfr.c (force_mpnum): Ditto.
+
+2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (do_print): There's actually no reason to test whether a
+ value is a number, since the STRCUR flag and stfmt value contain all
+ the necessary info, as in awk.h:force_string.
+
+2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (do_print): Do not use OFMT to print strnum values. We
+ accomplish this by calling format_val for a NUMBER only
+ if there is no string currently available, or if stfmt equals
+ neither -1 nor OFMTidx.
+
+2016-06-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h: Edit some comments. Add others. Minor coding style changes.
+ * builtin.c (format_tree): Restore a comment.
+ (do_mktime): Restore saving/restoring of byte after format string.
+ (do_sub): Coding style. Use %.*s in warning message.
+ (nondec2awknum): Restore saving/restoring of byte after string value
+ being converted.
+ * eval.c: Minor coding style edits.
+ * int_array.c (is_integer): Fix order of checks for not
+ updating string value: check length == 0 before testing values.
+ Coding style edits.
+ * mpfr.c (do_mpfr_strtonum): Coding style edits.
+ * node.c (r_force_number): Restore saving/restoring of byte after
+ string value being converted. Edit comments some.
+
2016-06-26 Arnold D. Robbins <arnold@skeeve.com>
Repair change of 2015-08-25 to handling of MAYBE_NUM.
@@ -224,6 +1579,22 @@
Thanks to Andrew Schorr for reporting the problem.
A test case will eventually be merged into master.
+ Only in stable and master.
+
+2016-06-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (do_strftime): Call fixtype before checking flags for
+ STRING type.
+ (do_print): Call fixtype before checking whether argument is a NUMBER.
+ * eval.c (set_BINMODE): Call fixtype before checking value type.
+ No need to call force_number if the flags say it's a number.
+ (r_get_field): Fix lint check for non-numeric argument.
+ * io.c (redirect): Call fixtype before checking whether it's a string.
+
+2016-06-18 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * node.c (r_force_number): Fix typo in comment.
+
2016-06-16 Arnold D. Robbins <arnold@skeeve.com>
* awk.h: Add comment headers for several functions.
@@ -234,10 +1605,110 @@
* config.sub: Update from GNULIB.
+2016-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (boolval): New inline function to standardize testing whether
+ a node's value is true.
+ * builtin.c (do_strftime): Use boolval to handle 3rd argument.
+ * eval.c (set_IGNORECASE, eval_condition): Use new boolval function.
+ * io.c (pty_vs_pipe): Use new boolval function.
+
+2016-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (do_strftime): Fix handling of 3rd argument to work
+ as a standard boolean: non-null or non-zero.
+
+2016-06-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.c (node_to_awk_value): When caller requests AWK_SCALAR
+ or AWK_UNDEFINED, we need to call fixtype before we check the type.
+
+2016-06-13 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkgram.y: Eliminate STRCUR tests. Must use STRING to test whether
+ a scalar is a string.
+
+2016-06-12 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h: Improve comment about STRING and NUMBER type assignment.
+ (nondec2awknum): Add endptr argument.
+ (fixtype): New inline function to clarify a scalar's type.
+ * array.c (sort_up_value_type): Call fixtype before checking the value
+ types.
+ * awkgram.y (yylex): Pass NULL endptr argument to nondec2awknum.
+ (valinfo): Remove dead tests: either STRING or NUMBER or both
+ must be set, so there's no reason to continue with checks for NUMCUR or
+ STRCUR.
+ * builtin.c (do_exp, do_int, do_log, do_sqrt, do_sin, do_cos, do_srand):
+ Fix lint check for non-numeric argument.
+ (do_string): Fix lint check for 1st and 2nd args being strings.
+ (do_length): Fix assert to allow for Node_typedregex.
+ Fix lint check for non-string argument.
+ (format_tree): Fix type detection for '%c' arguments.
+ (do_strftime): Fix lint check for non-numeric 2nd argument and
+ lint check for non-string 1st argument.
+ (do_mktime): Fix lint check for non-string argument. Eliminate useless
+ logic to save and restore terminating NUL.
+ (do_system, do_tolower, do_toupper): Fix lint check for non-string
+ argument.
+ (do_atan2, do_lshift, do_rshift, do_and, do_or, do_xor, do_compl,
+ do_intdiv): Fix lint checks for non-numeric args.
+ (do_sub): Attempt to clean up treatment of 3rd argument to gensub
+ despite vague documentation of expected behavior.
+ (do_strnum): Fix bug in number detection logic, and pass new endptr
+ arg to nondec2awknum.
+ (nondec2awknum): Add endptr argument so caller can detect how much
+ of the string was consumed. Eliminate unnecessary logic to save
+ and restore terminating NUL char.
+ (do_typeof): Use a switch to specify which cases are supported, and
+ issue a warning message when a corrupt type is detected.
+ * debug.c (print_memory): At least one of NUMBER and STRING should
+ be set, so no need to check for NUMCUR or STRCUR in addition.
+ * eval.c (cmp_nodes): Use fixtype function to fix arg types.
+ (set_IGNORECASE): Fix logic for acting on value type. Note that
+ setting IGNORECASE to a string value of "0" with NUMCUR set now enables
+ ignorecase, so that's a subtle change in behavior that seems to match
+ the docs.
+ (set_LINT): Try to clean up configuration logic based on type.
+ * ext.c (get_argument): Remove unused variable pcount.
+ * gawkapi.c (node_to_awk_value): Remove pointless test for NUMCUR
+ after calling force_number. Similarly, no need to test for STRCUR
+ after calling force_string.
+ * int_array.c (is_integer): Reject cases where a string value is
+ present that will not be correctly regenerated from the integer;
+ in particular, this could happen where blank space padding is present,
+ leading zeroes are present, or for hex or octal values.
+ Also fix some bugs where a strnum was converted to a NUMBER without
+ turning off the STRING bit.
+ * io.c (redirect_string): Make lint warning message more accurate.
+ (redirect): Change not_string test to use STRING bit, not STRCUR.
+ (pty_vs_pipe): Use fixtype to correct logic for detecting whether a
+ value is anumber.
+ * mpfr.c (mpg_force_number): If NUMCUR is set, there's no need to
+ test is_mpg_number. If it's not, the NODE is corrupt and we've got
+ bigger problems. Fix flag manipulation logic. Always set NUMCUR and
+ clear MAYBE_NUM,
+ (set_PREC): Fix logic using fixtype function.
+ (do_mpfr_atan2, do_mpfr_intdiv): Fix lint check for non-numeric
+ arguments.
+ (do_mpfr_func, do_mpfr_int, do_mpfr_compl, get_intval, do_mpfr_srand):
+ Fix lint check for non-numeric argument.
+ (do_mpfr_strtonum): Use fixtype and stop testing for NUMCUR bit.
+ * node.c (r_force_number): Eliminate pointless save and restore of
+ terminating NUL char. Always set NUMCUR and clear MAYBE_NUM, and
+ convert STRING to NUMBER if appropriate, fixing bugs in flag
+ manipulations. For non-decimal data, need to consider whether there
+ is trailing non-numeric data in deciding whether a MAYBE_NUM should
+ be converted to a NUMBER, so take advantage of new endptr arg
+ to nondec2awknum.
+
2016-06-14 Arnold D. Robbins <arnold@skeeve.com>
* builtin.c (do_sub): Fix sub for long runs of backslashes.
Thanks to Mike Brennan for the report.
+
+ Unrelated:
+ * ext.c (get_argument): Remove unused variable pcount.
2016-06-10 Arnold D. Robbins <arnold@skeeve.com>
@@ -274,6 +1745,16 @@
optional sign.
(r_force_number): Use it. Thanks to Mike Brennan for the report.
+2016-05-30 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (awk_ext_func_t): Rename num_expected_args to
+ max_expected_args, and explain in the comment that it doesn't really
+ matter.
+ * ext.c (make_builtin): Replace num_expected_args with
+ max_expected_args.
+ (get_argument): Do not check whether the argument number exceeds
+ the maximum expected by the function.
+
2016-05-30 Arnold D. Robbins <arnold@skeeve.com>
* main.c (arg_assign): Fully bracket ifdefs around call
@@ -322,6 +1803,13 @@
(api_set_argument): Pass (NODE *) returned by get_argument to
get_array_argument.
+2016-05-25 Manuel Collado <mcollado2011@gmail.com>.
+
+ * gawkapi.c (api_nonfatal): New function.
+ (api_impl): Include it.
+ * gawkapi.h (struct gawk_api): Add api_nonfatal member.
+ (nonfatal): New macro.
+
2016-05-12 Arnold Robbins <arnold@skeeve.com>
* str_array.c (str_lookup): Remove MAYBE_NUM from subscript flags.
@@ -334,12 +1822,20 @@
call to system.
* io.c (redirect, gawk_popen [PIPES_SIMULATED]): Same.
-
2016-05-12 Eli Zaretskii <eliz@gnu.org>
* nonposix.h: Add prototypes for Posix functions emulated in pc/*
files.
+2016-05-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * interpret.h (r_interpret): Op_ext_builtin. No need to test whether
+ op == Op_ext_builtin, since we wouldn't be here otherwise.
+
+2016-05-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * builtin.c (format_tree): Do not waste a byte at the end of a string.
+
2016-05-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
* builtin.c (format_tree): After the string has been rendered, use
@@ -415,6 +1911,15 @@
'system' differently under --traditional, as the low 8 bits are
the most interesting.
+2016-04-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_printf): Allow a write to the closed write-end of
+ a two-way pipe to be nonfatal if NONFATAL is set for it.
+ (do_print): Ditto.
+ (do_print_rec): Ditto.
+ * io.c (do_getline_redir): Same thing for reading from a closed
+ read end of a two-way pipe. Fatal error.
+
2016-04-04 Arnold D. Robbins <arnold@skeeve.com>
* builtin.c (do_fflush): Add warning for flush to two-way
@@ -432,12 +1937,54 @@
read end of a two-way pipe. Fatal error.
* NEWS: Updated.
+2016-03-27 Stephen Davies <sdavies@sdc.com.au>
+
+ * awkgram.y (get_comment): Strip CRs from comment. Strip
+ off trailing newlines.
+
+2016-03-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile.c (pprint): Improve handling of comment after
+ and if statement without an else.
+
+2016-03-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ Considerable improvements to handling of comments when pretty
+ printing, particularly for end-of-line comments.
+
+ * awkgram.y (prior_comment, comment_to_save): New variables.
+ (add_pending_comment): New function.
+ (grammar): Jump through lots more hoops to capture comments.
+ Due to shift-reduce parsing, there can be up to two comments
+ captured and waiting to be saved; be sure to get them both and
+ at the right times. This is difficult since comments have no
+ real syntactic exisitence. Call add_pending_comment on most of
+ the simple statements.
+ (get_comment): Save a pre-existing comment in prior_comment.
+ (split_comment): Use comment_to_save instead of `comment'.
+ * profile.c (end_line): Change to return the instruction after
+ the comment that gets printed; adjust return type.
+ (pprint): Add skip_comment static variable. Adjust logic for
+ skipping an end-of-line comment; only do it if skip_comment is
+ true. This is set to true in places where we can't use the
+ return value from end_line(). Call end_line() in many more places.
+ (pp_func): Handle end-of-line comments after a function header.
+
+2016-03-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ * debug.c (print_instruction): For Op_comment, improve notation as
+ to whether it's a full comment or an end of line comment.
+
2016-03-14 Arnold D. Robbins <arnold@skeeve.com>
* io.c (socketopen): For SOCK_DGRAM, set read_len to sizeof
remote_addr. Makes UDP more or less work again.
Thanks to Juergen Kahrs for the fix.
+2016-03-11 Arnold D. Robbins <arnold@skeeve.com>
+
+ * debug.c (print_instruction): Normalize printing of comment dump.
+
2016-03-10 Arnold D. Robbins <arnold@skeeve.com>
* builtin.c (do_system): Further improvements. Catch core dump
@@ -469,6 +2016,11 @@
* debug.c (print_instruction): Improvements in instruction dump
for if and else.
+2016-03-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ * debug.c (print_instruction): For Op_comment, add notation as
+ to whether it's a full comment or an end of line comment.
+
2016-02-29 Arnold D. Robbins <arnold@skeeve.com>
* profile.c (pp_list): Handle the case of nargs equal to zero.
@@ -492,6 +2044,15 @@
* configure.ac (AM_GNU_GETTEXT_VERSION): Bump to 0.19.7.
+2016-02-21 Nelson H.F. Beebe <beebe@math.utah.edu>
+
+ * random.c [SHUFFLE_BITS, SHUFFLE_MAX, SHUFFLE_MASK]: New macros.
+ (shuffle_init, shuffle_buffer): New static variables.
+ (random_old): Renamed from random.
+ (random): New function wrapping random_old and providing a
+ shuffle buffer to increase the period. See the literature citations
+ and other notes in the code.
+
2016-02-21 Arnold D. Robbins <arnold@skeeve.com>
* regexec.c (prune_impossible_nodes): Remove attribute that
@@ -517,6 +2078,43 @@
* README, NEWS: Updated to reflect use of Texinfo 6.1.
+ Unrelated:
+
+ * configure.ac: Switch to AC_PROG_CC_C99 to enable C99
+ compilation and features.
+ * dfa.c: Sync with GNU grep, go back to C99 style declarations
+ at point of use.
+
+2016-02-05 Arnold D. Robbins <arnold@skeeve.com>
+
+ Make optimization (constant folding and tail call recursion)
+ be on by default.
+
+ * awkgram.y (common_exp): Only do concatenation of two strings(!)
+ * main.c (do_optimize): Init to true.
+ (optab): Add new -s/--no-optimize option.
+ (usage): Update message to include it.
+ (parse_args): Parse it. Set do_optimize to false if pretty
+ printing or profiling.
+ * NEWS: Updated.
+
+2016-01-28 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (SUBDIRS): Include extras. Otherwise dist does
+ doesn't work.
+
+2016-01-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac (GAWK_AC_AIX_TWEAK): Remove call.
+ * configure: Regenerated.
+ * io.c (GAWK_AIX): Check _AIX instead.
+ * custom.h (_AIX): Add define of _XOPEN_SOURCE_EXTENDED.
+
+ Unrelated:
+
+ * configure.ac: Remove old stuff for ISC Unix, no longer needed.
+ * configure: Regenerated.
+
2016-01-25 John E. Malmberg <wb8tyw@qsl.net>
* io.c (redirect): Need to call close_one more than once after
@@ -578,6 +2176,12 @@
* ChangeLog: Cleanup spurious extra whitespace.
+2016-01-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac (GAWK_AC_LINUX_ALPHA): Remove call.
+ * configure: Regenerated.
+ * NEWS: Document removal of support for GNU/Linux on Alpha.
+
2016-01-02 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c (add_utf8_anychar): Minor change in declaration of
@@ -590,6 +2194,11 @@
empty else part for pretty printing. Bug report by
ziyunfei <446240525@qq.com>.
+2015-12-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * io.c (nonfatal): New static constant string.
+ * is_non_fatal, is_non_fatal_redirect: Use it.
+
2015-12-16 Arnold D. Robbins <arnold@skeeve.com>
* io.c (two_way_open): Remove unneeded close of slave in the
@@ -627,6 +2236,12 @@
* dfa.c: Sync with GNU grep.
+2015-10-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (yylex): Fix invalid write problems.
+ Reported by Hanno Boeck <hanno@hboeck.de>.
+ Only appeared in master. Harumph.
+
2015-10-16 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (SUBDIRS): Fix ordering so that
@@ -753,6 +2368,98 @@
* dfa.h, dfa.c: Sync with GNU grep.
+2015-06-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (yylex): If gawk extension function is found as
+ a function in a user-defined function body, treat it normally.
+ Makes eval "print and(a, 1)" work in the debugger again.
+ Thanks, yet again, to Hermann Peifer.
+ * interpret.h (r_interpret): Op_subscript. UPREF if the
+ element value is a typed regexp. Thanks to Hermann Peifer.
+
+2015-06-28 Arnold D. Robbins <arnold@skeeve.com>
+
+ Improve memory tracking of typed regexps.
+
+ * awkgram.y (make_regnode): Set valref to 1.
+ * interpret.h (r_interpret): Have Op_push_re upref typed regexp.
+ * builtin.c (do_typeof): OK to deref typed regex.
+ * awk.h (force_string): Do dupnode on the regexp text.
+
+2015-06-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ Remove support for old-style extensions.
+
+ * awk.h (Node_old_ext_func, Op_old_ext_func): Removed.
+ Remove all uses throughout the code.
+ (load_old_ext, make_old_builtin): Remove declarations.
+ * ext.c (load_old_ext, make_old_builtin): Removed.
+ * awkgram.y (tokentab): Remove "extension" entry.
+ * eval.c (Node_old_ext_funci, Op_old_ext_func): Remove from tables.
+ * interpret.h (interpret): Remove stuff for old extensions.
+
+ Unrelated:
+
+ * builtin.c (do_typeof): Add support for strnum, distinguish
+ untyped from unassigned, use "string" and "number". Thanks to
+ Hermann Peifer for suggesting inclusion of strnum.
+
+2015-06-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ Further work straightening out memory management for typeof.
+
+ * awk.h (DEREF): Add an assert.
+ * builtin.c (do_typeof): Add comments, cases where not to deref.
+ * debug.c (print_instruction): Add Op_push_arg_untyped.
+ * interpret.h (r_interpret): Additional comments / tweaks for
+ Op_push_arg_untyped.
+
+ Unrelated. Make `x = @/foo/ ; print x' print something.
+
+ * builtin.c (do_print): Check for Node_typedregex and handle it.
+ Needed for adding test code.
+
+ Unrelated. Typo fix.
+
+ * debug.c (initialize_watch_item): Dupnode the right thing.
+
+2015-06-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (snode): Make isarray not scalarize untyped parameters
+ also.
+ * profile.c (pprint): Add Op_push_arg_untyped.
+
+ Improve debugger support for typed regexps.
+ Thanks to Hermann Peifer for the bug report.
+
+ * awkgram.y (valinfo): Add support for Node_typedregex.
+ * debug.c (watchpoint_triggerred): Handle Node_typedregex.
+ (initialize_watch_item): Ditto.
+ (print_memory): Ditto.
+
+ Fix typeof to work on subarrays. Thanks, yet again, to
+ Hermann Peifer for the bug report.
+
+ * builtin.c (do_typeof): Don't deref Node_var_array.
+
+2015-06-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ Fixes for typeof - Don't let typeof change an untyped variable
+ into a scalar.
+
+ * awk.h (opcodeval): Add Op_push_arg_untyped.
+ * awkgram.y (snode): Separate out case for do_typeof, use
+ Op_push_arg_untyped.
+ * builtin.c (do_typeof): Arg will be equal to Nnull_string
+ if it's untyped.
+ * eval.c (optypes): Add Op_push_arg_untyped.
+ * interpret.h (r_interpret): Add Op_push_arg_untyped handling.
+
+2015-06-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_isarray): Minor edit to lint warning.
+ * TODO: Updated.
+
2015-06-14 Arnold D. Robbins <arnold@skeeve.com>
* regcomp.c, regex_internal.h, regexec.c: Sync with GLIBC.
@@ -766,6 +2473,16 @@
* regex_internal.h: Clean up defines for non-GCC for attribute;
essentially sync it with GLIBC.
+2015-06-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y: Finish converting "hard" regex to "typed" regex.
+
+2015-05-31 Arnold D. Robbins <arnold@skeeve.com>
+
+ * field.c (posix_def_parse_field): Removed. It's no longer
+ needed after updates to the POSIX standard. Thanks to
+ Michael Klement <michael.klement@usa.net> for pointing this out.
+
2015-05-26 Paul Eggert <eggert@Penguin.CS.UCLA.EDU>
* floatcomp.c (count_trailing_zeros): New function.
@@ -790,6 +2507,17 @@
* symbol.c (load_symbols): Plug minor memory leak by calling unref(tmp)
on "identifiers" string after assoc_lookup is done with it.
+2015-05-15 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * main.c (load_procinfo_argv): New function to save argv array values
+ in PROCINFO["argv"][0..argc-1].
+ (load_procinfo): Call load_procinfo_argv.
+
+2015-05-11 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h, awkgram.y, builtin.c, eval.c profile.c, re.c:
+ Change Node_hardregex to Node_typedregex everywhere.
+
2015-05-05 Arnold D. Robbins <arnold@skeeve.com>
* awkgram.y (yylex): Yet Another Fix for parsing bracket
@@ -800,6 +2528,14 @@
* config.guess, config.sub: Get latest versions.
+ Make profiling for hard regexes work.
+
+ * profile.c (pp_string_or_hard_regex): Renamed from pp_string.
+ Add bool param for hard regex and add @ if so.
+ (pp_string): New function, calls pp_string_or_hard_regex.
+ (pp_hard_regex): New function, calls pp_string_or_hard_regex.
+ (pprint): Adjust to print a hard regex correctly.
+
2015-05-01 Arnold D. Robbins <arnold@skeeve.com>
* awkgram.y: Make sure values are not null in param list.
@@ -824,6 +2560,11 @@
2015-04-28 Arnold D. Robbins <arnold@skeeve.com>
+ * builtin.c (isarray): Add lint warning that isarray()
+ is deprecated.
+
+2015-04-28 Arnold D. Robbins <arnold@skeeve.com>
+
* awkgram.y (yylex): Rework the bracket handling from zero.
Thanks to Michal Jaegermann for yet another test case.
@@ -856,6 +2597,21 @@
2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+ Let parameter names shadow the names of gawk additional built-ins.
+ Make it actually work.
+
+ * awkgram.y (want_param_names): Now an enum, there are three states.
+ (grammar): Set states properly.
+ (yylex): Improve checking logic.
+
+2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac: Updated by autoupdate.
+ * configure, aclocal.m4: Regenerated.
+ * io.c, main.c, profile.c: Removed use of RETSIGTYPE.
+
+2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
* builtin.c (do_strftime): Use a double for the timestamp and
check that the value is within range for a time_t.
@@ -869,6 +2625,14 @@
* NEWS: Updated.
+2015-04-15 Arnold D. Robbins <arnold@skeeve.com>
+
+ Let parameter names shadow the names of gawk additional built-ins.
+
+ * awkgram.y (want_param_names): New variable.
+ (yylex): Check it before returning a built-in token.
+ (grammar): Set and clear it in the right places.
+
2015-04-14 Arnold D. Robbins <arnold@skeeve.com>
* builtin.c (do_strftime): Restore checking for negative result and
@@ -882,6 +2646,23 @@
Unrelated:
* builtin.c (call_sub): Fix for indirect gensub, 3 args now works.
+ Unrelated:
+
+ * builtin.c (do_sub): Improve some variable names for readability
+ and add / expand some comments.
+
+ Unrelated:
+
+ * builtin.c (call_sub, call_match, call_split_func): Allow for
+ regex to be Node_hardregex.
+
+2015-04-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+ Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_sub): Make computations smarter; initial len
+ to malloc, test for final amount after all matches done and
+ need to copy in the final part of the original string.
+
2015-04-13 Arnold D. Robbins <arnold@skeeve.com>
* regcomp.c (analyze): Prevent malloc(0).
@@ -903,6 +2684,15 @@
* Makefile.am (efence): Make this link again.
Thanks to Michal Jaegermann for pointing out the problem.
+2015-04-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkgram.y (yyerror): Rationalize buffer size computations. Remove
+ old valgrind workarounds.
+ * debug.c (gprintf): Rationalize buffer size computations.
+ (serialize_subscript): Ditto.
+ * io.c (iop_finish): Rationalize buffer size computations.
+ * profile.c (pp_string): Correct space allocation computation.
+
2015-04-08 John E. Malmberg <wb8tyw@qsl.net>
* custom.h: VMS shares some code paths with ZOS_USS in
@@ -944,6 +2734,27 @@
Thanks to Andrew Schorr for finding the problem and supplying
initial code; I did it slightly differently.
+2015-04-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (force_string): If hard_regex, return string text of the regex.
+ (force_string, force_number): If hard_regex, return Nnull_string.
+ * awkgram.y: Fix ~ and !~ with @/.../.
+ * eval.c (setup_frame): Handle a hard regex.
+ * re.c (avoid_dfa): Ditto.
+
+2015-04-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * NEWS: Rename div to intdiv.
+
+2015-04-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ Rename div() to intdiv().
+
+ * builtin.c (do_intdiv): Renamed from do_div.
+ * mfpr.c (do_mpfr_intdiv): Renamed from do_mpfr_div.
+ * awk.h: Update declarations.
+ * awkgram.y (tokentab, snode): Revise accordingly.
+
2015-03-31 Arnold D. Robbins <arnold@skeeve.com>
* awk.h (call_sub): Renamed from call_sub_func.
@@ -960,6 +2771,12 @@
the buitin function expects.
* eval.c (r_get_field): Make extern.
+2015-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * io.c (redirect): Change not_string from int to bool.
+ * gawkapi.c (api_get_file): Minor stylistic improvements.
+ * NEWS: Updated for retryable I/O and new API function.
+
2015-03-24 Arnold D. Robbins <arnold@skeeve.com>
* awkgram.y (make_regnode): Make extern.
@@ -974,6 +2791,10 @@
* interpret.h (r_interpret): When Op_K_exit has an argument of
Nnull_string, do not update exit_val, since no value was supplied.
+2015-03-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h, gawkapi.c, io.c: Minor code reformatting.
+
2015-03-20 Arnold D. Robbins <arnold@skeeve.com>
Start on fixing indirect calls of builtins.
@@ -985,6 +2806,24 @@
* interpret.h (r_interpret): If calling do_sub, do it through
call_sub_func().
+2015-03-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * re.c (re_update): Handle hard regex - for sub/gsub/gensub.
+ * awkgram.y (grammar): Add support for hard_regex with ~ and !~;
+ allowed only on the right hand side.
+ (mk_rexp): Handle a hard regex.
+
+2015-03-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_typeof): Be smarter about checking for uninitialized
+ values; can now detect and return "untyped" for such values.
+ * awkgram.y (yylex): Collect @/.../ entirely in the lexer and return
+ a new terminal (HARD_REGEX).
+ (regexp): Reverted to just a regular awk regexp constant.
+ (hard_regexp): New nonterminal, can be used only in direct
+ assignment and as an argument in function call. New set of nonterminals
+ for function call expression lists. More work still to do.
+
2015-03-18 Arnold D. Robbins <arnold@skeeve.com>
* config.guess, config.sub: Updated, from libtool 2.4.6.
@@ -999,6 +2838,26 @@
* re.c (regexflags2str): Removed. It was redundant.
+ * io.c (devopen): Change the logic such that if nonfatal is true
+ for the socket, don't do retries. Also clean up the formatting
+ some. At strictopen, check if errno is ENOENT and if so, propagate
+ the error from getaddrinfo() up to the caller. Add explanatory
+ comments.
+
+2015-02-28 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (pty_vs_pipe): Remove check for NULL PROCINFO_node, since
+ this is now checked inside in_PROCINFO.
+
+2015-02-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (socketopen): New parameter hard_error; set it if
+ getaddrinfo() fails. Change fatals to warnings.
+ (devopen): Pass in address of boolean hard_error variable
+ and stop trying to open the file if hard_error is true.
+ Save and restore errno around call to socketopen() and
+ use restored errno if open() fails at strictopen.
+
2015-02-27 Arnold D. Robbins <arnold@skeeve.com>
* symbol.c (check_param_names): Fix argument order in memset() call.
@@ -1006,6 +2865,20 @@
a long-standing problem where `-lm' was used twice in the final
compilation line.
+2015-02-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ Start on making regexp a real type.
+
+ * awk.h (Node_hardregex): New node type.
+ (do_typeof): Add declaration.
+ * awkgram.y: Make @/.../ a hard regex.
+ (tokentab): New entry for typeof() function.
+ (snode): Try to handle typeof().
+ (make_regnode): Handle Node_hardregex.
+ * builtin.c (do_typeof): New function.
+ * eval.c (nodetypes): Add Node_hardregex.
+ * re.c (re_update): Check for hardregex too in assert.
+
2015-02-24 Arnold D. Robbins <arnold@skeeve.com>
* POSIX.STD: Update copyright year.
@@ -1029,6 +2902,34 @@
* gawkapi.h: Fix spelling error in comment.
+2015-02-10 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile.c (pprint): Restore printing of count for rules.
+ Bug report by Hermann Peifer.
+
+2015-02-08 Arnold D. Robbins <arnold@skeeve.com>
+
+ * io.c: Make it "NONFATAL" everywhere.
+
+2015-02-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (RED_NON_FATAL): Removed.
+ (redirect): Add new failure_fatal parameter.
+ (is_non_fatal_redirect): Add declaration.
+ * builtin.c (efwrite): Rework check for non-fatal.
+ (do_printf): Adjust calls to redirect.
+ (do_print_rec): Ditto. Move check for redirection error up.
+ * io.c (redflags2str): Remove RED_NON_FATAL.
+ (redirect): Add new failure_fatal parameter. Simplify the code.
+ (is_non_fatal_redirect): New function.
+ (do_getline_redir): Adjust calls to redirect.
+
+2014-12-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (is_non_fatal_std): Declare new function.
+ * io.c (is_non_fatal_std): New function.
+ * builtin.c (efwrite): Call it.
+
2015-02-07 Arnold D. Robbins <arnold@skeeve.com>
* regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h,
@@ -1091,6 +2992,11 @@
* command.c: Ditto.
* NEWS: Note same.
+2015-01-16 Stephen Davies <sdavies@sdc.com.au>
+
+ * awkgram.y (rule): Set first_rule to false. Catches more cases
+ for gathering comments. Thanks to Hermann Peifer for the test case.
+
2015-01-15 Arnold D. Robbins <arnold@skeeve.com>
* dfa.h, dfa.c: Sync with grep. Mainly copyright updates.
@@ -1108,6 +3014,22 @@
* builtin.c (do_length): Update comment.
* main.c (init_vars): Just call load_procinfo() and `load_environ()'.
+2015-01-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Revert changes to API deferred variable creation -- these variables
+ should be created when lookup is called, not when update is called.
+ * awk.h (variable_create): Remove function declaration.
+ * awkgram.y (variable_create): Remove function.
+ (variable): Restore variable_create functionality inline.
+ * gawkapi.c (api_sym_update): Revert to using install_symbol, since the
+ deferred variable check should be done when lookup is called, not here.
+
+2015-01-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.c (api_set_array_element): Remove stray call to
+ make_aname. I cannot see what purpose this served. Maybe I am
+ missing something.
+
2015-01-07 Arnold D. Robbins <arnold@skeeve.com>
* configure.ac: Update debug flags if developing.
@@ -1126,6 +3048,124 @@
(do_add_scrfile): Set it on -l.
(process_deferred): Check it also.
+2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.c (api_sym_update): If copying a subarray, must update
+ the parent_array pointer. Also, call the astore hook if non-NULL.
+ (api_set_array_element): Call the astore hook if non-NULL.
+
+2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (variable_create): Now takes a 3rd argument to tell caller
+ whether this is a deferred variable.
+ * awkgram.y (variable_create): Return indicator of whether this is
+ a deferred variable in a newly added 3rd arg.
+ (variable): Pass 3rd arg to variable_create.
+ * gawkapi.c (api_sym_update): If we triggered the creation of a deferred
+ variable, we must merge the extension's array elements into the deffered
+ array, not the other way around. The ENVIRON array has special funcs
+ to call setenv and unsetenv.
+
+2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (variable_create): Declare new function.
+ * awkgram.y (variable_create): New function to create a variable
+ taking the deferred variable list into consideration.
+ (variable): Call new function variable_create if the variable is
+ not found.
+ * gawkapi.c (api_sym_update): If an array is being created, then
+ call new function variable_create instead of install_symbol. If this
+ is the first reference to a deferred variable, than the new array
+ may contain elements that must be merged into the array provided by
+ the extension.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (wait_any): If the `interesting' argument is non-zero, then we
+ must not return until that child process has exited, since the caller
+ gawk_pclose depends on our returning its exit status. So in that case,
+ do not pass WNOHANG to waitpid.
+
+2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h: Fix another comment typo.
+
+2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h: Fix typo in comment.
+
+2015-01-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (gawk_api): Modify api_get_file to remove the typelen
+ argument.
+ (get_file): Remove typelen argument from the macro.
+ * gawkapi.c (api_get_file): Remove typelen argument.
+
+2014-12-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile.c (pprint): Be sure to set ip2 in all paths
+ through the code. Thanks to GCC 4.9 for the warning.
+
+2014-12-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_sub): Do not waste a byte at the end of a string.
+
+2014-12-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (yyerror): Do not waste a byte at the end of a string.
+ * builtin.c (do_match): Ditto.
+ * command.y (append_statement): Ditto.
+ * debug.c (gprintf, serialize): Ditto.
+ * field.c (set_FIELDWIDTHS): Ditto.
+ * io.c.c (grow_iop_buffer): Ditto.
+ * profile.c (pp_string, pp_group3): Ditto.
+
+2014-12-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * array.c (concat_exp): Do not waste a byte at the end of a string.
+ * awkgram.y (common_exp): Ditto.
+ * builtin.c (do_substr): Ditto.
+ * eval.c (set_OFS): Ditto.
+ * field.c (rebuild_record): Ditto.
+ * gawkapi.h (r_make_string): Ditto.
+ * interpret.h (r_interpret): Ditto for Op_assign_concat.
+ * node.c (r_format_val, r_dupnode, make_str_node, str2wstr, wstr2str):
+ Ditto.
+ * re.c (make_regexp): Ditto.
+
+2014-12-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ Enable non-fatal output on per-file or global basis,
+ via PROCINFO.
+
+ * awk.h (RED_NON_FATAL): New redirection flag.
+ * builtin.c (efwrite): If RED_NON_FATAL set, just set ERRNO and return.
+ (do_printf): Check errflg and if set, set ERRNO and return.
+ (do_print): Ditto.
+ (do_print_rec): Ditto.
+ * io.c (redflags2str): Update table.
+ (redirect): Check for global PROCINFO["nonfatal"] or for
+ PROCINFO[file, "nonfatal"] and don't fail on open if set.
+ Add RED_NON_FATAL to flags.
+ (in_PROCINFO): Make smarter and more general.
+
+2014-12-12 Stephen Davies <sdavies@sdc.com.au>
+
+ Improve comment handling in pretty printing.
+
+ * awk.h (comment_type): New field in the node.
+ (EOL_COMMENT, FULL_COMMENT): New defines.
+ * awkgram.y (block_comment): New variable.
+ (check_comment): New function.
+ (grammar): Add code to handle comments as needed.
+ (get_comment): Now takes a flag indicating kind of comment.
+ (yylex): Collect comments appropriately.
+ (append_rule): Ditto.
+ * profile.c (pprint): Smarten up comment handling.
+ Have printing \n take comments into account.
+ (end_line): New function.
+ (pp_func): Better handling of function comments.
+
2014-12-10 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c: Sync with GNU grep.
@@ -1230,6 +3270,36 @@
and a it's a Node_val set to Nnull_string, return AWK_UNDEFINED instead
of AWK_NUMBER 0.
+2014-11-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (redirect_string): First argument should be const. Add a new
+ extfd argument to enable extensions to create files with pre-opened
+ file descriptors.
+ (after_beginfile): Declare function used in both eval.c and gawkapi.c.
+ * eval.c (after_beginfile): Remove extern declaration now in awk.h.
+ * gawkapi.c (api_get_file): Implement API changes to return
+ awk_input_buf_t and/or awk_output_buf_t info, as well as accept an
+ fd for inserting an opened file into the table.
+ * gawkapi.h (gawk_api): Modify the api_get_file declaration to
+ return awk_bool_t and add 3 new arguments -- a file descriptor
+ for inserting an already opened file, and awk_input_buf_t and
+ awk_output_buf_t to return info about both input and output.
+ (get_file): Add new arguments to the macro.
+ * io.c (redirect_string): First arg should be const, and add a new
+ extfd arg so extensions can pass in a file that has already been
+ opened by the extension. Use the passed-in fd when appropriate,
+ and pass it into two_way_open.
+ (redirect): Pass new fd -1 arg to redirect_string.
+ (two_way_open): Accept new extension fd parameter and open it
+ as a socket.
+
+2014-11-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (retryable): New function to indicate whether I/O can be
+ retried for this file instead of throwing a hard error.
+ (get_a_record) Check whether this file is configured for retryable
+ I/O before returning nonstandard -2.
+
2014-11-03 Norihiro Tanaka <noritnk@kcn.ne.jp>
* re.c (research): Use dfa superset to improve matching speed.
@@ -1252,6 +3322,16 @@
(is_unary_minus): New function.
(pp_concat): Add checks for unary minus; needs to be parenthesized.
+2014-10-30 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * NEWS: Mention installation of /etc/profile.d/gawk.{csh,sh}.
+
+2014-10-29 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * configure.ac (AC_CONFIG_FILES): Add extras/Makefile.
+ * Makefile.am (SUBDIRS): Add extras.
+ * extras: Add new subdirectory.
+
2014-10-29 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c: Sync with GNU grep. Again, again.
@@ -1313,12 +3393,35 @@
* profile.c (pprint): Fix typo in header. Sheesh.
+ Unrelated:
+
+ * awkgram.y (mk_program): Add a comment that we don't need to
+ clear the comment* variables.
+
2014-10-04 Arnold D. Robbins <arnold@skeeve.com>
* profile.c (pp_string_fp): Fix breaklines case to actually
output the current letter. This broke at gawk 4.0.0. Sigh.
Thanks to Bert Bos (bert@w3.org) for the report.
+2014-10-03 Stephen Davies <sdavies@sdc.com.au>
+
+ * awkgram.y (program_comment): Renamed from comment0.
+ (function_comment): Renamed from commentf.
+
+2014-10-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y, profile.c: Minor white space cleanups.
+
+2014-10-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ Fix a few compile warnings:
+
+ * awkgram.y (split_comment): Make static.
+ General: Remove some unused variables, clean up some whitepace nits.
+
+ * profile.c (indent): Add some braces to turn off compiler warnings.
+
2014-09-29 Andrew J. Schorr <aschorr@telemetry-investments.com>
* main.c (main): In optlist, it should say "h", not "h:", since there
@@ -1391,6 +3494,45 @@
since use of isalnum() let non-ASCII letters slip through into
identifiers.
+2014-09-13 Stephen Davies <sdavies@sdc.com.au>
+
+ When doing pretty-printing (but not profiling), include the original
+ comments in the output.
+
+ General rules:
+
+ Pretty printing:
+ - Do NOT indent by a tab
+ - Do NOT print the header comments ("# BEGIN rules", etc.)
+ - DO print the comments that are in the program
+
+ Profiling:
+ - DO indent by a tab
+ - DO print the header comments
+ - Do NOT print the program's original comments
+
+ * awkgram.y (comment0, commentf): New varibles that are pointers to
+ program and function comments.
+ (get_comment): New function that retrieves consecutive comment lines
+ and empty lines as a unit).
+ (split_comment): New function: iff first block in the program is a
+ function and it is predeeded by comments, take the last non-blank
+ line as function comment and any preceeding lines as program comment.)
+
+ Following token rules were changed to handle comments:
+
+ * awkgram.y (pattern, LEX_BEGIN, LEX_END, LEX_BEGINFILE, LEX_ENDFILE,
+ action, function_prologue, statements): Update to handle comments.
+
+ Following functions were changed to handle comments:
+
+ * awkgram.y (mk_program, mk_function, allow_newline and yylex): Update
+ to handle comments. (Also fixed typo in case '\\'.)
+
+ * profile.c (print_comment): New function to format comment printing.
+ (indent, pprint, dump_prog, pp_func): Changed to handle comments and
+ the revised indentation rules.
+
2014-09-07 Arnold D. Robbins <arnold@skeeve.com>
* awk.h: Move libsigsegv stuff to ...
@@ -1452,6 +3594,27 @@
* 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.
@@ -1476,6 +3639,13 @@
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:
+ * cmake/package.cmake: Copyright update.
+ * README.cmake:
+ * README_d/README.cmake: Moved file.
+
2014-08-12 Arnold D. Robbins <arnold@skeeve.com>
OFS being set should rebuild $0 using previous OFS if $0
@@ -1547,6 +3717,12 @@
* awk.h (cleanup_mpfr): Add declaration.
* main.c (main): Add call to `cleanup_mpfr'.
+ Fix memory leak:
+
+ * mpfr.c (do_mpfr_div): Add unref to denominator and numerator
+ to not leak memory. Thanks to Katie Wasserman <katie@wass.net>
+ for isolating the problem to that routine.
+
2014-07-25 Arnold D. Robbins <arnold@skeeve.com>
* main.c (main): Add a warning message if -M is used and gawk was
@@ -1569,6 +3745,21 @@
2014-07-10 Arnold D. Robbins <arnold@skeeve.com>
+ New `div()' function to do integer division and remainder;
+ mainly useful for use with GMP integers. Thanks to
+ Katie Wasserman <katie@wass.net> for the suggestion.
+
+ * awk.h (do_div, do_mpfr_div): Declare new functions.
+ * builtin.c (do_div): New function.
+ * mpfr.c (do_mpfr_div): New function.
+ * awkgram.y (tokentab): New entry.
+ (snode): Add check for do_div/do_mpfr_div to make 3rd arg
+ be an array.
+ * NEWS: Updated.
+ * TODO: Updated.
+
+2014-07-10 Arnold D. Robbins <arnold@skeeve.com>
+
* awkgram.y (check_for_bad): New routine to do the fatal message,
with smarter checking.
(nextc): Call it as appropriate.
@@ -1583,6 +3774,13 @@
for bad characters in the source program.
(yylex): Adjust calls.
+2014-06-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * main.c (main): The --pretty-print option no longer runs the
+ program. This removes the need for the GAWK_NO_PP_RUN environment var.
+ * NEWS: Updated.
+ * TODO: Updated.
+
2014-06-22 Paul Eggert <eggert@penguin.cs.ucla.edu>
Bring in from GNULIB:
@@ -1703,6 +3901,13 @@
been moved into the inetfile() function.
(two_way_open): Update args to inetfile().
+2014-04-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_rand): Make calls to random() in predictable
+ order to avoid order of evaluation differences amongst compilers.
+ Thanks to Anders Magnusson <ragge@ludd.ltu.se> (of the PCC team)
+ for the suggestion.
+
2014-04-18 Arnold D. Robbins <arnold@skeeve.com>
* configure.ac: Change adding of -export-dynamic for GCC to be
@@ -2069,6 +4274,11 @@
* main.c (main): Ignore SIGPIPE. See the comment in the code.
Thanks to Alan Broder for reporting the issue.
+ Unrelated:
+
+ * rand.c (do_rand): Fix computation and loop checking against
+ 1.0 to use do..while.
+
2013-10-16 Arnold D. Robbins <arnold@skeeve.com>
Make -O work again. Turns out that C99 bool variables
@@ -2086,6 +4296,11 @@
* re.c (resetup): Add a comment about the joy of syntax bits.
+ Unrelated:
+
+ * builtin.c (do_rand): If result is exactly 1.0, keep trying.
+ Thanks to Nelson Beebe.
+
2013-10-10 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c (lex): Sync with GNU grep. Handle multibyte \s and \S.
@@ -2105,6 +4320,13 @@
* dfa.c: Sync with GNU grep.
+2013-09-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * builtin.c (do_rand): Make the result more random by calling
+ random() twice. See the comment in the code. Thanks to
+ Bob Jewett <jewett@bill.scs.agilent.com> for the report and
+ the fix.
+
2013-09-24 Arnold D. Robbins <arnold@skeeve.com>
* debug.c (find_rule): Handle case where lineno is zero. Can happen
@@ -2186,6 +4408,12 @@
* regcomp.c, regex.h, regex_internal.h: Sync with GLIBC.
+2013-08-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * str_array.c (env_store): If the new value being stored is NULL,
+ pass in "" instead. Avoids core dump on Mac OS X.
+ Thanks to Hermann Peifer for the bug report.
+
2013-08-20 Arnold D. Robbins <arnold@skeeve.com>
* nonposix.h: New file. Contains FAKE_FD_VALUE.
@@ -2194,6 +4422,16 @@
2013-08-18 Arnold D. Robbins <arnold@skeeve.com>
+ Reflect updates to ENVIRON into the real environment.
+
+ * awk.h (init_env_array): Add declaration.
+ * main.c (load_environ): Call init_env_array.
+ * str_array.c (env_remove, env_store, env_clear, init_env_array):
+ New functions.
+ (env_array_func): New array vtable.
+
+2013-08-18 Arnold D. Robbins <arnold@skeeve.com>
+
* array.c (force_array): Set symbol->xarray to NULL before
initing the array if it was Node_var_new.
(null_array): Restore assert, undoing change of 2013-05-27.
@@ -2202,6 +4440,24 @@
* debug.c (print_memory): Fix whitespace / indentation.
+2013-08-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkgram.y (append_rule): Add attempt to insert any comment
+ before a rule. Commented out at the moment.
+
+2013-07-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awk.h (enum opcodeval): Add Op_comment.
+ * awkgram.y (comment): New variable to hold comment text.
+ (statement): Add saved comments to lists being built.
+ (allow_newline): Save comment text if necessary. Append if have
+ existing text.
+ (yylex): Ditto.
+ * debug.c (print_instruction): Handle Op_comment.
+ * eval.c (optypes): Add entry for Op_comment.
+ * interpret.h (r_interpret): Ditto.
+ * profile.c (pprint): For Op_comment, print the comment text.
+
2013-07-24 Arnold D. Robbins <arnold@skeeve.com>
* io.c (FAKE_FD_VALUE): Move definition from here ...
@@ -2212,6 +4468,45 @@
* io.c (get_a_record): Change `min' to `MIN' for consistency with
other files and general practice.
+2013-07-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * configure.ac (AC_CHECK_FUNCS): Check for sigprocmask.
+ * io.c (wait_any): If sigprocmask is available, block signals instead
+ of ignoring them temporarily.
+
+2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (gawk_api): Document that the api_get_file function will not
+ access the file type and length arguments if the file name is empty.
+
+2013-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * configure.ac (AC_CHECK_FUNCS): Add a check for waitpid.
+ * io.c (wait_any): Enhance comment to explain why we loop reaping all
+ exited children when the argument is zero. When available, use waitpid
+ with WNOHANG to avoid blocking. Remove my previous incorrect patch to
+ exit after reaping the first child. The function is intended to
+ wait for all children, since we are not careful about reaping children
+ as soon as they die.
+
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkapi.h (gawk_api): Remove unused api_lookup_file hook.
+ (lookup_file): Remove associated macro.
+ * gawkapi.c (api_lookup_file): Remove unused function.
+ (api_impl): Remove unused api_lookup_file hook.
+
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkgram.y (main_beginfile): Declare new global INSTRUCTION *.
+ (parse_program): Set main_beginfile to point to the BEGINFILE
+ instruction block.
+ * gawkapi.c (api_get_file): After nextfile starts a new file,
+ we need to run the BEGINFILE actions. We retrieve the
+ instruction pointer from main_beginfile and execute it until
+ we reach the Op_after_beginfile opcode. We then run after_beginfile
+ manually and restore the value of currule and source.
+
2013-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
* gawkapi.h (awk_element_t): Add comment indicating that the array
@@ -2222,6 +4517,45 @@
force_string redundant, since node_to_awk_value does that internally
when we request a string.
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * eval.c (update_ERRNO_string): Set PROCINFO["errno"] to 0.
+ * io.c (inrec): Since get_a_record may now return -2, be sure
+ to throw an error in that case as well.
+ (wait_any): Fix what appears to be a bug. The old logic repeatedly
+ called wait until it failed. When a process has multiple children,
+ this causes it to stall until all of them have exited. Instead,
+ we now exit the function after the first successful wait call.
+ (do_getline_redir, do_getline): Handle case where get_a_record
+ returns -2.
+ (errno_io_retry): New function to decide whether an I/O operation should
+ be retried.
+ (get_a_record): When read returns an error, call errno_io_retry to
+ decide whether the operation should be retried. If so, return -2
+ instead of setting the IOP_AT_EOF flag.
+
+2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * eval.c (update_ERRNO_int, unset_ERRNO): Update PROCINFO["errno"].
+
+2013-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awk.h (redirect_string): Declare new function that provides API access
+ to the redirection mechanism.
+ * gawkapi.h (GAWK_API_MINOR_VERSION): Bump from 0 to 1 since 2 new
+ hooks were added to the api.
+ (gawk_api_t): Add 2 new functions api_lookup_file and api_get_file.
+ (lookup_file, get_file): New macros to wrap the new API functions.
+ * gawkapi.c (curfile): Declare this extern, since it is needed
+ by lookup_file and get_flie.
+ (api_lookup_file): Find an open file using curfile or getredirect().
+ (api_get_file): Find or open a file using curfile or redirect_string().
+ (api_impl): Add api_lookup_file and api_get_file.
+ * io.c (redirect_string): Renamed from redirect and changed arguments
+ to take a string instead of a 'NODE *'. This allows it to be called
+ through the API's new get_file hook.
+ (redirect): Now implemented by calling redirect_string backend function.
+
2013-07-04 Arnold D. Robbins <arnold@skeeve.com>
* builtin.c (format_tree): Fixes for %c with multibyte characters
diff --git a/Checklist b/Checklist
index b33fac65..f180522d 100644
--- a/Checklist
+++ b/Checklist
@@ -1,4 +1,4 @@
-Fri Aug 12 11:39:43 IDT 2016
+Wed Nov 2 05:40:56 IST 2016
============================
A checklist for making releases
@@ -30,6 +30,7 @@ doc/gawk.1 is up to date
doc/awkcard.in is up to date
Run prepinfo on the manual.
Spell check the manual.
+Update the wordlist for spell checking.
test/Makefile.am: order and prettify lists of tests
API Version numbers have been modified correctly in gawkapi.h.
@@ -39,6 +40,7 @@ Testing on
make maintainer-clean
make release
+ compile with tcc
compile with pcc
compile with clang
diff --git a/Makefile.am b/Makefile.am
index 8660c111..0d2efd18 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,31 +51,27 @@ EXTRA_DIST = \
po/README \
pc \
posix \
- regcomp.c \
- regex_internal.c \
- regex_internal.h \
- regexec.c \
vms \
ylwrap
# The order to do things in.
#
+# Build in support first, since we need the support library.
+#
# Build explicitly in "." in order to build gawk first, so
# that `make check' without a prior `make' works.
-#
+SUBDIRS = support .
+
# Build in extension before test so that
# ./configure && make check
# works properly too.
-#
-# Build in awklib after in doc, since we want to extract
-# sample files if doc/gawk.texi changed.
-SUBDIRS = .
-
if ENABLE_EXTENSIONS
SUBDIRS += extension
endif
-SUBDIRS += doc awklib po test
+# Build in awklib after in doc, since we want to extract
+# sample files if doc/gawk.texi changed.
+SUBDIRS += extras doc awklib po test
# what to make and install
bin_PROGRAMS = gawk
@@ -92,8 +88,6 @@ base_sources = \
command.y \
custom.h \
debug.c \
- dfa.c \
- dfa.h \
eval.c \
ext.c \
field.c \
@@ -102,10 +96,6 @@ base_sources = \
gawkapi.c \
gawkapi.h \
gawkmisc.c \
- getopt.c \
- getopt.h \
- getopt1.c \
- getopt_int.h \
gettext.h \
int_array.c \
interpret.h \
@@ -118,21 +108,17 @@ base_sources = \
nonposix.h \
profile.c \
protos.h \
- random.c \
- random.h \
re.c \
- regex.c \
- regex.h \
replace.c \
str_array.c \
symbol.c \
- version.c \
- xalloc.h
+ version.c
gawk_SOURCES = $(base_sources)
# Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
-LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR)
+LDADD = support/libsupport.a \
+ $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR)
# Directory for gawk's data files. Automake supplies datadir.
pkgdatadir = $(datadir)/awk
@@ -144,7 +130,7 @@ DEFPATH='".$(PATH_SEPARATOR)$(pkgdatadir)"'
SHLIBEXT = "\"$(GAWKLIBEXT)"\"
DEFLIBPATH="\"$(pkgextensiondir)\""
-DEFS= -DDEFPATH=$(DEFPATH) -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"'
+DEFS= -DDEFPATH=$(DEFPATH) -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"' -I"$(srcdir)/support"
# Get rid of core files when cleaning
CLEANFILES = core core.*
diff --git a/Makefile.in b/Makefile.in
index afb9bdc7..9a46553a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -111,6 +111,10 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+
+# Build in extension before test so that
+# ./configure && make check
+# works properly too.
@ENABLE_EXTENSIONS_TRUE@am__append_1 = extension
bin_PROGRAMS = gawk$(EXEEXT)
subdir = .
@@ -118,14 +122,14 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
- $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libsigsegv.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -140,20 +144,19 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)"
PROGRAMS = $(bin_PROGRAMS)
am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
cint_array.$(OBJEXT) command.$(OBJEXT) debug.$(OBJEXT) \
- dfa.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
+ eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) \
- getopt.$(OBJEXT) getopt1.$(OBJEXT) int_array.$(OBJEXT) \
- io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) \
- node.$(OBJEXT) profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
- regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
- symbol.$(OBJEXT) version.$(OBJEXT)
+ int_array.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) \
+ msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) re.$(OBJEXT) \
+ replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
+ version.$(OBJEXT)
am_gawk_OBJECTS = $(am__objects_1)
gawk_OBJECTS = $(am_gawk_OBJECTS)
gawk_LDADD = $(LDADD)
am__DEPENDENCIES_1 =
-gawk_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+gawk_DEPENDENCIES = support/libsupport.a $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -262,9 +265,9 @@ am__define_uniq_tagged_files = \
ETAGS = etags
CTAGS = ctags
CSCOPE = cscope
-DIST_SUBDIRS = . extension doc awklib po test
+DIST_SUBDIRS = support . extension extras doc awklib po test
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/configh.in ABOUT-NLS \
- AUTHORS COPYING ChangeLog INSTALL NEWS README awkgram.c \
+ AUTHORS COPYING ChangeLog INSTALL NEWS README TODO awkgram.c \
command.c compile config.guess config.rpath config.sub depcomp \
install-sh missing mkinstalldirs ylwrap
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -325,7 +328,7 @@ CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
-DEFS = -DDEFPATH=$(DEFPATH) -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"'
+DEFS = -DDEFPATH=$(DEFPATH) -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"' -I"$(srcdir)/support"
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -374,6 +377,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POSUB = @POSUB@
+RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -468,26 +472,20 @@ EXTRA_DIST = \
po/README \
pc \
posix \
- regcomp.c \
- regex_internal.c \
- regex_internal.h \
- regexec.c \
vms \
ylwrap
# The order to do things in.
#
+# Build in support first, since we need the support library.
+#
# Build explicitly in "." in order to build gawk first, so
# that `make check' without a prior `make' works.
-#
-# Build in extension before test so that
-# ./configure && make check
-# works properly too.
-#
+
# Build in awklib after in doc, since we want to extract
# sample files if doc/gawk.texi changed.
-SUBDIRS = . $(am__append_1) doc awklib po test
+SUBDIRS = support . $(am__append_1) extras doc awklib po test
include_HEADERS = gawkapi.h
# sources for both gawk and dgawk
@@ -501,8 +499,6 @@ base_sources = \
command.y \
custom.h \
debug.c \
- dfa.c \
- dfa.h \
eval.c \
ext.c \
field.c \
@@ -511,10 +507,6 @@ base_sources = \
gawkapi.c \
gawkapi.h \
gawkmisc.c \
- getopt.c \
- getopt.h \
- getopt1.c \
- getopt_int.h \
gettext.h \
int_array.c \
interpret.h \
@@ -527,21 +519,18 @@ base_sources = \
nonposix.h \
profile.c \
protos.h \
- random.c \
- random.h \
re.c \
- regex.c \
- regex.h \
replace.c \
str_array.c \
symbol.c \
- version.c \
- xalloc.h
+ version.c
gawk_SOURCES = $(base_sources)
# Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
-LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR)
+LDADD = support/libsupport.a \
+ $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR)
+
# stuff for compiling gawk/pgawk
DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"'
@@ -670,15 +659,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cint_array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/field.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/floatcomp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gawkapi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gawkmisc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int_array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@@ -686,9 +672,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/re.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/replace.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str_array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol.Po@am__quote@
diff --git a/NEWS b/NEWS
index c149dfd7..327b9259 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,123 @@
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved.
+Changes from 4.1.x to 4.2.0
+---------------------------
+
+1. If not in POSIX mode, changes to ENVIRON are reflected into
+ gawk's environment, affecting any programs run by system()
+ or for piped redirections. This can also affect built-in routines, such
+ as mktime(), which is typically influenced by the TZ environment variable.
+
+2. The series of numbers returned by rand() should now be "more
+ random" than previously. Gawk's rand() remains repeatable; you will
+ get the same series of numbers each time you call rand() repeatedly,
+ but this will be a different series than previously.
+
+3. The --pretty-print option no longer runs the program too.
+
+4. The igawk script and igawk.1 man page are no longer installed by
+ `make install'. They have been obsolete since gawk 4.0.0.
+
+5. Gawk now has a `intdiv()' function to perform integer division; this is
+ primarily useful for the -M option to avoid MPFR division when all
+ values involved are integers.
+
+6. Gawk can now be built with CMake. This is an alternative build
+ 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. Setting PROCINFO["redirection", "NONFATAL"] to true makes I/O
+ errors for "redirection" not fatal, setting ERRNO. Setting
+ PROCINFO["NONFATAL"] makes all I/O nonfatal.
+
+9. MirBSD is no longer supported.
+
+10. Pretty printing now preserves comments and places them into the
+ pretty-printed file.
+
+11. `make install' now installs shell startup files
+ $sysconfdir/profile.d/gawk.{csh,sh} containing shell functions to
+ manipulate the AWKPATH and AWKLIBPATH environment variables. On a Fedora
+ system, these files belong in /etc/profile.d, but the appropriate location
+ may be different on other platforms.
+
+12. Gawk now supports retryable I/O via PROCINFO[input-file, "RETRY"]; see
+ the manual.
+
+13. The API minor version has been increased to 2; the get_file()
+ API provides access to open redirections. Also see the manual.
+
+14. Revisions in the POSIX standard remove the special case for POSIX
+ mode when FS = " " where newline was not a field separator. The code
+ and doc have been updated.
+
+15. Gawk now supports strongly typed regexp constants. Such constants
+ look like @/.../. You can assign them to variables, pass them to
+ functions, use them in ~, !~ and the case part of a switch statement.
+ More details are provided in the manual.
+
+16. The new typeof() function can be used to indicate if a variable or
+ array element is an array, regexp, string or number. The isarray()
+ function is deprecated in favor of typeof().
+
+17. As promised when 4.1 was released, the old extension mechanism,
+ using the `extension' function, is now gone.
+
+18. Support for GNU/Linux on Alpha systems has been removed.
+
+19. Optimizations are now enabled by default. Use the new -s/--no-optimize
+ option(s) to disable them. Pretty-printing and profiling automatically
+ disable optimizations so that the output program is the same as the
+ original input program.
+
+20. The extension API now provides a mechanism for generating nonfatal
+ error messages.
+
+20. Gawk now uses fwrite_unlocked if it's available. The yields a 7% - 18%
+ improvement in raw output speed (gawk '{ print }' on a large file).
+
+21. Pretty-printing now uses the original text of constant numeric values for
+ pretty-printing and profiling.
+
+22. Passing negative operands to any of the bitwise functions now
+ produces a fatal error.
+
+23. The C API has undergone changes that break binary compatibility with
+ the previous version. Thus the API version is now at 2.0. YOU WILL
+ NEED TO RECOMPILE YOUR EXTENSIONS to work with this version of gawk.
+ Source code compatibility remains intact, although you will get
+ compiler warnings if you do not revise your extensions. We strongly
+ recommend that you do so. Fortunately, the changes are fairly minor
+ and straightforward.
+
+24. Programs that toggle IGNORECASE a lot should now be noticeably faster.
+
+25. The mktime function now accepts an optional second argument. If this
+ argument is present and is non-zero or non-null, the time will be converted
+ from UTC instead of from the local timezone.
+
+26. The FIELDWIDTHS parsing syntax has been enhanced to allow specifying
+ how many characters to skip before a field starts. It also allows
+ specifying '*' as the last character to mean "the rest of the record".
+ Field splitting with FIELDWIDTHS now sets NF correctly. The documentation
+ for FIELDWIDTHS in the manual has been considerably reorganized and
+ improved as well.
+
+27. An API input parser now has the ability to override the default field
+ parsing mechanism by specifying the locations of each field in the input
+ record. When this is in effect, PROCINFO["FS"] will be set to "API".
+
+28. The PROCINFO["argv"] array records all of gawk's command line arguments
+ as gawk received them (the values of the C level argv array).
+
+29. Pretty-printing now preserves parenthesized expressions as they
+ were in the source file. This solves several niggling corner cases
+ with such things.
+
Changes from 4.1.3 to 4.1.4
---------------------------
diff --git a/README_d/ChangeLog b/README_d/ChangeLog
index da3ced84..0ef41704 100644
--- a/README_d/ChangeLog
+++ b/README_d/ChangeLog
@@ -1,3 +1,7 @@
+2016-12-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * README.macosx: Updated.
+
2016-10-31 Arnold D. Robbins <arnold@skeeve.com>
* README.aix: New file.
@@ -31,6 +35,10 @@
* README.macosx: New file.
+2014-08-12 Juergen Kahrs <jkahrs@users.sourceforge.net>
+
+ * README.cmake: Moved file from top-level to here.
+
2014-04-08 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.1: Release tar ball made.
diff --git a/README_d/README.cmake b/README_d/README.cmake
new file mode 100644
index 00000000..7a61aed4
--- /dev/null
+++ b/README_d/README.cmake
@@ -0,0 +1,100 @@
+CMake is a build automation system
+ http://en.wikipedia.org/wiki/Cmake
+
+We try to use it as a replacement for the established GNU build system.
+This attempt is currently only experimental. If you wonder why anyone
+should do this, read
+
+ Why the KDE project switched to CMake -- and how
+ http://lwn.net/Articles/188693/
+ Escape from GNU Autohell!
+ http://www.shlomifish.org/open-source/anti/autohell
+
+- How can I get GNU Awk compiled with CMake as fast as possible ?
+ git clone git://git.savannah.gnu.org/gawk.git
+ cd gawk
+ git checkout cmake
+ mkdir build
+ cd build
+ cmake ..
+ make
+ ./gawk --version
+ make test
+Notice that this git-checkout allows you to read the source code,
+track the cmake branch and get updates. You will not be able to
+commit anything.
+
+- How can I use git to contribute source code ?
+You need an account at Savannah. Read this to understand the first steps:
+ http://savannah.gnu.org/maintenance/UsingGit
+ README.git
+Use your account there to register your public ssh key at Savannah.
+Then you are ready to checkout. Remember that (when cloning) you are
+setting up your own local repository and make sure you configure it
+properly.
+ git clone ssh://my_account_name@git.sv.gnu.org/srv/git/gawk.git
+ git config --global user.name "first-name last-name"
+ git config --global user.email First.Last@email.com
+ git config --global color.ui auto
+
+- What is the current status of the cmake branch ?
+It has just begun, pre-alpha, unclear if it will ever be taken up
+by the maintainer. We want to study if using CMake with such a
+basic tool like gawk is feasible and if it easier to use than
+the GNU build system.
+
+- Where can I find a tutorial on CMake basics ?
+Use the "official tutorial":
+ http://www.cmake.org/cmake/help/cmake_tutorial.html
+
+- Where is the reference of all commands and variables ?
+Depending on the CMake version you use, select one of these:
+ http://www.cmake.org/cmake/help/v2.8.10/cmake.html
+
+- How can I cross-compile ?
+Proceed in the same way as explained above for native compilation,
+but use a different build directory. When using CMake, do this:
+ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain_mingw32.cmake ..
+Write a new Toolchain file for your cross-compiler and use it.
+
+- How can I build an installable file ?
+By default, installable files will not be generated.
+But if you instruct CMake about the kind of installable file you want,
+then some kinds of files can be generated.
+The exact kind of installable file depends on your operating system.
+Possible kinds are TGZ (.tar.gz file), RPM (.rpm file), and DEB (.deb file).
+ cmake -DCPACK_GENERATOR=DEB ..
+ make package
+
+- Can I build an executable that runs on any Win32 platform ?
+Yes, there are two ways of doing this.
+In both cases you need a MinGW compiler and the NSIS package builder
+installed on the host that shall do the build.
+ http://sourceforge.net/projects/mingw
+ http://sourceforge.net/projects/nsis
+When installed properly, the NSIS tool can even build an installer file
+(a single .exe file that unpacks, registers and installs the gawk executable
+and several other files).
+1. way: native build on a Win32 platform
+ http://www.cmake.org/cmake/help/runningcmake.html
+ After clicking "Configure" select the MinGW option with the default native compiler
+ In the build directory, the command "mingw32-make" will build the gawk.exe
+ The command "mingw32-make package" will build installer file
+2. way: build with cross-compiler on a Linux platform like Ubuntu 12.04 LTS
+ Proceed as describe above for cross-compilers.
+ The command "make ; make package" will build gawk.exe and the installer file
+
+- How can I run test cases ?
+You can run all the test cases that are defined in test/Makefile.am.
+These test case scripts were not changed, but the way they are invoked has
+been adapted to CMake habits.
+See http://cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing
+ cmake ..
+ make
+ make test # run all test cases
+ ctest -N # list all test cases but don't run them
+ ctest -R BASIC # run all test cases belonging to group BASIC
+ ctest -R MPFR # run all test cases belonging to group MPFR
+ ctest -E SHLIB.filefunc # run all tests, except the SHLIB.filefunc test case
+Remember that running test cases is possible only after a native build.
+
diff --git a/README_d/README.macosx b/README_d/README.macosx
index f147d4af..de9305de 100644
--- a/README_d/README.macosx
+++ b/README_d/README.macosx
@@ -1,3 +1,12 @@
+Fri Dec 23 13:42:58 IST 2016
+============================
+
+If anyone besides me still has a PowerPC Macintosh, it's no longer
+possible to build gawk using MPFR. C99 and the last version of MPFR
+that works on that platform don't get along, and I could not solve
+the problem. So I simply disabled the MPFR check in configure.ac on
+that platform.
+
Wed Aug 24 21:54:13 IDT 2016
============================
diff --git a/TODO b/TODO
new file mode 100644
index 00000000..fa6e1177
--- /dev/null
+++ b/TODO
@@ -0,0 +1,162 @@
+Mon Jul 3 21:05:03 IDT 2017
+============================
+
+There were too many files tracking different thoughts and ideas for
+things to do, or consider doing. This file merges them into one. As
+tasks are completed, they should be removed.
+
+This file should exist only in the master branch or branches based off
+of it for development, but not in the stable branch. This may require some
+careful work with Git.
+
+TODO
+====
+
+Minor Cleanups and Code Improvements
+------------------------------------
+
+ API:
+ ??? #if !defined(GAWK) && !defined(GAWK_OMIT_CONVENIENCE_MACROS)
+
+ ?? Add debugger commands to reference card
+
+ Look at function order within files.
+
+ Consider removing use of and/or need for the protos.h file.
+
+ Recheck if gnulib regex can be dropped in
+
+ Fully synchronize whitespace tests (for \s, \S in Unicode
+ environment) with those of GNU grep.
+
+ See if something like b = a "" can be optimized to not do
+ a concatenation, but instead just set STRCUR on a.
+
+Minor New Features
+------------------
+
+ Enable command line source text in the debugger.
+
+ Enhance extension/fork.c waitpid to allow the caller to specify
+ the options. And add an optional array argument to wait and
+ waitpid in which to return exit status information.
+
+ Consider relaxing the strictness of --posix.
+
+ ? Add an optional base to strtonum, allowing 2-36.
+
+ ? Optional third argument for index indicating where to start the
+ search.
+
+Major New Features
+------------------
+
+ Think about how to generalize indirect access. Manuel Collado
+ suggests things like
+
+ foo = 5
+ @"foo" += 4
+
+ Also needed:
+
+ Indirect through array elements, not just scalar variables
+
+ Add ability to do decimal arithmetic.
+
+ Rework management of array index storage. (Partially DONE.)
+
+ Consider using an atom table for all string array indices.
+
+ DBM storage of awk arrays. Try to allow multiple dbm packages.
+
+ ?? A RECLEN variable for fixed-length record input. PROCINFO["RS"]
+ would be "RS" or "RECLEN" depending upon what's in use.
+ *** Could this be done as an extension?
+
+ ?? Use a new or improved dfa and/or regex library.
+
+ Rewrite in C++.
+
+Things To Think About That May Never Happen
+-------------------------------------------
+
+ Consider making shadowed variables a warning and not
+ a fatal warning when --lint=fatal.
+
+ Similar for extra parameters in a function call.
+
+ Look at code coverage tools, like S2E: https://s2e.epfl.ch/
+
+ Try running with diehard. See http://www.diehard-software.org,
+ https://github.com/emeryberger/DieHard
+
+ Implement namespaces. Arnold suggested the following in an email:
+ - Extend the definition of an 'identifier' to include "." as a valid
+ character although an identifier can't start with it.
+ - Extension libraries install functions and global variables with names
+ that have a "." in them: XML.parse(), XML.name, whatever.
+ - Awk code can read/write such variables and call such functions,
+ but they cannot define such functions
+ function XML.foo() { .. } # error
+ or create a variable with such a name if it doesn't exist. This would
+ be a run-time error, not a parse-time error.
+ - This last rule may be too restrictive.
+ I don't want to get into fancy rules a la perl and file-scope visibility
+ etc, I'd like to keep things simple. But how we design this is going
+ to be very important.
+
+ Include a sample rpm spec file in a new packaging subdirectory.
+ (Really needed?)
+
+ Patch lexer for @include and @load to make quotes optional.
+ (Really needed?)
+
+ Add a lint check if the return value of a function is used but
+ the function did not supply a value.
+
+ Consider making gawk output +nan for NaN values so that it
+ will accept its own output as input.
+ NOTE: Investigated this. GLIBC formats NaN as '-nan'
+ and -NaN as 'nan'. Dealing with this is not simple.
+
+ Review the bash source script for working with shared libraries in
+ order to nuke the use of libtool. [ Partially started in the
+ dead-branches/nolibtool branch. ]
+
+Things That We Decided We Will Never Do
+=======================================
+
+ Consider moving var_value info into Node_var itself to reduce
+ memory usage. This would break all uses of get_lhs in the
+ code. It's too sweeping a change.
+
+ Add macros for working with flags instead of using & and |
+ directly.
+
+ FIX regular field splitting to use FPAT algorithm.
+ Note: Looked at this. Not sure it's with the trouble:
+ If it ain't broke...
+
+ Scope IDs for IPv6 addresses
+
+ Gnulib
+
+ Make FIELDWIDTHS be an array?
+
+ "Do an optimization pass over parse tree?"
+ This isn't relevant now that we are using a byte code engine.
+
+ "Consider integrating Fred Fish's DBUG library into gawk."
+ I did this once as an experiment. But I don't see a lot of value
+ to this at this stage of the development. Stepping through things
+ in a debugger is generally enough. Also, I would have to try to
+ track down the latest version of this.
+
+ "Make awk '/foo/' files... run at egrep speeds" (How?)
+ This has been on the list since the early days (gawk 1.x or early
+ 2.x). But I am not sure how to really do this, nor have I done
+ timings, nor does there seem to be any real demand for this.
+
+ Change from dlopen to using the libltdl library (i.e. lt_dlopen).
+ This may support more platforms. If we move off of libtool
+ then this is the wrong direction.
diff --git a/aclocal.m4 b/aclocal.m4
index c150e9a8..2e07e0a8 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1155,7 +1155,6 @@ m4_include([m4/codeset.m4])
m4_include([m4/gettext.m4])
m4_include([m4/iconv.m4])
m4_include([m4/intlmacosx.m4])
-m4_include([m4/isc-posix.m4])
m4_include([m4/lcmessage.m4])
m4_include([m4/lib-ld.m4])
m4_include([m4/lib-link.m4])
diff --git a/array.c b/array.c
index 8c9cc72e..3159bfdc 100644
--- a/array.c
+++ b/array.c
@@ -2,23 +2,23 @@
* array.c - routines for awk arrays.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2014, 2016,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -102,7 +102,7 @@ make_array()
/* vname, flags, and parent_array not set here */
return array;
-}
+}
/* null_array --- force symbol to be an empty typeless array */
@@ -150,7 +150,7 @@ null_lookup(NODE *symbol, NODE *subs)
return symbol->alookup(symbol, subs);
}
-/* null_length --- default function for array length interface */
+/* null_length --- default function for array length interface */
NODE **
null_length(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
@@ -198,7 +198,7 @@ assoc_copy(NODE *symbol, NODE *newsymb)
void
assoc_dump(NODE *symbol, NODE *ndump)
{
- if (symbol->adump)
+ if (symbol->adump)
(void) symbol->adump(symbol, ndump);
}
@@ -229,7 +229,7 @@ make_aname(const NODE *symbol)
max_alen = alen + SLEN;
emalloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname");
} else if (alen > max_alen) {
- max_alen = alen + SLEN;
+ max_alen = alen + SLEN;
erealloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname");
}
memcpy(aname, symbol->vname, alen + 1);
@@ -258,11 +258,11 @@ array_vname(const NODE *symbol)
const NODE *save_symbol = symbol;
const char *from = _("from %s");
const char *aname;
-
+
if (symbol->type != Node_array_ref
|| symbol->orig_array->type != Node_var_array
) {
- if (symbol->type != Node_var_array || symbol->parent_array == NULL)
+ if (symbol->type != Node_var_array || symbol->parent_array == NULL)
return symbol->vname;
return make_aname(symbol);
}
@@ -373,7 +373,7 @@ force_array(NODE *symbol, bool canfatal)
/* set_SUBSEP --- update SUBSEP related variables when SUBSEP assigned to */
-
+
void
set_SUBSEP()
{
@@ -396,7 +396,7 @@ concat_exp(int nargs, bool do_subsep)
size_t subseplen = 0;
int i;
extern NODE **args_array;
-
+
if (nargs == 1)
return POP_STRING();
@@ -417,7 +417,7 @@ concat_exp(int nargs, bool do_subsep)
}
len += (nargs - 1) * subseplen;
- emalloc(str, char *, len + 2, "concat_exp");
+ emalloc(str, char *, len + 1, "concat_exp");
r = args_array[nargs];
memcpy(str, r->stptr, r->stlen);
@@ -498,13 +498,13 @@ adjust_fcall_stack(NODE *symbol, int nsubs)
* But excludes cases like (nsubs = 0):
*
* function f(c, d) { delete c; ..}
- * BEGIN { a[0][0] = 1; f(a[0], a[0]); ...}
+ * BEGIN { a[0][0] = 1; f(a[0], a[0]); ...}
*/
null_array(r);
r->parent_array = NULL;
continue;
- }
+ }
/* Case 2 */
for (n = n->parent_array; n != NULL; n = n->parent_array) {
@@ -583,8 +583,8 @@ do_delete(NODE *symbol, int nsubs)
if (val == NULL) {
if (do_lint) {
subs = force_string(subs);
- lintwarn(_("delete: index `%s' not in array `%s'"),
- subs->stptr, array_vname(symbol));
+ lintwarn(_("delete: index `%.*s' not in array `%s'"),
+ (int) subs->stlen, subs->stptr, array_vname(symbol));
}
/* avoid memory leak, free all subs */
free_subs(i);
@@ -648,7 +648,7 @@ do_delete_loop(NODE *symbol, NODE **lhs)
efree(list);
/* blast the array in one shot */
- adjust_fcall_stack(symbol, 0);
+ adjust_fcall_stack(symbol, 0);
assoc_clear(symbol);
}
@@ -660,7 +660,6 @@ value_info(NODE *n)
{
#define PREC_NUM -1
-#define PREC_STR -1
if (n == Nnull_string || n == Null_field) {
fprintf(output_fp, "<(null)>");
@@ -669,7 +668,7 @@ value_info(NODE *n)
if ((n->flags & (STRING|STRCUR)) != 0) {
fprintf(output_fp, "<");
- fprintf(output_fp, "\"%.*s\"", PREC_STR, n->stptr);
+ fprintf(output_fp, "\"%.*s\"", (int) n->stlen, n->stptr);
if ((n->flags & (NUMBER|NUMCUR)) != 0) {
#ifdef HAVE_MPFR
if (is_mpg_float(n))
@@ -696,20 +695,30 @@ value_info(NODE *n)
fprintf(output_fp, ":%s", flags2str(n->flags));
- if ((n->flags & FIELD) == 0)
+ if ((n->flags & MALLOC) != 0)
fprintf(output_fp, ":%ld", n->valref);
else
fprintf(output_fp, ":");
if ((n->flags & (STRING|STRCUR)) == STRCUR) {
+ size_t len;
+
fprintf(output_fp, "][");
- fprintf(output_fp, "stfmt=%d, ", n->stfmt);
- fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "<unused>"
+ fprintf(output_fp, "stfmt=%d, ", n->stfmt);
+ /*
+ * If not STFMT_UNUSED, could be CONVFMT or OFMT if last
+ * used in a print statement. If immutable, could be that it
+ * was originally set as a string, or it's a number that has
+ * an integer value.
+ */
+ len = fmt_list[n->stfmt]->stlen;
+ fmt_list[n->stfmt]->stptr[len] = '\0';
+ fprintf(output_fp, "FMT=\"%s\"",
+ n->stfmt == STFMT_UNUSED ? "<unused>"
: fmt_list[n->stfmt]->stptr);
}
#undef PREC_NUM
-#undef PREC_STR
}
@@ -796,6 +805,7 @@ asort_actual(int nargs, sort_context_t ctxt)
NODE **list = NULL, **ptr, **lhs;
unsigned long num_elems, i;
const char *sort_str;
+ char save;
if (nargs == 3) /* 3rd optional arg */
s = POP_STRING();
@@ -804,6 +814,8 @@ asort_actual(int nargs, sort_context_t ctxt)
s = force_string(s);
sort_str = s->stptr;
+ save = s->stptr[s->stlen];
+ s->stptr[s->stlen] = '\0';
if (s->stlen == 0) { /* default sorting */
if (ctxt == ASORT)
sort_str = "@val_type_asc";
@@ -844,6 +856,7 @@ asort_actual(int nargs, sort_context_t ctxt)
/* sorting happens inside assoc_list */
list = assoc_list(array, sort_str, ctxt);
+ s->stptr[s->stlen] = save;
DEREF(s);
num_elems = assoc_length(array);
@@ -906,6 +919,7 @@ asort_actual(int nargs, sort_context_t ctxt)
arr = make_array();
subs = force_string(subs);
arr->vname = subs->stptr;
+ arr->vname[subs->stlen] = '\0';
subs->stptr = NULL;
subs->flags &= ~STRCUR;
arr->parent_array = array; /* actual parent, not the temporary one. */
@@ -1047,7 +1061,7 @@ sort_up_index_number(const void *p1, const void *p2)
ret = cmp_numbers(t1, t2);
if (ret != 0)
- return ret;
+ return ret;
/* break a tie with the index string itself */
t1 = force_string((NODE *) t1);
@@ -1157,17 +1171,8 @@ sort_up_value_type(const void *p1, const void *p2)
}
/* two scalars */
- /* 2. Resolve MAYBE_NUM, so that have only NUMBER or STRING */
- if ((n1->flags & MAYBE_NUM) != 0)
- (void) force_number(n1);
- if ((n2->flags & MAYBE_NUM) != 0)
- (void) force_number(n2);
-
- /* 2.5. Resolve INTIND, so that is STRING, and not NUMBER */
- if ((n1->flags & INTIND) != 0)
- (void) force_string(n1);
- if ((n2->flags & INTIND) != 0)
- (void) force_string(n2);
+ (void) fixtype(n1);
+ (void) fixtype(n2);
if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) {
return cmp_numbers(n1, n2);
@@ -1243,7 +1248,7 @@ sort_user_func(const void *p1, const void *p2)
}
-/* assoc_list -- construct, and optionally sort, a list of array elements */
+/* assoc_list -- construct, and optionally sort, a list of array elements */
NODE **
assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt)
@@ -1282,7 +1287,7 @@ assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt)
extern int currule;
int save_rule = 0;
assoc_kind_t assoc_kind = ANONE;
-
+
elem_size = 1;
for (qi = 0, j = sizeof(sort_funcs)/sizeof(sort_funcs[0]); qi < j; qi++) {
@@ -1306,7 +1311,7 @@ assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt)
} else { /* unrecognized */
NODE *f;
- const char *sp;
+ const char *sp;
for (sp = sort_str; *sp != '\0' && ! isspace((unsigned char) *sp); sp++)
continue;
@@ -1330,7 +1335,7 @@ assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt)
code->func_body = f;
code->func_name = NULL; /* not needed, func_body already assigned */
(code + 1)->expr_count = 4; /* function takes 4 arguments */
- code->nexti = bcalloc(Op_stop, 1, 0);
+ code->nexti = bcalloc(Op_stop, 1, 0);
/*
* make non-redirected getline, exit, `next' and `nextfile' fatal in
@@ -1348,29 +1353,29 @@ assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt)
list = symbol->alist(symbol, & akind);
assoc_kind = (assoc_kind_t) akind.flags; /* symbol->alist can modify it */
- if (list == NULL || ! cmp_func || (assoc_kind & (AASC|ADESC)) != 0)
- return list; /* empty list or unsorted, or list already sorted */
+ /* check for empty list or unsorted, or list already sorted */
+ if (list != NULL && cmp_func != NULL && (assoc_kind & (AASC|ADESC)) == 0) {
+ num_elems = assoc_length(symbol);
+
+ qsort(list, num_elems, elem_size * sizeof(NODE *), cmp_func); /* shazzam! */
+
+ if (sort_ctxt == SORTED_IN && (assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) {
+ /* relocate all index nodes to the first half of the list. */
+ for (j = 1; j < num_elems; j++)
+ list[j] = list[2 * j];
- num_elems = assoc_length(symbol);
+ /* give back extra memory */
- qsort(list, num_elems, elem_size * sizeof(NODE *), cmp_func); /* shazzam! */
+ erealloc(list, NODE **, num_elems * sizeof(NODE *), "assoc_list");
+ }
+ }
if (cmp_func == sort_user_func) {
code = POP_CODE();
- currule = save_rule; /* restore current rule */
+ currule = save_rule; /* restore current rule */
bcfree(code->nexti); /* Op_stop */
bcfree(code); /* Op_func_call */
}
- if (sort_ctxt == SORTED_IN && (assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) {
- /* relocate all index nodes to the first half of the list. */
- for (j = 1; j < num_elems; j++)
- list[j] = list[2 * j];
-
- /* give back extra memory */
-
- erealloc(list, NODE **, num_elems * sizeof(NODE *), "assoc_list");
- }
-
return list;
}
diff --git a/awk.h b/awk.h
index 27fb2751..3edfe5bd 100644
--- a/awk.h
+++ b/awk.h
@@ -1,23 +1,23 @@
/*
- * awk.h -- Definitions for gawk.
+ * awk.h -- Definitions for gawk.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -178,6 +178,10 @@ extern void *memset_ulong(void *dest, int val, unsigned long l);
#define memset memset_ulong
#endif
+#ifdef HAVE_FWRITE_UNLOCKED
+#define fwrite fwrite_unlocked
+#endif /* HAVE_FWRITE_UNLOCKED */
+
#if defined(__EMX__) || defined(__MINGW32__)
#include "nonposix.h"
#endif /* defined(__EMX__) || defined(__MINGW32__) */
@@ -206,11 +210,8 @@ typedef struct Regexp {
struct re_pattern_buffer pat;
struct re_registers regs;
struct dfa *dfareg;
- short dfa;
- short has_anchor; /* speed up of avoid_dfa kludge, temporary */
- short non_empty; /* for use in fpat_parse_field */
- short has_meta; /* re has meta chars so (probably) isn't simple string */
- short maybe_long; /* re has meta chars that can match long text */
+ bool has_meta; /* re has meta chars so (probably) isn't simple string */
+ bool maybe_long; /* re has meta chars that can match long text */
} Regexp;
#define RESTART(rp,s) (rp)->regs.start[0]
#define REEND(rp,s) (rp)->regs.end[0]
@@ -219,6 +220,7 @@ typedef struct Regexp {
#define NUMSUBPATS(rp,s) (rp)->regs.num_regs
/* regexp matching flags: */
+#define RE_NO_FLAGS 0 /* empty flags */
#define RE_NEED_START 1 /* need to know start/end of match */
#define RE_NO_BOL 2 /* not allowed to match ^ in regexp */
@@ -272,7 +274,6 @@ typedef enum nodevals {
Node_param_list, /* lnode is a variable, rnode is more list */
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 */
@@ -341,10 +342,9 @@ typedef struct exp_node {
} l;
union {
struct exp_node *rptr;
- Regexp *preg;
+ Regexp *preg[2];
struct exp_node **av;
BUCKET **bv;
- void *aq;
void (*uptr)(void);
struct exp_instruction *iptr;
} r;
@@ -352,16 +352,14 @@ typedef struct exp_node {
struct exp_node *extra;
void (*aptr)(void);
long xl;
- char **param_list;
} x;
char *name;
size_t reserved;
struct exp_node *rn;
unsigned long cnt;
unsigned long reflags;
-# define CASE 1
-# define CONSTANT 2
-# define FS_DFLT 4
+# define CONSTANT 1
+# define FS_DFLT 2
} nodep;
struct {
@@ -372,9 +370,7 @@ typedef struct exp_node {
mpz_t mpi;
} nm;
#else
- AWKNUM fltnum; /* this is here for optimal packing of
- * the structure on many machines
- */
+ AWKNUM fltnum;
#endif
char *sp;
size_t slen;
@@ -382,18 +378,19 @@ typedef struct exp_node {
int idx;
wchar_t *wsp;
size_t wslen;
+ struct exp_node *typre;
} val;
} sub;
NODETYPE type;
unsigned int flags;
-/* any type */
-# define MALLOC 0x0001 /* can be free'd */
-
/* type = Node_val */
/*
- * STRING and NUMBER are mutually exclusive. They represent the
- * type of a value as assigned.
+ * STRING and NUMBER are mutually exclusive, except for the special
+ * case of an uninitialized value, represented internally by
+ * Nnull_string. They represent the type of a value as assigned.
+ * Nnull_string has both STRING and NUMBER attributes, but all other
+ * scalar values should have precisely one of these bits set.
*
* STRCUR and NUMCUR are not mutually exclusive. They represent that
* the particular type of value is up to date. For example,
@@ -406,13 +403,16 @@ typedef struct exp_node {
* b = a + 0 # Adds NUMCUR to a, since numeric value
* # is now available. But the type hasn't changed!
*
- * MAYBE_NUM is the joker. It means "this is string data, but
- * the user may have really wanted it to be a number. If we have
- * to guess, like in a comparison, turn it into a number."
+ * USER_INPUT is the joker. When STRING|USER_INPUT is set, it means
+ * "this is string data, but the user may have really wanted it to be a
+ * number. If we have to guess, like in a comparison, turn it into a
+ * number if the string is indeed numeric."
* For example, gawk -v a=42 ....
- * Here, `a' gets STRING|STRCUR|MAYBE_NUM and then when used where
+ * Here, `a' gets STRING|STRCUR|USER_INPUT and then when used where
* a number is needed, it gets turned into a NUMBER and STRING
- * is cleared.
+ * is cleared. In that case, we leave the USER_INPUT in place, so
+ * the combination NUMBER|USER_INPUT means it is a strnum a.k.a. a
+ * "numeric string".
*
* WSTRCUR is for efficiency. If in a multibyte locale, and we
* need to do something character based (substr, length, etc.)
@@ -430,35 +430,36 @@ typedef struct exp_node {
*
* We hope that the rest of the flags are self-explanatory. :-)
*/
+# define MALLOC 0x0001 /* stptr can be free'd, i.e. not a field node pointing into a shared buffer */
# define STRING 0x0002 /* assigned as string */
# define STRCUR 0x0004 /* string value is current */
# define NUMCUR 0x0008 /* numeric value is current */
# define NUMBER 0x0010 /* assigned as number */
-# define MAYBE_NUM 0x0020 /* user input: if NUMERIC then
+# define USER_INPUT 0x0020 /* user input: if NUMERIC then
* a NUMBER */
-# define FIELD 0x0040 /* this is a field */
-# define INTLSTR 0x0080 /* use localized version */
-# define NUMINT 0x0100 /* numeric value is an integer */
-# define INTIND 0x0200 /* integral value is array index;
+# define INTLSTR 0x0040 /* use localized version */
+# define NUMINT 0x0080 /* numeric value is an integer */
+# define INTIND 0x0100 /* integral value is array index;
* lazy conversion to string.
*/
-# define WSTRCUR 0x0400 /* wide str value is current */
-# define MPFN 0x0800 /* arbitrary-precision floating-point number */
-# define MPZN 0x1000 /* arbitrary-precision integer */
-# define NO_EXT_SET 0x2000 /* extension cannot set a value for this variable */
-# define NULL_FIELD 0x4000 /* this is the null field */
+# define WSTRCUR 0x0200 /* wide str value is current */
+# define MPFN 0x0400 /* arbitrary-precision floating-point number */
+# define MPZN 0x0800 /* arbitrary-precision integer */
+# define NO_EXT_SET 0x1000 /* extension cannot set a value for this variable */
+# define NULL_FIELD 0x2000 /* this is the null field */
/* type = Node_var_array */
-# define ARRAYMAXED 0x8000 /* array is at max size */
-# define HALFHAT 0x10000 /* half-capacity Hashed Array Tree;
+# define ARRAYMAXED 0x4000 /* array is at max size */
+# define HALFHAT 0x8000 /* half-capacity Hashed Array Tree;
* See cint_array.c */
-# define XARRAY 0x20000
+# define XARRAY 0x10000
+# define NUMCONSTSTR 0x20000 /* have string value for numeric constant */
+# define REGEX 0x40000 /* this is a typed regex */
} NODE;
#define vname sub.nodep.name
#define lnode sub.nodep.l.lptr
-#define nextp sub.nodep.l.lptr
#define rnode sub.nodep.r.rptr
/* Node_param_list */
@@ -480,6 +481,14 @@ typedef struct exp_node {
#define re_cnt flags
/* Node_val */
+/*
+ * Note that the string in stptr may not be NUL-terminated, but it is
+ * guaranteed to have at least one extra byte that may be temporarily set
+ * to '\0'. This is helpful when calling functions such as strtod that require
+ * a NUL-terminated argument. In particular, field values $n for n > 0 and
+ * n < NF will not have a NUL terminator, since they point into the $0 buffer.
+ * All other strings are NUL-terminated.
+ */
#define stptr sub.val.sp
#define stlen sub.val.slen
#define valref sub.val.sref
@@ -493,6 +502,17 @@ typedef struct exp_node {
#else
#define numbr sub.val.fltnum
#endif
+#define typed_re sub.val.typre
+
+/*
+ * If stfmt is set to STFMT_UNUSED, it means that the string representation
+ * stored in stptr is not a function of the value of CONVFMT or OFMT. That
+ * indicates that either the string value was explicitly assigned, or it
+ * was converted from a NUMBER that has an integer value. When stfmt is not
+ * set to STFMT_UNUSED, it is an offset into the fmt_list array of distinct
+ * CONVFMT and OFMT node pointers.
+ */
+#define STFMT_UNUSED -1
/* Node_arrayfor */
#define for_list sub.nodep.r.av
@@ -515,14 +535,13 @@ typedef struct exp_node {
/* Node_var_array: */
#define buckets sub.nodep.r.bv
#define nodes sub.nodep.r.av
-#define a_opaque sub.nodep.r.aq
#define array_funcs sub.nodep.l.lp
#define array_base sub.nodep.l.ll
#define table_size sub.nodep.reflags
#define array_size sub.nodep.cnt
#define array_capacity sub.nodep.reserved
#define xarray sub.nodep.rn
-#define parent_array sub.nodep.x.extra
+#define parent_array sub.nodep.x.extra
#define ainit array_funcs[0]
#define ainit_ind 0
@@ -556,6 +575,11 @@ typedef struct exp_node {
#define adepth sub.nodep.l.ll
#define alevel sub.nodep.x.xl
+/* Op_comment */
+#define comment_type sub.val.idx
+#define EOL_COMMENT 1
+#define FULL_COMMENT 2
+
/* --------------------------------lint warning types----------------------------*/
typedef enum lintvals {
LINT_illegal,
@@ -566,8 +590,7 @@ typedef enum lintvals {
/* --------------------------------Instruction ---------------------------------- */
typedef enum opcodeval {
- /* illegal entry == 0 */
- Op_illegal,
+ Op_illegal = 0, /* illegal entry */
/* binary operators */
Op_times,
@@ -597,6 +620,7 @@ typedef enum opcodeval {
Op_postincrement,
Op_postdecrement,
Op_unary_minus,
+ Op_unary_plus,
Op_field_spec,
/* unary relationals */
@@ -633,7 +657,7 @@ typedef enum opcodeval {
Op_nomatch,
Op_rule,
-
+
/* keywords */
Op_K_case,
Op_K_default,
@@ -654,7 +678,6 @@ typedef enum opcodeval {
Op_builtin,
Op_sub_builtin, /* sub, gsub and gensub */
Op_ext_builtin,
- Op_old_ext_builtin, /* temporary */
Op_in_array, /* boolean test of membership in array */
/* function call instruction */
@@ -663,6 +686,7 @@ typedef enum opcodeval {
Op_push, /* scalar variable */
Op_push_arg, /* variable type (scalar or array) argument to built-in */
+ Op_push_arg_untyped, /* like Op_push_arg, but for typeof */
Op_push_i, /* number, string */
Op_push_re, /* regex */
Op_push_array,
@@ -690,6 +714,7 @@ typedef enum opcodeval {
Op_func,
+ Op_comment, /* for pretty printing */
Op_exec_count,
Op_breakpoint,
Op_lint,
@@ -697,13 +722,13 @@ typedef enum opcodeval {
Op_stop,
/* parsing (yylex and yyparse), should never appear in valid compiled code */
- Op_token,
+ Op_token,
Op_symbol,
Op_list,
/* program structures -- for use in the profiler/pretty printer */
Op_K_do,
- Op_K_for,
+ Op_K_for,
Op_K_arrayfor,
Op_K_while,
Op_K_switch,
@@ -711,6 +736,7 @@ typedef enum opcodeval {
Op_K_else,
Op_K_function,
Op_cond_exp,
+ Op_parens,
Op_final /* sentry value, not legal */
} OPCODE;
@@ -733,7 +759,9 @@ typedef struct exp_instruction {
NODE *dn;
struct exp_instruction *di;
NODE *(*fptr)(int);
- awk_value_t *(*efptr)(int, awk_value_t *);
+ awk_value_t *(*efptr)(int num_actual_args,
+ awk_value_t *result,
+ struct awk_ext_func *finfo);
long dl;
char *name;
} d;
@@ -744,9 +772,11 @@ typedef struct exp_instruction {
void (*aptr)(void);
struct exp_instruction *xi;
struct break_point *bpt;
+ awk_ext_func_t *exf;
} x;
short source_line;
+ short pool_size; // memory management in symbol.c
OPCODE opcode;
} INSTRUCTION;
@@ -759,6 +789,8 @@ typedef struct exp_instruction {
#define expr_count x.xl
+#define c_func x.exf
+
#define target_continue d.di
#define target_jmp d.di
#define target_break x.xi
@@ -772,7 +804,7 @@ typedef struct exp_instruction {
/* Op_K_exit */
#define target_end d.di
-#define target_atexit x.xi
+#define target_atexit x.xi
/* Op_newfile, Op_K_getline, Op_nextfile */
#define target_endfile x.xi
@@ -861,7 +893,7 @@ typedef struct exp_instruction {
#define field_assign x.aptr
/* Op_field_assign, Op_var_assign */
-#define assign_ctxt d.dl
+#define assign_ctxt d.dl
/* Op_concat */
#define concat_flag d.dl
@@ -894,7 +926,7 @@ typedef struct exp_instruction {
/* Op_line_range */
#define condpair_left d.di
-#define condpair_right x.xi
+#define condpair_right x.xi
/* Op_store_var */
#define initval x.xn
@@ -984,7 +1016,7 @@ typedef struct srcfile {
int fd;
int maxlen; /* size of the longest line */
- void (*fini_func)(); /* dynamic extension of type SRC_EXTLIB */
+ void (*fini_func)(); /* dynamic extension of type SRC_EXTLIB */
char *lexptr;
char *lexend;
@@ -993,9 +1025,19 @@ typedef struct srcfile {
int lasttok;
} SRCFILE;
+// structure for INSTRUCTION pool, needed mainly for debugger
+typedef struct instruction_pool {
+#define MAX_INSTRUCTION_ALLOC 3 // we don't call bcalloc with more than this
+ struct instruction_mem_pool {
+ struct instruction_block *block_list;
+ INSTRUCTION *free_space; // free location in active block
+ INSTRUCTION *free_list;
+ } pool[MAX_INSTRUCTION_ALLOC];
+} INSTRUCTION_POOL;
+
/* structure for execution context */
typedef struct context {
- INSTRUCTION pools;
+ INSTRUCTION_POOL pools;
NODE symbols;
INSTRUCTION rule_list;
SRCFILE srcfiles;
@@ -1012,17 +1054,20 @@ struct flagtab {
};
-typedef struct block_item {
- size_t size;
+struct block_item {
struct block_item *freep;
-} BLOCK;
+};
+
+struct block_header {
+ struct block_item *freep;
+ size_t size;
+};
enum block_id {
- BLOCK_INVALID = 0, /* not legal */
- BLOCK_NODE,
+ BLOCK_NODE = 0,
BLOCK_BUCKET,
BLOCK_MAX /* count */
-};
+};
typedef int (*Func_pre_exec)(INSTRUCTION **);
typedef void (*Func_post_exec)(INSTRUCTION *);
@@ -1036,7 +1081,7 @@ typedef void (*Func_post_exec)(INSTRUCTION *);
#ifndef LONG_MIN
#define LONG_MIN ((long)(-LONG_MAX - 1L))
#endif
-#define UNLIMITED LONG_MAX
+#define UNLIMITED LONG_MAX
/* -------------------------- External variables -------------------------- */
/* gawk builtin variables */
@@ -1044,7 +1089,7 @@ extern long NF;
extern long NR;
extern long FNR;
extern int BINMODE;
-extern int IGNORECASE;
+extern bool IGNORECASE;
extern bool RS_is_null;
extern char *OFS;
extern int OFSlen;
@@ -1080,7 +1125,7 @@ extern afunc_t int_array_func[];
/* special node used to indicate success in array routines (not NULL) */
extern NODE *success_node;
-extern BLOCK nextfree[];
+extern struct block_header nextfree[];
extern bool field0_valid;
extern int do_flags;
@@ -1181,7 +1226,7 @@ extern STACK_ITEM *stack_top;
#define POP_ADDRESS() (decr_sp()->lptr)
#define PEEK(n) ((stack_ptr - (n))->rptr)
#define TOP() (stack_ptr->rptr) /* same as PEEK(0) */
-#define TOP_ADDRESS() (stack_ptr->lptr)
+#define TOP_ADDRESS() (stack_ptr->lptr)
#define PUSH(r) (void) (incr_sp()->rptr = (r))
#define PUSH_ADDRESS(l) (void) (incr_sp()->lptr = (l))
#define REPLACE(r) (void) (stack_ptr->rptr = (r))
@@ -1203,6 +1248,7 @@ extern void r_unref(NODE *tmp);
static inline void
DEREF(NODE *r)
{
+ assert(r->valref > 0);
if (--r->valref == 0)
r_unref(r);
}
@@ -1212,23 +1258,34 @@ DEREF(NODE *r)
/* ------------------------- Pseudo-functions ------------------------- */
#ifdef HAVE_MPFR
+
+#if 0
+
+/*
+ * In principle, there is no need to have both the MPFN and MPZN flags,
+ * since we are using 2 bits to encode 1 bit of information. But
+ * there may be some minor performance advantages from testing only the
+ * node flag bits without needing also to access the global do_mpfr flag bit.
+ */
+#define numtype_choose(n, mpfrval, mpzval, dblval) \
+ (!do_mpfr ? (dblval) : (((n)->flags & MPFN) ? (mpfrval) : (mpzval)))
+
+#endif
+
+/* N.B. This implementation seems to give the fastest results. */
+#define numtype_choose(n, mpfrval, mpzval, dblval) \
+ (!((n)->flags & (MPFN|MPZN)) ? (dblval) : (((n)->flags & MPFN) ? (mpfrval) : (mpzval)))
+
/* conversion to C types */
-#define get_number_ui(n) (((n)->flags & MPFN) ? mpfr_get_ui((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? mpz_get_ui((n)->mpg_i) \
- : (unsigned long) (n)->numbr)
-#define get_number_si(n) (((n)->flags & MPFN) ? mpfr_get_si((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? mpz_get_si((n)->mpg_i) \
- : (long) (n)->numbr)
-#define get_number_d(n) (((n)->flags & MPFN) ? mpfr_get_d((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? mpz_get_d((n)->mpg_i) \
- : (double) (n)->numbr)
-#define get_number_uj(n) (((n)->flags & MPFN) ? mpfr_get_uj((n)->mpg_numbr, ROUND_MODE) \
- : ((n)->flags & MPZN) ? (uintmax_t) mpz_get_d((n)->mpg_i) \
- : (uintmax_t) (n)->numbr)
-
-#define iszero(n) (((n)->flags & MPFN) ? mpfr_zero_p((n)->mpg_numbr) \
- : ((n)->flags & MPZN) ? (mpz_sgn((n)->mpg_i) == 0) \
- : ((n)->numbr == 0.0))
+#define get_number_ui(n) numtype_choose((n), mpfr_get_ui((n)->mpg_numbr, ROUND_MODE), mpz_get_ui((n)->mpg_i), (unsigned long) (n)->numbr)
+
+#define get_number_si(n) numtype_choose((n), mpfr_get_si((n)->mpg_numbr, ROUND_MODE), mpz_get_si((n)->mpg_i), (long) (n)->numbr)
+
+#define get_number_d(n) numtype_choose((n), mpfr_get_d((n)->mpg_numbr, ROUND_MODE), mpz_get_d((n)->mpg_i), (double) (n)->numbr)
+
+#define get_number_uj(n) numtype_choose((n), mpfr_get_uj((n)->mpg_numbr, ROUND_MODE), (uintmax_t) mpz_get_d((n)->mpg_i), (uintmax_t) (n)->numbr)
+
+#define iszero(n) numtype_choose((n), mpfr_zero_p((n)->mpg_numbr), (mpz_sgn((n)->mpg_i) == 0), ((n)->numbr == 0.0))
#define IEEE_FMT(r, t) (void) (do_ieee_fmt && format_ieee(r, t))
@@ -1255,10 +1312,10 @@ DEREF(NODE *r)
&((n)->var_value) : r_get_lhs((n), (r))
#define getblock(p, id, ty) (void) ((p = (ty) nextfree[id].freep) ? \
- (ty) (nextfree[id].freep = ((BLOCK *) p)->freep) \
+ (ty) (nextfree[id].freep = ((struct block_item *) p)->freep) \
: (p = (ty) more_blocks(id)))
-#define freeblock(p, id) (void) (((BLOCK *) p)->freep = nextfree[id].freep, \
- nextfree[id].freep = (BLOCK *) p)
+#define freeblock(p, id) (void) (((struct block_item *) p)->freep = nextfree[id].freep, \
+ nextfree[id].freep = (struct block_item *) p)
#define getnode(n) getblock(n, BLOCK_NODE, NODE *)
#define freenode(n) freeblock(n, BLOCK_NODE)
@@ -1275,6 +1332,7 @@ DEREF(NODE *r)
__LINE__, __FILE__)
#define emalloc(var,ty,x,str) (void) (var = (ty) emalloc_real((size_t)(x), str, #var, __FILE__, __LINE__))
+#define ezalloc(var,ty,x,str) (void) (var = (ty) ezalloc_real((size_t)(x), str, #var, __FILE__, __LINE__))
#define erealloc(var,ty,x,str) (void) (var = (ty) erealloc_real((void *) var, (size_t)(x), str, #var, __FILE__, __LINE__))
#define efree(p) free(p)
@@ -1306,7 +1364,7 @@ if (--val) \
typedef enum { SORTED_IN = 1, ASORT, ASORTI } sort_context_t;
typedef enum {
ANONE = 0x00, /* "unused" value */
- AINDEX = 0x001, /* list of indices */
+ AINDEX = 0x001, /* list of indices */
AVALUE = 0x002, /* list of values */
AINUM = 0x004, /* numeric index */
AISTR = 0x008, /* string index */
@@ -1339,6 +1397,7 @@ extern NODE *do_aoption(int nargs);
extern NODE *do_asort(int nargs);
extern NODE *do_asorti(int nargs);
extern unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t *code);
+extern void init_env_array(NODE *env_node);
/* awkgram.c */
extern NODE *variable(int location, char *name, NODETYPE type);
extern int parse_program(INSTRUCTION **pcode);
@@ -1401,17 +1460,20 @@ extern NODE *do_or(int nargs);
extern NODE *do_xor(int nargs);
extern NODE *do_compl(int nargs);
extern NODE *do_strtonum(int nargs);
-extern AWKNUM nondec2awknum(char *str, size_t len);
+extern AWKNUM nondec2awknum(char *str, size_t len, char **endptr);
extern NODE *do_dcgettext(int nargs);
extern NODE *do_dcngettext(int nargs);
extern NODE *do_bindtextdomain(int nargs);
+extern NODE *do_intdiv(int nargs);
+extern NODE *do_typeof(int nargs);
extern int strncasecmpmbs(const unsigned char *,
const unsigned char *, size_t);
+extern int sanitize_exit_status(int status);
/* eval.c */
extern void PUSH_CODE(INSTRUCTION *cp);
extern INSTRUCTION *POP_CODE(void);
extern void init_interpret(void);
-extern int cmp_nodes(NODE *t1, NODE *t2);
+extern int cmp_nodes(NODE *t1, NODE *t2, bool use_strcmp);
extern int cmp_awknums(const NODE *t1, const NODE *t2);
extern void set_IGNORECASE(void);
extern void set_OFS(void);
@@ -1443,10 +1505,8 @@ extern NODE **r_get_field(NODE *n, Func_ptr *assign, bool reference);
/* ext.c */
extern NODE *do_ext(int nargs);
void load_ext(const char *lib_name); /* temporary */
-extern NODE *load_old_ext(SRCFILE *s, const char *init_func, const char *fini_func, NODE *obj);
extern void close_extensions(void);
#ifdef DYNAMIC
-extern void make_old_builtin(const char *, NODE *(*)(int), int);
extern awk_bool_t make_builtin(const awk_ext_func_t *);
extern NODE *get_argument(int);
extern NODE *get_actual_argument(NODE *, int, bool);
@@ -1455,7 +1515,7 @@ extern NODE *get_actual_argument(NODE *, int, bool);
#endif
/* field.c */
extern void init_fields(void);
-extern void set_record(const char *buf, int cnt);
+extern void set_record(const char *buf, int cnt, const awk_fieldwidth_info_t *);
extern void reset_record(void);
extern void rebuild_record(void);
extern void set_NF(void);
@@ -1472,9 +1532,11 @@ extern void update_PROCINFO_num(const char *subscript, AWKNUM val);
typedef enum {
Using_FS,
Using_FIELDWIDTHS,
- Using_FPAT
+ Using_FPAT,
+ Using_API
} field_sep_type;
extern field_sep_type current_field_sep(void);
+extern const char *current_field_sep_str(void);
/* gawkapi.c: */
extern gawk_api_t api_impl;
@@ -1483,6 +1545,7 @@ extern void update_ext_api(void);
extern NODE *awk_value_to_node(const awk_value_t *);
extern void run_ext_exit_handlers(int exitval);
extern void print_ext_versions(void);
+extern void free_api_string_copies(void);
/* gawkmisc.c */
extern char *gawk_name(const char *filespec);
@@ -1508,7 +1571,10 @@ extern void register_two_way_processor(awk_two_way_processor_t *processor);
extern void set_FNR(void);
extern void set_NR(void);
-extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg);
+extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal);
+extern struct redirect *redirect_string(const char *redir_exp_str,
+ size_t redir_exp_len, bool not_string_flag, int redirtype,
+ int *errflg, int extfd, bool failure_fatal);
extern NODE *do_close(int nargs);
extern int flush_io(void);
extern int close_io(bool *stdio_problem);
@@ -1523,6 +1589,12 @@ extern NODE *do_getline(int intovar, IOBUF *iop);
extern struct redirect *getredirect(const char *str, int len);
extern bool inrec(IOBUF *iop, int *errcode);
extern int nextfile(IOBUF **curfile, bool skipping);
+extern bool is_non_fatal_std(FILE *fp);
+extern bool is_non_fatal_redirect(const char *str, size_t len);
+extern void ignore_sigpipe(void);
+extern void set_sigpipe_to_default(void);
+extern bool non_fatal_flush_std_file(FILE *fp);
+
/* main.c */
extern int arg_assign(char *arg, bool initing);
extern int is_std_var(const char *var);
@@ -1530,6 +1602,7 @@ extern int is_off_limits_var(const char *var);
extern char *estrdup(const char *str, size_t len);
extern void update_global_values();
extern long getenv_long(const char *name);
+extern void after_beginfile(IOBUF **curfile);
/* mpfr.c */
extern void set_PREC(void);
@@ -1546,6 +1619,7 @@ extern NODE *do_mpfr_compl(int);
extern NODE *do_mpfr_cos(int);
extern NODE *do_mpfr_exp(int);
extern NODE *do_mpfr_int(int);
+extern NODE *do_mpfr_intdiv(int);
extern NODE *do_mpfr_log(int);
extern NODE *do_mpfr_lshift(int);
extern NODE *do_mpfr_or(int);
@@ -1591,6 +1665,7 @@ extern NODE *r_force_number(NODE *n);
extern NODE *r_format_val(const char *format, int index, NODE *s);
extern NODE *r_dupnode(NODE *n);
extern NODE *make_str_node(const char *s, size_t len, int flags);
+extern NODE *make_typed_regex(const char *re, size_t len);
extern void *more_blocks(int id);
extern int parse_escape(const char **string_ptr);
extern NODE *str2wstr(NODE *n, size_t **ptr);
@@ -1614,9 +1689,9 @@ extern void reg_error(const char *s);
extern Regexp *re_update(NODE *t);
extern void resyntax(int syntax);
extern void resetup(void);
-extern int avoid_dfa(NODE *re, char *str, size_t len);
extern int reisstring(const char *text, size_t len, Regexp *re, const char *buf);
-extern int get_numbase(const char *str, bool use_locale);
+extern int get_numbase(const char *str, size_t len, bool use_locale);
+extern bool using_utf8(void);
/* symbol.c */
extern void load_symbols();
@@ -1720,7 +1795,7 @@ POP_SCALAR()
if (t->type == Node_var_array)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t));
-
+
return t;
}
@@ -1733,7 +1808,7 @@ TOP_SCALAR()
if (t->type == Node_var_array)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t));
-
+
return t;
}
@@ -1751,7 +1826,7 @@ in_array(NODE *a, NODE *s)
NODE **ret;
ret = a->aexists(a, s);
-
+
return ret ? *ret : NULL;
}
@@ -1771,18 +1846,30 @@ dupnode(NODE *n)
}
#endif
-/* force_string --- force a node to have a string value */
+/*
+ * force_string_fmt --- force a node to have a string value in a given format.
+ * The string representation of a number may change due to whether it was most
+ * recently rendered with CONVFMT or OFMT, or due to changes in the CONVFMT
+ * and OFMT values. But if the value entered gawk as a string or strnum, then
+ * stfmt should be set to STFMT_UNUSED, and the string representation should
+ * not change.
+ */
static inline NODE *
-force_string(NODE *s)
+force_string_fmt(NODE *s, const char *fmtstr, int fmtidx)
{
if ((s->flags & STRCUR) != 0
- && (s->stfmt == -1 || s->stfmt == CONVFMTidx)
+ && (s->stfmt == STFMT_UNUSED || s->stfmt == fmtidx)
)
return s;
- return format_val(CONVFMT, CONVFMTidx, s);
+ return format_val(fmtstr, fmtidx, s);
}
+/* conceptually should be force_string_convfmt, but this is the typical case */
+#define force_string(s) force_string_fmt((s), CONVFMT, CONVFMTidx)
+
+#define force_string_ofmt(s) force_string_fmt((s), OFMT, OFMTidx)
+
#ifdef GAWKDEBUG
#define unref r_unref
#define force_number str2number
@@ -1807,6 +1894,46 @@ force_number(NODE *n)
#endif /* GAWKDEBUG */
+
+/* fixtype --- make a node decide if it's a number or a string */
+
+/*
+ * In certain contexts, the true type of a scalar value matters, and we
+ * must ascertain whether it is a NUMBER or a STRING. In such situations,
+ * please use this function to resolve the type.
+ *
+ * It is safe to assume that the return value will be the same NODE,
+ * since force_number on a USER_INPUT should always return the same NODE,
+ * and force_string on an INTIND should as well.
+ */
+
+static inline NODE *
+fixtype(NODE *n)
+{
+ assert(n->type == Node_val);
+ if ((n->flags & (NUMCUR|USER_INPUT)) == USER_INPUT)
+ return force_number(n);
+ if ((n->flags & INTIND) != 0)
+ return force_string(n);
+ return n;
+}
+
+/* boolval --- return true/false based on awk's criteria */
+
+/*
+ * In awk, a value is considered to be true if it is nonzero _or_
+ * non-null. Otherwise, the value is false.
+ */
+
+static inline bool
+boolval(NODE *t)
+{
+ (void) fixtype(t);
+ if ((t->flags & NUMBER) != 0)
+ return ! iszero(t);
+ return (t->stlen > 0);
+}
+
/* emalloc_real --- malloc with error checking */
static inline void *
@@ -1825,6 +1952,24 @@ emalloc_real(size_t count, const char *where, const char *var, const char *file,
return ret;
}
+/* ezalloc_real --- malloc zero-filled bytes with error checking */
+
+static inline void *
+ezalloc_real(size_t count, const char *where, const char *var, const char *file, int line)
+{
+ void *ret;
+
+ if (count == 0)
+ fatal("%s:%d: ezalloc called with zero bytes", file, line);
+
+ ret = (void *) calloc(1, count);
+ if (ret == NULL)
+ fatal(_("%s:%d:%s: %s: can't allocate %ld bytes of memory (%s)"),
+ file, line, where, var, (long) count, strerror(errno));
+
+ return ret;
+}
+
/* erealloc_real --- realloc with error checking */
static inline void *
@@ -1842,3 +1987,35 @@ erealloc_real(void *ptr, size_t count, const char *where, const char *var, const
return ret;
}
+
+
+/*
+ * str_terminate_f, str_terminate, str_restore: function and macros to
+ * reduce chances of typos when terminating and restoring strings.
+ * This also helps to enforce that the NODE must be in scope when we restore.
+ */
+
+static inline void
+str_terminate_f(NODE *n, char *savep)
+{
+ *savep = n->stptr[n->stlen];
+ n->stptr[n->stlen] = '\0';
+}
+
+#define str_terminate(n, save) str_terminate_f((n), &save)
+#define str_restore(n, save) (n)->stptr[(n)->stlen] = save
+
+#ifdef SIGPIPE
+#define ignore_sigpipe() signal(SIGPIPE, SIG_IGN)
+#define set_sigpipe_to_default() signal(SIGPIPE, SIG_DFL)
+#define die_via_sigpipe() (signal(SIGPIPE, SIG_DFL), kill(getpid(), SIGPIPE))
+#else
+#define ignore_sigpipe()
+#define set_sigpipe_to_default()
+#ifdef __MINGW32__
+/* 0xC0000008 is EXCEPTION_INVALID_HANDLE, somewhat appropriate for EPIPE */
+#define die_via_sigpipe() exit(0xC0000008)
+#else /* !__MINGW32__ */
+#define die_via_sigpipe() exit(EXIT_FATAL)
+#endif /* !__MINGW32__ */
+#endif
diff --git a/awkgram.c b/awkgram.c
index 7191c1e7..82ac3589 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -80,7 +80,7 @@ static void lintwarn_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
static void warning_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
static char *get_src_buf(void);
static int yylex(void);
-int yyparse(void);
+int yyparse(void);
static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
static char **check_params(char *fname, int pcount, INSTRUCTION *list);
static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist);
@@ -97,6 +97,7 @@ static int include_source(INSTRUCTION *file);
static int load_library(INSTRUCTION *file);
static void next_sourcefile(void);
static char *tokexpand(void);
+static NODE *set_profile_text(NODE *n, const char *str, size_t len);
#define instruction(t) bcalloc(t, 1, 0)
@@ -123,10 +124,18 @@ static void check_funcs(void);
static ssize_t read_one_line(int fd, void *buffer, size_t count);
static int one_line_close(int fd);
+static void split_comment(void);
+static void check_comment(void);
+static void add_sign_to_num(NODE *n, char sign);
static bool at_seen = false;
static bool want_source = false;
static bool want_regexp = false; /* lexical scanning kludge */
+static enum {
+ FUNC_HEADER,
+ FUNC_BODY,
+ DONT_CHECK
+} want_param_names = DONT_CHECK; /* ditto */
static char *in_function; /* parsing kludge */
static int rule = 0;
@@ -146,7 +155,7 @@ static char *lexptr; /* pointer to next char during parsing */
static char *lexend; /* end of buffer */
static char *lexptr_begin; /* keep track of where we were for error msgs */
static char *lexeme; /* beginning of lexeme for debugging */
-static bool lexeof; /* seen EOF for current source? */
+static bool lexeof; /* seen EOF for current source? */
static char *thisline = NULL;
static int in_braces = 0; /* count braces for firstline, lastline in an 'action' */
static int lastline = 0;
@@ -181,17 +190,29 @@ static INSTRUCTION *ip_atexit = NULL;
static INSTRUCTION *ip_end;
static INSTRUCTION *ip_endfile;
static INSTRUCTION *ip_beginfile;
+INSTRUCTION *main_beginfile;
+
+static INSTRUCTION *comment = NULL;
+static INSTRUCTION *prior_comment = NULL;
+static INSTRUCTION *comment_to_save = NULL;
+static INSTRUCTION *program_comment = NULL;
+static INSTRUCTION *function_comment = NULL;
+static INSTRUCTION *block_comment = NULL;
+
+static bool func_first = true;
+static bool first_rule = true;
static inline INSTRUCTION *list_create(INSTRUCTION *x);
static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x);
static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x);
static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2);
+static inline INSTRUCTION *add_pending_comment(INSTRUCTION *stmt);
extern double fmod(double x, double y);
#define YYSTYPE INSTRUCTION *
-#line 195 "awkgram.c" /* yacc.c:339 */
+#line 216 "awkgram.c" /* yacc.c:339 */
# ifndef YY_NULLPTR
# if defined __cplusplus && 201103L <= __cplusplus
@@ -229,51 +250,52 @@ extern int yydebug;
FILENAME = 261,
YNUMBER = 262,
YSTRING = 263,
- RELOP = 264,
- IO_OUT = 265,
- IO_IN = 266,
- ASSIGNOP = 267,
- ASSIGN = 268,
- MATCHOP = 269,
- CONCAT_OP = 270,
- SUBSCRIPT = 271,
- LEX_BEGIN = 272,
- LEX_END = 273,
- LEX_IF = 274,
- LEX_ELSE = 275,
- LEX_RETURN = 276,
- LEX_DELETE = 277,
- LEX_SWITCH = 278,
- LEX_CASE = 279,
- LEX_DEFAULT = 280,
- LEX_WHILE = 281,
- LEX_DO = 282,
- LEX_FOR = 283,
- LEX_BREAK = 284,
- LEX_CONTINUE = 285,
- LEX_PRINT = 286,
- LEX_PRINTF = 287,
- LEX_NEXT = 288,
- LEX_EXIT = 289,
- LEX_FUNCTION = 290,
- LEX_BEGINFILE = 291,
- LEX_ENDFILE = 292,
- LEX_GETLINE = 293,
- LEX_NEXTFILE = 294,
- LEX_IN = 295,
- LEX_AND = 296,
- LEX_OR = 297,
- INCREMENT = 298,
- DECREMENT = 299,
- LEX_BUILTIN = 300,
- LEX_LENGTH = 301,
- LEX_EOF = 302,
- LEX_INCLUDE = 303,
- LEX_EVAL = 304,
- LEX_LOAD = 305,
- NEWLINE = 306,
- SLASH_BEFORE_EQUAL = 307,
- UNARY = 308
+ TYPED_REGEXP = 264,
+ RELOP = 265,
+ IO_OUT = 266,
+ IO_IN = 267,
+ ASSIGNOP = 268,
+ ASSIGN = 269,
+ MATCHOP = 270,
+ CONCAT_OP = 271,
+ SUBSCRIPT = 272,
+ LEX_BEGIN = 273,
+ LEX_END = 274,
+ LEX_IF = 275,
+ LEX_ELSE = 276,
+ LEX_RETURN = 277,
+ LEX_DELETE = 278,
+ LEX_SWITCH = 279,
+ LEX_CASE = 280,
+ LEX_DEFAULT = 281,
+ LEX_WHILE = 282,
+ LEX_DO = 283,
+ LEX_FOR = 284,
+ LEX_BREAK = 285,
+ LEX_CONTINUE = 286,
+ LEX_PRINT = 287,
+ LEX_PRINTF = 288,
+ LEX_NEXT = 289,
+ LEX_EXIT = 290,
+ LEX_FUNCTION = 291,
+ LEX_BEGINFILE = 292,
+ LEX_ENDFILE = 293,
+ LEX_GETLINE = 294,
+ LEX_NEXTFILE = 295,
+ LEX_IN = 296,
+ LEX_AND = 297,
+ LEX_OR = 298,
+ INCREMENT = 299,
+ DECREMENT = 300,
+ LEX_BUILTIN = 301,
+ LEX_LENGTH = 302,
+ LEX_EOF = 303,
+ LEX_INCLUDE = 304,
+ LEX_EVAL = 305,
+ LEX_LOAD = 306,
+ NEWLINE = 307,
+ SLASH_BEFORE_EQUAL = 308,
+ UNARY = 309
};
#endif
/* Tokens. */
@@ -283,51 +305,52 @@ extern int yydebug;
#define FILENAME 261
#define YNUMBER 262
#define YSTRING 263
-#define RELOP 264
-#define IO_OUT 265
-#define IO_IN 266
-#define ASSIGNOP 267
-#define ASSIGN 268
-#define MATCHOP 269
-#define CONCAT_OP 270
-#define SUBSCRIPT 271
-#define LEX_BEGIN 272
-#define LEX_END 273
-#define LEX_IF 274
-#define LEX_ELSE 275
-#define LEX_RETURN 276
-#define LEX_DELETE 277
-#define LEX_SWITCH 278
-#define LEX_CASE 279
-#define LEX_DEFAULT 280
-#define LEX_WHILE 281
-#define LEX_DO 282
-#define LEX_FOR 283
-#define LEX_BREAK 284
-#define LEX_CONTINUE 285
-#define LEX_PRINT 286
-#define LEX_PRINTF 287
-#define LEX_NEXT 288
-#define LEX_EXIT 289
-#define LEX_FUNCTION 290
-#define LEX_BEGINFILE 291
-#define LEX_ENDFILE 292
-#define LEX_GETLINE 293
-#define LEX_NEXTFILE 294
-#define LEX_IN 295
-#define LEX_AND 296
-#define LEX_OR 297
-#define INCREMENT 298
-#define DECREMENT 299
-#define LEX_BUILTIN 300
-#define LEX_LENGTH 301
-#define LEX_EOF 302
-#define LEX_INCLUDE 303
-#define LEX_EVAL 304
-#define LEX_LOAD 305
-#define NEWLINE 306
-#define SLASH_BEFORE_EQUAL 307
-#define UNARY 308
+#define TYPED_REGEXP 264
+#define RELOP 265
+#define IO_OUT 266
+#define IO_IN 267
+#define ASSIGNOP 268
+#define ASSIGN 269
+#define MATCHOP 270
+#define CONCAT_OP 271
+#define SUBSCRIPT 272
+#define LEX_BEGIN 273
+#define LEX_END 274
+#define LEX_IF 275
+#define LEX_ELSE 276
+#define LEX_RETURN 277
+#define LEX_DELETE 278
+#define LEX_SWITCH 279
+#define LEX_CASE 280
+#define LEX_DEFAULT 281
+#define LEX_WHILE 282
+#define LEX_DO 283
+#define LEX_FOR 284
+#define LEX_BREAK 285
+#define LEX_CONTINUE 286
+#define LEX_PRINT 287
+#define LEX_PRINTF 288
+#define LEX_NEXT 289
+#define LEX_EXIT 290
+#define LEX_FUNCTION 291
+#define LEX_BEGINFILE 292
+#define LEX_ENDFILE 293
+#define LEX_GETLINE 294
+#define LEX_NEXTFILE 295
+#define LEX_IN 296
+#define LEX_AND 297
+#define LEX_OR 298
+#define INCREMENT 299
+#define DECREMENT 300
+#define LEX_BUILTIN 301
+#define LEX_LENGTH 302
+#define LEX_EOF 303
+#define LEX_INCLUDE 304
+#define LEX_EVAL 305
+#define LEX_LOAD 306
+#define NEWLINE 307
+#define SLASH_BEFORE_EQUAL 308
+#define UNARY 309
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@@ -345,7 +368,7 @@ int yyparse (void);
/* Copy the second part of user declarations. */
-#line 349 "awkgram.c" /* yacc.c:358 */
+#line 372 "awkgram.c" /* yacc.c:358 */
#ifdef short
# undef short
@@ -587,21 +610,21 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 1155
+#define YYLAST 1236
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 75
+#define YYNTOKENS 76
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 65
+#define YYNNTS 70
/* YYNRULES -- Number of rules. */
-#define YYNRULES 188
+#define YYNRULES 203
/* YYNSTATES -- Number of states. */
-#define YYNSTATES 335
+#define YYNSTATES 350
/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
by yylex, with out-of-bounds checking. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 308
+#define YYMAXUTOK 309
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -613,16 +636,16 @@ static const yytype_uint8 yytranslate[] =
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 63, 2, 2, 66, 62, 2, 2,
- 67, 68, 60, 58, 55, 59, 2, 61, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 54, 74,
- 56, 2, 57, 53, 69, 2, 2, 2, 2, 2,
+ 2, 2, 2, 64, 2, 2, 67, 63, 2, 2,
+ 68, 69, 61, 59, 56, 60, 2, 62, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 55, 75,
+ 57, 2, 58, 54, 70, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 70, 2, 71, 65, 2, 2, 2, 2, 2,
+ 2, 71, 2, 72, 66, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 72, 2, 73, 2, 2, 2, 2,
+ 2, 2, 2, 73, 2, 74, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -640,32 +663,34 @@ static const yytype_uint8 yytranslate[] =
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 64
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 65
};
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 194, 194, 196, 201, 202, 206, 218, 222, 233,
- 239, 245, 254, 262, 264, 269, 277, 279, 285, 286,
- 288, 314, 325, 336, 342, 351, 361, 363, 365, 371,
- 379, 380, 384, 403, 402, 436, 438, 443, 444, 457,
- 462, 463, 467, 469, 471, 478, 568, 610, 652, 765,
- 772, 779, 789, 798, 807, 816, 827, 843, 842, 866,
- 878, 878, 976, 976, 1009, 1039, 1045, 1046, 1052, 1053,
- 1060, 1065, 1077, 1091, 1093, 1101, 1106, 1108, 1116, 1118,
- 1127, 1128, 1136, 1141, 1141, 1152, 1156, 1164, 1165, 1168,
- 1170, 1175, 1176, 1185, 1186, 1191, 1196, 1205, 1207, 1209,
- 1216, 1217, 1223, 1224, 1229, 1231, 1236, 1238, 1246, 1251,
- 1260, 1267, 1269, 1271, 1287, 1297, 1304, 1306, 1311, 1313,
- 1315, 1323, 1325, 1330, 1332, 1337, 1339, 1341, 1391, 1393,
- 1395, 1397, 1399, 1401, 1403, 1405, 1419, 1424, 1429, 1454,
- 1460, 1462, 1464, 1466, 1468, 1470, 1475, 1479, 1511, 1513,
- 1519, 1525, 1538, 1539, 1540, 1545, 1550, 1554, 1558, 1573,
- 1586, 1591, 1628, 1657, 1658, 1664, 1665, 1670, 1672, 1679,
- 1696, 1713, 1715, 1722, 1727, 1735, 1745, 1757, 1766, 1770,
- 1774, 1778, 1782, 1786, 1789, 1791, 1795, 1799, 1803
+ 0, 215, 215, 217, 222, 223, 227, 239, 244, 255,
+ 262, 268, 277, 285, 287, 292, 300, 302, 308, 316,
+ 326, 356, 370, 384, 392, 403, 415, 417, 419, 425,
+ 433, 434, 438, 438, 484, 483, 517, 532, 534, 539,
+ 549, 596, 601, 602, 606, 608, 610, 617, 707, 749,
+ 791, 904, 911, 918, 929, 939, 949, 959, 971, 988,
+ 987, 1012, 1024, 1024, 1123, 1123, 1157, 1188, 1197, 1198,
+ 1204, 1205, 1212, 1217, 1229, 1243, 1245, 1253, 1260, 1262,
+ 1270, 1279, 1281, 1290, 1291, 1299, 1304, 1304, 1315, 1319,
+ 1327, 1328, 1331, 1333, 1338, 1339, 1348, 1349, 1354, 1359,
+ 1368, 1370, 1372, 1379, 1380, 1386, 1387, 1392, 1394, 1399,
+ 1401, 1409, 1414, 1423, 1424, 1429, 1431, 1436, 1438, 1446,
+ 1451, 1459, 1460, 1465, 1472, 1476, 1478, 1480, 1493, 1510,
+ 1520, 1527, 1529, 1534, 1536, 1538, 1546, 1548, 1553, 1555,
+ 1560, 1562, 1564, 1620, 1622, 1624, 1626, 1628, 1630, 1632,
+ 1634, 1648, 1653, 1658, 1683, 1689, 1691, 1693, 1695, 1697,
+ 1699, 1704, 1708, 1740, 1747, 1753, 1759, 1772, 1773, 1774,
+ 1779, 1784, 1788, 1792, 1807, 1828, 1833, 1870, 1899, 1900,
+ 1906, 1907, 1912, 1914, 1921, 1938, 1955, 1957, 1964, 1969,
+ 1977, 1987, 1999, 2008, 2012, 2016, 2020, 2024, 2028, 2031,
+ 2033, 2037, 2041, 2045
};
#endif
@@ -675,30 +700,32 @@ static const yytype_uint16 yyrline[] =
static const char *const yytname[] =
{
"$end", "error", "$undefined", "FUNC_CALL", "NAME", "REGEXP",
- "FILENAME", "YNUMBER", "YSTRING", "RELOP", "IO_OUT", "IO_IN", "ASSIGNOP",
- "ASSIGN", "MATCHOP", "CONCAT_OP", "SUBSCRIPT", "LEX_BEGIN", "LEX_END",
- "LEX_IF", "LEX_ELSE", "LEX_RETURN", "LEX_DELETE", "LEX_SWITCH",
- "LEX_CASE", "LEX_DEFAULT", "LEX_WHILE", "LEX_DO", "LEX_FOR", "LEX_BREAK",
- "LEX_CONTINUE", "LEX_PRINT", "LEX_PRINTF", "LEX_NEXT", "LEX_EXIT",
- "LEX_FUNCTION", "LEX_BEGINFILE", "LEX_ENDFILE", "LEX_GETLINE",
- "LEX_NEXTFILE", "LEX_IN", "LEX_AND", "LEX_OR", "INCREMENT", "DECREMENT",
- "LEX_BUILTIN", "LEX_LENGTH", "LEX_EOF", "LEX_INCLUDE", "LEX_EVAL",
- "LEX_LOAD", "NEWLINE", "SLASH_BEFORE_EQUAL", "'?'", "':'", "','", "'<'",
- "'>'", "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "UNARY", "'^'", "'$'",
- "'('", "')'", "'@'", "'['", "']'", "'{'", "'}'", "';'", "$accept",
- "program", "rule", "source", "library", "pattern", "action", "func_name",
- "lex_builtin", "function_prologue", "regexp", "$@1", "a_slash",
- "statements", "statement_term", "statement", "non_compound_stmt", "$@2",
- "simple_stmt", "$@3", "$@4", "opt_simple_stmt", "case_statements",
- "case_statement", "case_value", "print", "print_expression_list",
- "output_redir", "$@5", "if_statement", "nls", "opt_nls", "input_redir",
- "opt_param_list", "param_list", "opt_exp", "opt_expression_list",
- "expression_list", "exp", "assign_operator", "relop_or_less", "a_relop",
- "common_exp", "simp_exp", "simp_exp_nc", "non_post_simp_exp",
- "func_call", "direct_func_call", "opt_variable", "delete_subscript_list",
- "delete_subscript", "delete_exp_list", "bracketed_exp_list", "subscript",
- "subscript_list", "simple_variable", "variable", "opt_incdec", "l_brace",
- "r_brace", "r_paren", "opt_semi", "semi", "colon", "comma", YY_NULLPTR
+ "FILENAME", "YNUMBER", "YSTRING", "TYPED_REGEXP", "RELOP", "IO_OUT",
+ "IO_IN", "ASSIGNOP", "ASSIGN", "MATCHOP", "CONCAT_OP", "SUBSCRIPT",
+ "LEX_BEGIN", "LEX_END", "LEX_IF", "LEX_ELSE", "LEX_RETURN", "LEX_DELETE",
+ "LEX_SWITCH", "LEX_CASE", "LEX_DEFAULT", "LEX_WHILE", "LEX_DO",
+ "LEX_FOR", "LEX_BREAK", "LEX_CONTINUE", "LEX_PRINT", "LEX_PRINTF",
+ "LEX_NEXT", "LEX_EXIT", "LEX_FUNCTION", "LEX_BEGINFILE", "LEX_ENDFILE",
+ "LEX_GETLINE", "LEX_NEXTFILE", "LEX_IN", "LEX_AND", "LEX_OR",
+ "INCREMENT", "DECREMENT", "LEX_BUILTIN", "LEX_LENGTH", "LEX_EOF",
+ "LEX_INCLUDE", "LEX_EVAL", "LEX_LOAD", "NEWLINE", "SLASH_BEFORE_EQUAL",
+ "'?'", "':'", "','", "'<'", "'>'", "'+'", "'-'", "'*'", "'/'", "'%'",
+ "'!'", "UNARY", "'^'", "'$'", "'('", "')'", "'@'", "'['", "']'", "'{'",
+ "'}'", "';'", "$accept", "program", "rule", "source", "library",
+ "pattern", "action", "func_name", "lex_builtin", "function_prologue",
+ "$@1", "regexp", "$@2", "typed_regexp", "a_slash", "statements",
+ "statement_term", "statement", "non_compound_stmt", "$@3", "simple_stmt",
+ "$@4", "$@5", "opt_simple_stmt", "case_statements", "case_statement",
+ "case_value", "print", "print_expression_list", "output_redir", "$@6",
+ "if_statement", "nls", "opt_nls", "input_redir", "opt_param_list",
+ "param_list", "opt_exp", "opt_expression_list", "expression_list",
+ "opt_fcall_expression_list", "fcall_expression_list", "fcall_exp", "exp",
+ "assign_operator", "relop_or_less", "a_relop", "common_exp", "simp_exp",
+ "simp_exp_nc", "non_post_simp_exp", "func_call", "direct_func_call",
+ "opt_variable", "delete_subscript_list", "delete_subscript",
+ "delete_exp_list", "bracketed_exp_list", "subscript", "subscript_list",
+ "simple_variable", "variable", "opt_incdec", "l_brace", "r_brace",
+ "r_paren", "opt_semi", "semi", "colon", "comma", YY_NULLPTR
};
#endif
@@ -712,60 +739,61 @@ static const yytype_uint16 yytoknum[] =
275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
- 305, 306, 307, 63, 58, 44, 60, 62, 43, 45,
- 42, 47, 37, 33, 308, 94, 36, 40, 41, 64,
- 91, 93, 123, 125, 59
+ 305, 306, 307, 308, 63, 58, 44, 60, 62, 43,
+ 45, 42, 47, 37, 33, 309, 94, 36, 40, 41,
+ 64, 91, 93, 123, 125, 59
};
# endif
-#define YYPACT_NINF -273
+#define YYPACT_NINF -275
#define yypact_value_is_default(Yystate) \
- (!!((Yystate) == (-273)))
+ (!!((Yystate) == (-275)))
-#define YYTABLE_NINF -104
+#define YYTABLE_NINF -115
#define yytable_value_is_error(Yytable_value) \
- (!!((Yytable_value) == (-104)))
+ (!!((Yytable_value) == (-115)))
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
static const yytype_int16 yypact[] =
{
- -273, 376, -273, -273, -27, -21, -273, -273, -273, -273,
- 157, -273, -273, 11, 11, 11, -5, -3, -273, -273,
- -273, 1019, 1019, -273, 1019, 1065, 821, 116, -273, -20,
- 1, -273, -273, 35, 758, 992, 252, 296, -273, -273,
- -273, -273, 233, 789, 821, -273, 2, -273, -273, -273,
- -273, -273, 63, 54, -273, 69, -273, -273, -273, 789,
- 789, 127, 87, 115, 87, 87, 1019, 131, -273, -273,
- 55, 295, 40, 47, -273, 83, -273, -273, -273, 35,
- -273, 83, -273, 151, -273, -273, 1019, 132, 1019, 1019,
- 1019, 83, -273, -273, -273, 1019, 124, 252, 1019, 1019,
- 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019,
- -273, -273, -273, -273, 152, 1019, 100, 16, 1034, 37,
- -273, -273, -273, 43, 1019, -273, 100, 100, 295, -273,
- -273, -273, 1019, 83, -273, 137, 867, -273, -273, 75,
- -19, -273, 77, -19, 35, -273, 596, -273, -273, 123,
- -273, 141, 175, 1098, 1019, 161, 11, -26, -26, 87,
- 87, 87, 87, -26, -26, 87, 87, 87, 87, -273,
- 1034, -273, -273, -273, -273, 100, 65, 252, -273, -273,
- 1034, -273, 132, -273, 1034, -273, -273, -273, -273, -273,
- 104, -273, 26, 118, 119, 83, 121, -19, -19, -273,
- -273, -19, 1019, -19, 83, -273, -273, -19, -273, -273,
- 1034, -273, 117, 83, 1019, 1034, -273, 83, -273, 112,
- -273, 1019, 1019, -273, 188, 1019, 1019, 710, 900, -273,
- -273, -273, -19, 1034, -273, -273, -273, 642, 596, 83,
- -273, -273, 1034, -273, -273, -273, 295, -19, -21, 126,
- 295, 295, 169, -13, -273, 117, -273, 821, 186, -273,
- -273, -273, 83, -273, -273, 13, -273, -273, -273, 83,
- 83, 139, 132, 83, 55, -273, -273, 710, -273, -273,
- 1, 710, 1019, 100, 743, 137, 1019, 192, -273, -273,
- 295, 83, 286, 83, 992, 83, 44, 83, 710, 83,
- 946, 710, -273, 247, 154, -273, 156, -273, -273, 946,
- 100, -273, -273, -273, 226, 228, -273, 154, -273, 83,
- -273, 100, 83, -273, -273, 83, -273, 83, 710, -273,
- 448, 710, -273, 522, -273
+ -275, 376, -275, -275, -12, -9, -275, -275, -275, -275,
+ 171, -275, -275, 44, 44, 44, 5, 40, -275, -275,
+ -275, 1139, 1139, -275, 1139, 1166, 869, 27, -275, -18,
+ 2, -275, -275, 89, 884, 1065, 192, 214, -275, -275,
+ -275, -275, 248, 795, 869, -275, 10, -275, -275, -275,
+ -275, -275, 116, 82, -275, 115, -275, -275, -275, 795,
+ 795, 166, 107, 104, 107, 107, 1139, 117, -275, -275,
+ 15, 349, 23, 45, -275, 125, -275, -275, -275, 89,
+ -275, 125, -275, 178, -275, -275, 1092, 172, 1139, 1139,
+ 1139, 125, -275, -275, -275, 1139, 146, 192, 1139, 1139,
+ 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139,
+ -275, 181, -275, -275, 173, 1139, -275, -275, -275, 128,
+ 73, -275, 1107, 14, 1107, -275, -275, -275, -275, 1139,
+ -275, 128, 128, 349, -275, -275, -275, 1139, 125, -275,
+ 152, 916, -275, -275, 16, 92, -275, 20, 92, 89,
+ -275, 599, -275, -275, -275, 148, -275, 124, 22, 1048,
+ 1139, 199, 44, 265, 265, 107, 107, 107, 107, 265,
+ 265, 107, 107, 107, 107, -275, -275, 1107, -275, 1092,
+ 842, -275, 43, 192, -275, -275, 1107, -275, 172, -275,
+ 1107, -275, -275, -275, -275, -275, 133, -275, 41, 144,
+ 145, 125, 147, 92, 92, -275, -275, 92, 1139, 92,
+ 125, -275, -275, 92, -275, -275, 1107, -275, 151, 125,
+ 1139, 1107, -275, -275, -275, -275, -275, -275, 128, 76,
+ -275, 1139, 1139, -275, 224, 1139, 1139, 715, 949, -275,
+ -275, -275, 92, 1107, -275, -275, -275, 646, 599, 125,
+ -275, -275, 1107, 125, -275, 49, 349, 92, -9, 160,
+ 349, 349, 206, 113, -275, 151, -275, 869, 225, -275,
+ 169, -275, -275, -275, -275, -275, 125, -275, -275, 11,
+ -275, -275, -275, 125, 125, 179, 172, 125, 15, -275,
+ -275, 715, -275, -275, 2, 715, 1139, 128, 762, 152,
+ 1139, 219, -275, -275, 349, 125, 275, 125, 1065, 125,
+ 112, 125, 715, 125, 997, 715, -275, 261, 205, -275,
+ 191, -275, -275, 997, 128, -275, -275, -275, 271, 272,
+ -275, -275, 205, -275, 125, -275, 128, 125, -275, -275,
+ 125, -275, 125, 715, -275, 449, 715, -275, 524, -275
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -773,64 +801,65 @@ static const yytype_int16 yypact[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 2, 0, 1, 6, 0, 174, 156, 157, 21, 22,
- 0, 23, 24, 163, 0, 0, 0, 151, 5, 87,
- 36, 0, 0, 35, 0, 0, 0, 0, 3, 0,
- 0, 146, 33, 4, 19, 117, 125, 126, 128, 152,
- 160, 176, 153, 0, 0, 171, 0, 175, 27, 26,
- 30, 31, 0, 0, 28, 91, 164, 154, 155, 0,
- 0, 0, 159, 153, 158, 147, 0, 180, 153, 106,
- 0, 104, 0, 0, 161, 89, 186, 7, 8, 40,
- 37, 89, 9, 0, 88, 121, 0, 0, 0, 0,
- 0, 89, 122, 124, 123, 0, 0, 127, 0, 0,
+ 2, 0, 1, 6, 0, 189, 171, 172, 21, 22,
+ 0, 23, 24, 178, 0, 0, 0, 166, 5, 90,
+ 38, 0, 0, 37, 0, 0, 0, 0, 3, 0,
+ 0, 161, 34, 4, 19, 132, 140, 141, 143, 167,
+ 175, 191, 168, 0, 0, 186, 0, 190, 27, 26,
+ 30, 31, 0, 0, 28, 94, 179, 169, 170, 0,
+ 0, 0, 174, 168, 173, 162, 0, 195, 168, 109,
+ 0, 107, 0, 0, 176, 92, 201, 7, 8, 42,
+ 39, 92, 9, 0, 91, 136, 0, 0, 0, 0,
+ 0, 92, 137, 139, 138, 0, 0, 142, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 119, 118, 136, 137, 0, 0, 0, 0, 104, 0,
- 173, 172, 29, 0, 0, 135, 0, 0, 0, 178,
- 179, 177, 107, 89, 183, 0, 0, 148, 14, 0,
- 0, 17, 0, 0, 90, 181, 0, 41, 34, 113,
- 114, 111, 112, 0, 0, 115, 163, 133, 134, 130,
- 131, 132, 129, 144, 145, 141, 142, 143, 140, 120,
- 110, 162, 170, 97, 95, 0, 0, 92, 149, 150,
- 108, 188, 0, 109, 105, 13, 10, 16, 11, 39,
- 0, 57, 0, 0, 0, 89, 0, 0, 0, 78,
- 79, 0, 100, 0, 89, 38, 51, 0, 60, 44,
- 65, 37, 184, 89, 0, 20, 139, 89, 98, 0,
- 138, 0, 100, 62, 0, 0, 0, 0, 66, 52,
- 53, 54, 0, 101, 55, 182, 59, 0, 0, 89,
- 185, 42, 116, 32, 99, 96, 0, 0, 165, 0,
- 0, 0, 0, 174, 67, 0, 56, 0, 82, 80,
- 43, 25, 89, 58, 63, 0, 167, 169, 64, 89,
- 89, 0, 0, 89, 0, 83, 61, 0, 166, 168,
- 0, 0, 0, 0, 0, 81, 0, 85, 68, 46,
- 0, 89, 0, 89, 84, 89, 0, 89, 0, 89,
- 66, 0, 70, 0, 0, 69, 0, 47, 48, 66,
- 0, 86, 73, 76, 0, 0, 77, 0, 187, 89,
- 45, 0, 89, 75, 74, 89, 37, 89, 0, 37,
- 0, 0, 50, 0, 49
+ 134, 133, 151, 152, 0, 0, 117, 36, 122, 0,
+ 0, 115, 121, 0, 107, 188, 187, 29, 32, 0,
+ 150, 0, 0, 0, 193, 194, 192, 110, 92, 198,
+ 0, 0, 163, 14, 0, 0, 17, 0, 0, 93,
+ 196, 0, 43, 35, 127, 128, 129, 125, 126, 0,
+ 0, 130, 178, 148, 149, 145, 146, 147, 144, 159,
+ 160, 156, 157, 158, 155, 124, 135, 123, 177, 118,
+ 0, 185, 0, 95, 164, 165, 111, 203, 0, 112,
+ 108, 13, 10, 16, 11, 41, 0, 59, 0, 0,
+ 0, 92, 0, 0, 0, 81, 82, 0, 103, 0,
+ 92, 40, 53, 0, 62, 46, 67, 39, 199, 92,
+ 0, 20, 154, 119, 120, 116, 100, 98, 0, 0,
+ 153, 0, 103, 64, 0, 0, 0, 0, 68, 54,
+ 55, 56, 0, 104, 57, 197, 61, 0, 0, 92,
+ 200, 44, 131, 92, 101, 0, 0, 0, 180, 0,
+ 0, 0, 0, 189, 69, 0, 58, 0, 85, 83,
+ 0, 45, 25, 33, 102, 99, 92, 60, 65, 0,
+ 182, 184, 66, 92, 92, 0, 0, 92, 0, 86,
+ 63, 0, 181, 183, 0, 0, 0, 0, 0, 84,
+ 0, 88, 70, 48, 0, 92, 0, 92, 87, 92,
+ 0, 92, 0, 92, 68, 0, 72, 0, 0, 71,
+ 0, 49, 50, 68, 0, 89, 75, 78, 0, 0,
+ 79, 80, 0, 202, 92, 47, 0, 92, 77, 76,
+ 92, 39, 92, 0, 39, 0, 0, 52, 0, 51
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -273, -273, -273, -273, -273, -273, 208, -273, -273, -273,
- -64, -273, -273, -202, 71, -58, -273, -273, -218, -273,
- -273, -272, -273, -273, -273, -273, -273, -273, -273, -273,
- 50, 76, -273, -273, -273, 19, -54, -23, -1, -273,
- -273, -273, -44, 39, -273, 224, -273, -11, 94, -273,
- -273, -7, -38, -273, -273, -73, -2, -273, -28, -231,
- -46, -273, -25, -57, 85
+ -275, -275, -275, -275, -275, -275, 252, -275, -275, -275,
+ -275, -33, -275, -80, -275, -213, 100, -144, -275, -275,
+ -231, -275, -275, -274, -275, -275, -275, -275, -275, -275,
+ -275, -275, 7, 62, -275, -275, -275, 54, -275, -43,
+ 1, -275, -23, -1, -275, -275, -275, -13, 17, -275,
+ 263, -275, 8, 127, -275, -275, 21, -36, -275, -275,
+ -78, -2, -275, -27, -230, -65, -275, -15, -38, -94
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 28, 140, 143, 29, 77, 53, 54, 30,
- 31, 83, 32, 146, 78, 205, 206, 222, 207, 237,
- 248, 255, 296, 305, 317, 208, 258, 276, 286, 209,
- 144, 145, 125, 175, 176, 232, 116, 117, 210, 115,
- 94, 95, 35, 36, 37, 38, 39, 40, 55, 264,
- 265, 266, 45, 46, 47, 41, 42, 131, 211, 212,
- 137, 239, 213, 319, 136
+ -1, 1, 28, 145, 148, 29, 77, 53, 54, 30,
+ 182, 31, 83, 118, 32, 151, 78, 211, 212, 232,
+ 213, 247, 258, 265, 310, 319, 332, 214, 268, 290,
+ 300, 215, 149, 150, 130, 228, 229, 242, 269, 70,
+ 119, 120, 121, 216, 115, 94, 95, 35, 36, 37,
+ 38, 39, 40, 55, 278, 279, 280, 45, 46, 47,
+ 41, 42, 136, 217, 218, 142, 249, 219, 334, 141
};
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
@@ -838,306 +867,325 @@ static const yytype_int16 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int16 yytable[] =
{
- 34, 80, 80, 70, 81, 126, 127, 260, 121, 238,
- 254, 56, 57, 58, 150, 5, 74, 132, 120, 63,
- 63, 119, 63, 68, 135, 71, -103, 272, 310, 278,
- 223, 19, 19, 63, 100, 101, 102, 321, 132, 103,
- 43, 138, 118, 118, 173, 302, 139, 174, 141, 44,
- 74, 33, 75, 142, 76, 76, 132, 44, 118, 118,
- 62, 64, 59, 65, 60, 128, 218, -103, 303, 304,
- 171, 133, 44, 75, 97, 320, 185, 25, 187, 79,
- 178, 179, 254, 44, -103, 149, 84, 151, 152, 153,
- -103, 254, 133, 224, 155, 19, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 172, 220,
- 133, -93, 122, 244, 170, 81, 245, -89, 81, 4,
- 133, 123, 63, 134, 330, 124, -12, 333, -15, 217,
- 4, 180, 85, -94, 19, 184, 5, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, -12,
- 85, -15, 103, 215, 56, 86, 148, 147, 112, 113,
- 48, 49, 156, 177, 72, 169, 73, 154, 134, 252,
- -104, 221, 81, 81, 129, 130, 81, 182, 81, 92,
- 93, 87, 81, 259, 85, 225, 226, 240, 228, 86,
- 79, 76, 249, 79, 268, 271, 275, 92, 93, 283,
- 262, 233, 50, 51, 269, 270, 282, 81, 318, 181,
- 267, 186, 295, 242, 188, 87, 88, -104, -104, 287,
- 246, 233, 81, 289, 250, 251, 52, 267, 285, 204,
- 273, 92, 93, 323, 274, 324, 118, 291, 82, 316,
- 308, 247, 294, 311, 297, 110, 111, 79, 79, 67,
- 216, 79, 288, 79, 312, 313, 71, 79, 279, 293,
- 325, 219, 0, 0, 322, 0, 0, 299, 229, 230,
- 332, 227, 231, 334, 234, 327, 112, 113, 236, 0,
- 235, 290, 79, 292, 63, 114, 0, 0, 0, 241,
- 0, 0, 63, 243, 0, 85, 0, 79, 0, 20,
- 86, 0, 0, 256, 85, 314, 315, 0, 23, 86,
- 98, 99, 100, 101, 102, 261, 0, 103, 263, 0,
- 0, 0, 0, 0, 0, 0, 87, 88, 89, 0,
- 0, 0, 0, 97, 0, 87, 88, 89, 277, 90,
- 0, 0, 92, 93, 0, 280, 281, 0, 90, 284,
- 0, 92, 93, 0, 104, 105, 106, 107, 108, 0,
- 76, 109, 0, 134, 0, 0, 0, 298, 0, 300,
- 0, 301, 306, 307, 0, 309, 2, 3, 0, 4,
- 5, 0, 0, 6, 7, 0, 0, 0, 0, 0,
- 0, 0, 0, 8, 9, 326, 0, 0, 328, 0,
- 0, 329, 0, 331, 0, 0, 0, 0, 0, 0,
- 0, 10, 11, 12, 13, 0, 0, 0, 0, 14,
- 15, 16, 17, 18, 0, 0, 0, 19, 20, 0,
- 0, 0, 0, 0, 21, 22, 0, 23, 0, 24,
- 0, 0, 25, 26, 0, 27, 0, 0, -18, 189,
- -18, 4, 5, 0, 0, 6, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 190, 0, 191,
- 192, 193, -72, -72, 194, 195, 196, 197, 198, 199,
- 200, 201, 202, 0, 0, 0, 13, 203, 0, 0,
- 0, 14, 15, 16, 17, 0, 0, 0, 0, -72,
- 20, 0, 0, 0, 0, 0, 21, 22, 0, 23,
- 0, 24, 0, 0, 25, 26, 0, 61, 0, 0,
- 75, -72, 76, 189, 0, 4, 5, 0, 0, 6,
- 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 190, 0, 191, 192, 193, -71, -71, 194, 195,
- 196, 197, 198, 199, 200, 201, 202, 0, 0, 0,
- 13, 203, 0, 0, 0, 14, 15, 16, 17, 0,
- 0, 0, 0, -71, 20, 0, 0, 0, 0, 0,
- 21, 22, 0, 23, 0, 24, 0, 0, 25, 26,
- 0, 61, 0, 0, 75, -71, 76, 189, 0, 4,
+ 34, 123, 80, 80, 248, 140, 154, 264, 33, 156,
+ 126, 56, 57, 58, 81, 137, 137, 191, 271, 63,
+ 63, 193, 63, 68, 143, 71, 180, 125, 292, 144,
+ 4, 175, 85, 63, 19, 74, 79, 86, 62, 64,
+ 324, 65, 122, 124, 226, 233, 146, 227, 5, 336,
+ 274, 147, 97, 275, 178, 75, 43, 76, 122, 122,
+ 131, 132, 44, 87, 88, 133, 184, 185, -12, 74,
+ 138, 138, -15, 59, 179, 75, 72, 254, 73, 92,
+ 93, 44, 44, 264, 139, 155, 181, 157, 158, 159,
+ 335, -12, 264, 262, 161, -15, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 60, 234,
+ 230, 25, -96, 316, 177, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 63, 345, 138,
+ 81, 348, 138, 81, 85, 255, 186, 317, 318, 86,
+ 190, 84, -114, 152, 19, -97, 183, 301, 112, 113,
+ 128, 303, 79, 160, 286, 79, 223, 225, 85, 221,
+ 56, 134, 135, 253, 19, 87, 127, 76, 322, 4,
+ 137, 325, 129, 103, 48, 49, 5, 19, 122, 122,
+ -106, 92, 93, 153, 44, 162, -92, 176, 81, 81,
+ 117, 276, 81, 188, 81, 283, 284, 139, 81, 347,
+ 187, 231, 349, 250, 270, 92, 93, 243, 297, -115,
+ 79, 79, 235, 236, 79, 238, 79, 50, 51, 252,
+ 79, -106, 281, 299, 288, 138, 76, 81, 259, 282,
+ 256, 243, 305, 285, 260, 261, 289, 331, -106, 311,
+ 309, 52, 81, 281, -106, 192, 124, 296, 194, 79,
+ 287, 98, 99, 100, 101, 102, -115, -115, 103, 337,
+ 333, 110, 111, 237, 79, 210, 71, 302, 326, 327,
+ 117, 342, 245, 104, 105, 106, 107, 108, 338, 339,
+ 109, 251, 82, 307, 330, 85, 257, 308, 67, 222,
+ 86, 313, 112, 113, 340, 304, 0, 306, 63, 0,
+ 293, 114, 0, 239, 240, 0, 63, 241, 0, 244,
+ 0, 272, 0, 246, 20, 273, 87, 88, 89, 0,
+ 328, 329, 0, 23, 0, 97, 100, 101, 102, 90,
+ 0, 103, 92, 93, 0, 0, 0, 0, 291, 0,
+ 0, 0, 266, 0, 0, 294, 295, 0, 0, 298,
+ 76, 0, 0, 0, 0, 0, 0, 277, 0, 85,
+ 0, 0, 0, 0, 86, 0, 0, 312, 0, 314,
+ 0, 315, 320, 321, 0, 323, 2, 3, 0, 4,
5, 0, 0, 6, 7, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 190, 0, 191, 192, 193,
- 0, 0, 194, 195, 196, 197, 198, 199, 200, 201,
- 202, 0, 0, 0, 13, 203, 0, 0, 0, 14,
- 15, 16, 17, 69, 0, 4, 5, 0, 20, 6,
- 7, 0, -102, 0, 21, 22, 0, 23, 0, 24,
- 0, 0, 25, 26, 0, 61, 0, 0, 75, 204,
- 76, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 13, 0, 0, 0, 0, 14, 15, 16, 17, 0,
- 0, 0, 0, -102, 20, 0, 0, 0, 0, 0,
- 21, 22, 0, 23, 0, 24, 0, 0, 25, 257,
- -102, 61, 0, 4, 5, 0, -102, 6, 7, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 190,
- 0, 191, 192, 193, 0, 0, 194, 195, 196, 197,
- 198, 199, 200, 201, 202, 0, 4, 5, 13, 203,
- 6, 7, 0, 14, 15, 16, 17, 0, 0, 0,
- 0, 0, 20, 0, 0, 0, 0, 85, 21, 22,
- 0, 23, 86, 24, 0, 0, 25, 26, 0, 61,
- 0, 13, 75, 0, 76, 0, 14, 15, 16, 17,
- 69, 0, 4, 5, 0, 20, 6, 7, 87, 88,
+ 87, 88, 89, 0, 8, 9, 341, 0, 0, 343,
+ 0, 0, 344, 90, 346, 0, 92, 93, 0, 0,
+ 0, 0, 10, 11, 12, 13, 0, 0, 139, 0,
+ 14, 15, 16, 17, 18, 0, 0, 0, 19, 20,
+ 0, 0, 0, 0, 0, 21, 22, 0, 23, 0,
+ 24, 0, 0, 25, 26, 0, 27, 0, 0, -18,
+ 195, -18, 4, 5, 0, 0, 6, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 196,
+ 0, 197, 198, 199, -74, -74, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 0, 0, 0, 13, 209,
+ 0, 0, 0, 14, 15, 16, 17, 0, 0, 0,
+ 0, -74, 20, 0, 0, 0, 0, 0, 21, 22,
+ 0, 23, 0, 24, 0, 0, 25, 26, 0, 61,
+ 0, 0, 75, -74, 76, 195, 0, 4, 5, 0,
+ 0, 6, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 196, 0, 197, 198, 199, -73,
+ -73, 200, 201, 202, 203, 204, 205, 206, 207, 208,
+ 0, 0, 0, 13, 209, 0, 0, 0, 14, 15,
+ 16, 17, 0, 0, 0, 0, -73, 20, 0, 0,
+ 0, 0, 0, 21, 22, 0, 23, 0, 24, 0,
+ 0, 25, 26, 0, 61, 0, 0, 75, -73, 76,
+ 195, 0, 4, 5, 0, 0, 6, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 196,
+ 0, 197, 198, 199, 0, 0, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 0, 0, 0, 13, 209,
+ 0, 0, 0, 14, 15, 16, 17, 69, 0, 4,
+ 5, 0, 20, 6, 7, 0, 0, -105, 21, 22,
+ 0, 23, 0, 24, 0, 0, 25, 26, 0, 61,
+ 0, 0, 75, 210, 76, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 14, 15, 16, 17, 0, 0, 0, 0, -105, 20,
+ 0, 0, 0, 0, 0, 21, 22, 0, 23, 0,
+ 24, 0, 0, 25, 267, -105, 61, 0, 4, 5,
+ 0, -105, 6, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 196, 0, 197, 198, 199,
+ 0, 0, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 0, 0, 0, 13, 209, 0, 0, 0, 14,
+ 15, 16, 17, 0, 0, 4, 5, 0, 20, 6,
+ 7, 0, 0, 0, 21, 22, 0, 23, 0, 24,
+ 0, 0, 25, 26, 0, 61, 0, 0, 75, 0,
+ 76, 0, 0, 0, 0, 0, 116, 0, 4, 5,
+ 0, 13, 6, 7, 117, 0, 14, 15, 16, 17,
+ 0, 0, 0, 0, 0, 20, 0, 0, 0, 0,
+ 0, 21, 22, 0, 23, 0, 24, 0, 0, 25,
+ 26, 0, 61, 0, 13, 0, 0, 76, 0, 14,
+ 15, 16, 17, 224, 0, 4, 5, 0, 20, 6,
+ 7, 117, 0, 0, 21, 22, 0, 23, 0, 24,
+ 0, 0, 25, 26, -113, 61, 0, 0, 0, 0,
+ 69, 0, 4, 5, 0, 0, 6, 7, 0, 0,
+ 0, 13, 0, 0, 0, 0, 14, 15, 16, 17,
+ 0, 0, 0, 0, 85, 20, 0, 0, 0, 86,
+ 0, 21, 22, 0, 23, 0, 24, 0, 13, 25,
+ 26, 0, 61, 14, 15, 16, 17, 189, 0, 4,
+ 5, 0, 20, 6, 7, 87, 88, 89, 21, 22,
+ 0, 23, 0, 24, 0, 0, 25, 26, 90, 61,
+ 91, 92, 93, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 263, 0, 13, 6, 7, 0, 0,
+ 14, 15, 16, 17, 0, 0, 0, 0, 0, 20,
+ 0, 0, 198, 0, 0, 21, 22, 0, 23, 0,
+ 24, 205, 206, 25, 26, 0, 61, 0, 13, 0,
+ 0, 0, 0, 14, 15, 16, 17, 0, 0, 0,
+ 4, 5, 20, 0, 6, 7, 0, 0, 21, 22,
+ 0, 23, 0, 24, 0, 0, 25, 26, 0, 61,
+ 198, 0, 0, 0, 0, 0, 0, 0, 0, 205,
+ 206, 0, 0, 0, 0, 0, 13, 0, 0, 0,
+ 0, 14, 15, 16, 17, 0, 0, 0, 0, 0,
+ 20, 0, 0, 0, 0, 0, 21, 22, 85, 23,
+ 0, 24, 0, 86, 25, 26, 0, 61, 4, 5,
+ 0, 0, 6, 7, 0, 0, 0, 96, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 87,
+ 88, 89, 0, 0, 0, 4, 5, 0, 0, 6,
+ 7, 117, 90, 220, 13, 92, 93, 0, 0, 14,
+ 15, 16, 17, 0, 0, 0, 0, 85, 20, 0,
+ 0, 0, 86, 0, 21, 22, 0, 23, 0, 24,
+ 0, 13, 25, 26, 0, 61, 14, 15, 16, 17,
+ 0, 0, 4, 5, 0, 20, 6, 7, 87, 88,
89, 21, 22, 0, 23, 0, 24, 0, 0, 25,
- 26, 90, 61, 91, 92, 93, 0, 76, 0, 0,
- 0, 0, 69, 0, 4, 5, 0, 13, 6, 7,
- 0, 0, 14, 15, 16, 17, 0, 0, 0, 0,
- 0, 20, 0, 0, 0, 0, 0, 21, 22, 0,
- 23, 0, 24, 0, 0, 25, 26, -102, 61, 13,
- 0, 0, 0, 0, 14, 15, 16, 17, 183, 0,
- 4, 5, 0, 20, 6, 7, 0, 0, 0, 21,
- 22, 0, 23, 0, 24, 0, 0, 25, 26, 0,
- 61, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 4, 253, 13, 0, 6, 7, 0,
+ 26, 90, 61, 0, 92, 93, 0, 0, 0, 4,
+ 5, 0, 0, 6, 7, 0, 0, 0, 13, 0,
+ 0, 0, 0, 14, 15, 16, 17, 0, 0, 0,
+ 0, 0, 20, 0, 0, 0, 0, 0, 21, 22,
+ 0, 23, 0, 24, 0, 0, 25, 26, 0, 61,
14, 15, 16, 17, 0, 0, 0, 0, 0, 20,
- 0, 0, 192, 0, 0, 21, 22, 0, 23, 0,
- 24, 199, 200, 25, 26, 0, 61, 0, 13, 0,
- 0, 0, 0, 14, 15, 16, 17, 0, 0, 4,
- 5, 0, 20, 6, 7, 0, 0, 0, 21, 22,
- 0, 23, 0, 24, 0, 0, 25, 26, 192, 61,
- 0, 0, 0, 0, 0, 0, 0, 199, 200, 0,
- 0, 0, 0, 0, 13, 0, 0, 0, 0, 14,
- 15, 16, 17, 0, 0, 4, 5, 0, 20, 6,
- 7, 0, 0, 96, 21, 22, 0, 23, 0, 24,
- 0, 0, 25, 26, 0, 61, 0, 0, 0, 0,
- 0, 0, 4, 5, 0, 0, 6, 7, 0, 0,
- 13, 0, 0, 0, 0, 14, 15, 16, 17, 0,
- 0, 0, 0, 85, 20, 0, 0, 0, 86, 0,
- 21, 22, 0, 23, 0, 24, 0, 13, 25, 26,
- 0, 61, 14, 15, 16, 17, 0, 0, 4, 5,
- 0, 20, 6, 7, 87, 88, 89, 21, 22, 0,
- 23, 0, 24, 0, 0, 25, 26, 90, 61, 0,
- 92, 93, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 85, 14, 15,
- 16, 17, 86, 0, 0, 0, 0, 20, 0, 0,
- 0, 0, 0, 21, 22, 0, 23, 0, 24, 0,
- 0, 25, 66, 0, 61, 0, 0, 0, 87, 88,
- 89, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 90, 214, 0, 92, 93
+ 0, 0, 0, 0, 0, 21, 22, 0, 23, 0,
+ 24, 0, 0, 25, 66, 0, 61
};
static const yytype_int16 yycheck[] =
{
- 1, 29, 30, 26, 29, 59, 60, 238, 46, 211,
- 228, 13, 14, 15, 87, 4, 27, 1, 16, 21,
- 22, 44, 24, 25, 70, 26, 10, 40, 300, 16,
- 4, 51, 51, 35, 60, 61, 62, 309, 1, 65,
- 67, 1, 43, 44, 1, 1, 6, 4, 1, 70,
- 61, 1, 72, 6, 74, 74, 1, 70, 59, 60,
- 21, 22, 67, 24, 67, 66, 1, 51, 24, 25,
- 116, 55, 70, 72, 35, 306, 1, 66, 1, 29,
- 126, 127, 300, 70, 68, 86, 51, 88, 89, 90,
- 74, 309, 55, 67, 95, 51, 98, 99, 100, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 71, 182,
- 55, 68, 49, 1, 115, 140, 4, 73, 143, 3,
- 55, 67, 124, 68, 326, 56, 51, 329, 51, 175,
- 3, 132, 9, 68, 51, 136, 4, 98, 99, 100,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 74,
- 9, 74, 65, 154, 156, 14, 5, 81, 43, 44,
- 3, 4, 38, 124, 48, 13, 50, 91, 68, 227,
- 9, 67, 197, 198, 43, 44, 201, 40, 203, 56,
- 57, 40, 207, 237, 9, 67, 67, 212, 67, 14,
- 140, 74, 4, 143, 68, 26, 10, 56, 57, 272,
- 246, 202, 45, 46, 250, 251, 67, 232, 54, 133,
- 248, 140, 20, 214, 143, 40, 41, 56, 57, 277,
- 221, 222, 247, 281, 225, 226, 69, 265, 274, 73,
- 255, 56, 57, 7, 257, 7, 237, 283, 30, 303,
- 298, 222, 286, 301, 290, 12, 13, 197, 198, 25,
- 156, 201, 280, 203, 7, 8, 257, 207, 265, 284,
- 317, 176, -1, -1, 310, -1, -1, 292, 197, 198,
- 328, 195, 201, 331, 203, 321, 43, 44, 207, -1,
- 204, 282, 232, 284, 286, 52, -1, -1, -1, 213,
- -1, -1, 294, 217, -1, 9, -1, 247, -1, 52,
- 14, -1, -1, 232, 9, 58, 59, -1, 61, 14,
- 58, 59, 60, 61, 62, 239, -1, 65, 247, -1,
- -1, -1, -1, -1, -1, -1, 40, 41, 42, -1,
- -1, -1, -1, 294, -1, 40, 41, 42, 262, 53,
- -1, -1, 56, 57, -1, 269, 270, -1, 53, 273,
- -1, 56, 57, -1, 58, 59, 60, 61, 62, -1,
- 74, 65, -1, 68, -1, -1, -1, 291, -1, 293,
- -1, 295, 296, 297, -1, 299, 0, 1, -1, 3,
- 4, -1, -1, 7, 8, -1, -1, -1, -1, -1,
- -1, -1, -1, 17, 18, 319, -1, -1, 322, -1,
- -1, 325, -1, 327, -1, -1, -1, -1, -1, -1,
- -1, 35, 36, 37, 38, -1, -1, -1, -1, 43,
- 44, 45, 46, 47, -1, -1, -1, 51, 52, -1,
- -1, -1, -1, -1, 58, 59, -1, 61, -1, 63,
- -1, -1, 66, 67, -1, 69, -1, -1, 72, 1,
- 74, 3, 4, -1, -1, 7, 8, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 19, -1, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, -1, -1, -1, 38, 39, -1, -1,
- -1, 43, 44, 45, 46, -1, -1, -1, -1, 51,
- 52, -1, -1, -1, -1, -1, 58, 59, -1, 61,
- -1, 63, -1, -1, 66, 67, -1, 69, -1, -1,
- 72, 73, 74, 1, -1, 3, 4, -1, -1, 7,
- 8, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 19, -1, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, -1, -1, -1,
- 38, 39, -1, -1, -1, 43, 44, 45, 46, -1,
- -1, -1, -1, 51, 52, -1, -1, -1, -1, -1,
- 58, 59, -1, 61, -1, 63, -1, -1, 66, 67,
- -1, 69, -1, -1, 72, 73, 74, 1, -1, 3,
+ 1, 44, 29, 30, 217, 70, 86, 238, 1, 87,
+ 46, 13, 14, 15, 29, 1, 1, 1, 248, 21,
+ 22, 1, 24, 25, 1, 26, 120, 17, 17, 6,
+ 3, 111, 10, 35, 52, 27, 29, 15, 21, 22,
+ 314, 24, 43, 44, 1, 4, 1, 4, 4, 323,
+ 1, 6, 35, 4, 119, 73, 68, 75, 59, 60,
+ 59, 60, 71, 41, 42, 66, 131, 132, 52, 61,
+ 56, 56, 52, 68, 1, 73, 49, 1, 51, 57,
+ 58, 71, 71, 314, 69, 86, 72, 88, 89, 90,
+ 320, 75, 323, 237, 95, 75, 98, 99, 100, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 68, 68,
+ 188, 67, 69, 1, 115, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 129, 341, 56,
+ 145, 344, 56, 148, 10, 229, 137, 25, 26, 15,
+ 141, 52, 69, 81, 52, 69, 129, 291, 44, 45,
+ 68, 295, 145, 91, 41, 148, 179, 180, 10, 160,
+ 162, 44, 45, 228, 52, 41, 50, 75, 312, 3,
+ 1, 315, 57, 66, 3, 4, 4, 52, 179, 180,
+ 11, 57, 58, 5, 71, 39, 74, 14, 203, 204,
+ 9, 256, 207, 41, 209, 260, 261, 69, 213, 343,
+ 138, 68, 346, 218, 247, 57, 58, 208, 286, 10,
+ 203, 204, 68, 68, 207, 68, 209, 46, 47, 220,
+ 213, 52, 258, 288, 267, 56, 75, 242, 4, 69,
+ 231, 232, 297, 27, 235, 236, 11, 317, 69, 304,
+ 21, 70, 257, 279, 75, 145, 247, 68, 148, 242,
+ 265, 59, 60, 61, 62, 63, 57, 58, 66, 324,
+ 55, 13, 14, 201, 257, 74, 267, 294, 7, 8,
+ 9, 336, 210, 59, 60, 61, 62, 63, 7, 7,
+ 66, 219, 30, 298, 317, 10, 232, 300, 25, 162,
+ 15, 306, 44, 45, 332, 296, -1, 298, 300, -1,
+ 279, 53, -1, 203, 204, -1, 308, 207, -1, 209,
+ -1, 249, -1, 213, 53, 253, 41, 42, 43, -1,
+ 59, 60, -1, 62, -1, 308, 61, 62, 63, 54,
+ -1, 66, 57, 58, -1, -1, -1, -1, 276, -1,
+ -1, -1, 242, -1, -1, 283, 284, -1, -1, 287,
+ 75, -1, -1, -1, -1, -1, -1, 257, -1, 10,
+ -1, -1, -1, -1, 15, -1, -1, 305, -1, 307,
+ -1, 309, 310, 311, -1, 313, 0, 1, -1, 3,
4, -1, -1, 7, 8, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 19, -1, 21, 22, 23,
- -1, -1, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, -1, -1, -1, 38, 39, -1, -1, -1, 43,
- 44, 45, 46, 1, -1, 3, 4, -1, 52, 7,
- 8, -1, 10, -1, 58, 59, -1, 61, -1, 63,
- -1, -1, 66, 67, -1, 69, -1, -1, 72, 73,
- 74, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 38, -1, -1, -1, -1, 43, 44, 45, 46, -1,
- -1, -1, -1, 51, 52, -1, -1, -1, -1, -1,
- 58, 59, -1, 61, -1, 63, -1, -1, 66, 67,
- 68, 69, -1, 3, 4, -1, 74, 7, 8, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 19,
- -1, 21, 22, 23, -1, -1, 26, 27, 28, 29,
- 30, 31, 32, 33, 34, -1, 3, 4, 38, 39,
- 7, 8, -1, 43, 44, 45, 46, -1, -1, -1,
- -1, -1, 52, -1, -1, -1, -1, 9, 58, 59,
- -1, 61, 14, 63, -1, -1, 66, 67, -1, 69,
- -1, 38, 72, -1, 74, -1, 43, 44, 45, 46,
- 1, -1, 3, 4, -1, 52, 7, 8, 40, 41,
- 42, 58, 59, -1, 61, -1, 63, -1, -1, 66,
- 67, 53, 69, 55, 56, 57, -1, 74, -1, -1,
- -1, -1, 1, -1, 3, 4, -1, 38, 7, 8,
- -1, -1, 43, 44, 45, 46, -1, -1, -1, -1,
- -1, 52, -1, -1, -1, -1, -1, 58, 59, -1,
- 61, -1, 63, -1, -1, 66, 67, 68, 69, 38,
- -1, -1, -1, -1, 43, 44, 45, 46, 1, -1,
- 3, 4, -1, 52, 7, 8, -1, -1, -1, 58,
- 59, -1, 61, -1, 63, -1, -1, 66, 67, -1,
- 69, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 3, 4, 38, -1, 7, 8, -1,
- 43, 44, 45, 46, -1, -1, -1, -1, -1, 52,
- -1, -1, 22, -1, -1, 58, 59, -1, 61, -1,
- 63, 31, 32, 66, 67, -1, 69, -1, 38, -1,
- -1, -1, -1, 43, 44, 45, 46, -1, -1, 3,
- 4, -1, 52, 7, 8, -1, -1, -1, 58, 59,
- -1, 61, -1, 63, -1, -1, 66, 67, 22, 69,
- -1, -1, -1, -1, -1, -1, -1, 31, 32, -1,
- -1, -1, -1, -1, 38, -1, -1, -1, -1, 43,
- 44, 45, 46, -1, -1, 3, 4, -1, 52, 7,
- 8, -1, -1, 11, 58, 59, -1, 61, -1, 63,
- -1, -1, 66, 67, -1, 69, -1, -1, -1, -1,
- -1, -1, 3, 4, -1, -1, 7, 8, -1, -1,
- 38, -1, -1, -1, -1, 43, 44, 45, 46, -1,
- -1, -1, -1, 9, 52, -1, -1, -1, 14, -1,
- 58, 59, -1, 61, -1, 63, -1, 38, 66, 67,
- -1, 69, 43, 44, 45, 46, -1, -1, 3, 4,
- -1, 52, 7, 8, 40, 41, 42, 58, 59, -1,
- 61, -1, 63, -1, -1, 66, 67, 53, 69, -1,
- 56, 57, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 9, 43, 44,
- 45, 46, 14, -1, -1, -1, -1, 52, -1, -1,
- -1, -1, -1, 58, 59, -1, 61, -1, 63, -1,
- -1, 66, 67, -1, 69, -1, -1, -1, 40, 41,
- 42, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 53, 54, -1, 56, 57
+ 41, 42, 43, -1, 18, 19, 334, -1, -1, 337,
+ -1, -1, 340, 54, 342, -1, 57, 58, -1, -1,
+ -1, -1, 36, 37, 38, 39, -1, -1, 69, -1,
+ 44, 45, 46, 47, 48, -1, -1, -1, 52, 53,
+ -1, -1, -1, -1, -1, 59, 60, -1, 62, -1,
+ 64, -1, -1, 67, 68, -1, 70, -1, -1, 73,
+ 1, 75, 3, 4, -1, -1, 7, 8, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 20,
+ -1, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, -1, -1, -1, 39, 40,
+ -1, -1, -1, 44, 45, 46, 47, -1, -1, -1,
+ -1, 52, 53, -1, -1, -1, -1, -1, 59, 60,
+ -1, 62, -1, 64, -1, -1, 67, 68, -1, 70,
+ -1, -1, 73, 74, 75, 1, -1, 3, 4, -1,
+ -1, 7, 8, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 20, -1, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ -1, -1, -1, 39, 40, -1, -1, -1, 44, 45,
+ 46, 47, -1, -1, -1, -1, 52, 53, -1, -1,
+ -1, -1, -1, 59, 60, -1, 62, -1, 64, -1,
+ -1, 67, 68, -1, 70, -1, -1, 73, 74, 75,
+ 1, -1, 3, 4, -1, -1, 7, 8, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 20,
+ -1, 22, 23, 24, -1, -1, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, -1, -1, -1, 39, 40,
+ -1, -1, -1, 44, 45, 46, 47, 1, -1, 3,
+ 4, -1, 53, 7, 8, -1, -1, 11, 59, 60,
+ -1, 62, -1, 64, -1, -1, 67, 68, -1, 70,
+ -1, -1, 73, 74, 75, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 39, -1, -1, -1, -1,
+ 44, 45, 46, 47, -1, -1, -1, -1, 52, 53,
+ -1, -1, -1, -1, -1, 59, 60, -1, 62, -1,
+ 64, -1, -1, 67, 68, 69, 70, -1, 3, 4,
+ -1, 75, 7, 8, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 20, -1, 22, 23, 24,
+ -1, -1, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, -1, -1, -1, 39, 40, -1, -1, -1, 44,
+ 45, 46, 47, -1, -1, 3, 4, -1, 53, 7,
+ 8, -1, -1, -1, 59, 60, -1, 62, -1, 64,
+ -1, -1, 67, 68, -1, 70, -1, -1, 73, -1,
+ 75, -1, -1, -1, -1, -1, 1, -1, 3, 4,
+ -1, 39, 7, 8, 9, -1, 44, 45, 46, 47,
+ -1, -1, -1, -1, -1, 53, -1, -1, -1, -1,
+ -1, 59, 60, -1, 62, -1, 64, -1, -1, 67,
+ 68, -1, 70, -1, 39, -1, -1, 75, -1, 44,
+ 45, 46, 47, 1, -1, 3, 4, -1, 53, 7,
+ 8, 9, -1, -1, 59, 60, -1, 62, -1, 64,
+ -1, -1, 67, 68, 69, 70, -1, -1, -1, -1,
+ 1, -1, 3, 4, -1, -1, 7, 8, -1, -1,
+ -1, 39, -1, -1, -1, -1, 44, 45, 46, 47,
+ -1, -1, -1, -1, 10, 53, -1, -1, -1, 15,
+ -1, 59, 60, -1, 62, -1, 64, -1, 39, 67,
+ 68, -1, 70, 44, 45, 46, 47, 1, -1, 3,
+ 4, -1, 53, 7, 8, 41, 42, 43, 59, 60,
+ -1, 62, -1, 64, -1, -1, 67, 68, 54, 70,
+ 56, 57, 58, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 3, 4, -1, 39, 7, 8, -1, -1,
+ 44, 45, 46, 47, -1, -1, -1, -1, -1, 53,
+ -1, -1, 23, -1, -1, 59, 60, -1, 62, -1,
+ 64, 32, 33, 67, 68, -1, 70, -1, 39, -1,
+ -1, -1, -1, 44, 45, 46, 47, -1, -1, -1,
+ 3, 4, 53, -1, 7, 8, -1, -1, 59, 60,
+ -1, 62, -1, 64, -1, -1, 67, 68, -1, 70,
+ 23, -1, -1, -1, -1, -1, -1, -1, -1, 32,
+ 33, -1, -1, -1, -1, -1, 39, -1, -1, -1,
+ -1, 44, 45, 46, 47, -1, -1, -1, -1, -1,
+ 53, -1, -1, -1, -1, -1, 59, 60, 10, 62,
+ -1, 64, -1, 15, 67, 68, -1, 70, 3, 4,
+ -1, -1, 7, 8, -1, -1, -1, 12, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 41,
+ 42, 43, -1, -1, -1, 3, 4, -1, -1, 7,
+ 8, 9, 54, 55, 39, 57, 58, -1, -1, 44,
+ 45, 46, 47, -1, -1, -1, -1, 10, 53, -1,
+ -1, -1, 15, -1, 59, 60, -1, 62, -1, 64,
+ -1, 39, 67, 68, -1, 70, 44, 45, 46, 47,
+ -1, -1, 3, 4, -1, 53, 7, 8, 41, 42,
+ 43, 59, 60, -1, 62, -1, 64, -1, -1, 67,
+ 68, 54, 70, -1, 57, 58, -1, -1, -1, 3,
+ 4, -1, -1, 7, 8, -1, -1, -1, 39, -1,
+ -1, -1, -1, 44, 45, 46, 47, -1, -1, -1,
+ -1, -1, 53, -1, -1, -1, -1, -1, 59, 60,
+ -1, 62, -1, 64, -1, -1, 67, 68, -1, 70,
+ 44, 45, 46, 47, -1, -1, -1, -1, -1, 53,
+ -1, -1, -1, -1, -1, 59, 60, -1, 62, -1,
+ 64, -1, -1, 67, 68, -1, 70
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
- 0, 76, 0, 1, 3, 4, 7, 8, 17, 18,
- 35, 36, 37, 38, 43, 44, 45, 46, 47, 51,
- 52, 58, 59, 61, 63, 66, 67, 69, 77, 80,
- 84, 85, 87, 105, 113, 117, 118, 119, 120, 121,
- 122, 130, 131, 67, 70, 127, 128, 129, 3, 4,
- 45, 46, 69, 82, 83, 123, 131, 131, 131, 67,
- 67, 69, 118, 131, 118, 118, 67, 120, 131, 1,
- 112, 113, 48, 50, 122, 72, 74, 81, 89, 105,
- 133, 137, 81, 86, 51, 9, 14, 40, 41, 42,
- 53, 55, 56, 57, 115, 116, 11, 118, 58, 59,
- 60, 61, 62, 65, 58, 59, 60, 61, 62, 65,
- 12, 13, 43, 44, 52, 114, 111, 112, 113, 112,
- 16, 127, 49, 67, 56, 107, 111, 111, 113, 43,
- 44, 132, 1, 55, 68, 135, 139, 135, 1, 6,
- 78, 1, 6, 79, 105, 106, 88, 106, 5, 113,
- 130, 113, 113, 113, 106, 113, 38, 118, 118, 118,
- 118, 118, 118, 118, 118, 118, 118, 118, 118, 13,
- 113, 135, 71, 1, 4, 108, 109, 118, 135, 135,
- 113, 106, 40, 1, 113, 1, 89, 1, 89, 1,
- 19, 21, 22, 23, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 39, 73, 90, 91, 93, 100, 104,
- 113, 133, 134, 137, 54, 113, 123, 135, 1, 139,
- 130, 67, 92, 4, 67, 67, 67, 106, 67, 89,
- 89, 89, 110, 113, 89, 106, 89, 94, 88, 136,
- 137, 106, 113, 106, 1, 4, 113, 110, 95, 4,
- 113, 113, 90, 4, 93, 96, 89, 67, 101, 111,
- 134, 106, 135, 89, 124, 125, 126, 127, 68, 135,
- 135, 26, 40, 137, 112, 10, 102, 106, 16, 126,
- 106, 106, 67, 130, 106, 135, 103, 90, 133, 90,
- 113, 135, 113, 137, 117, 20, 97, 135, 106, 137,
- 106, 106, 1, 24, 25, 98, 106, 106, 90, 106,
- 96, 90, 7, 8, 58, 59, 85, 99, 54, 138,
- 134, 96, 135, 7, 7, 138, 106, 135, 106, 106,
- 88, 106, 90, 88, 90
+ 0, 77, 0, 1, 3, 4, 7, 8, 18, 19,
+ 36, 37, 38, 39, 44, 45, 46, 47, 48, 52,
+ 53, 59, 60, 62, 64, 67, 68, 70, 78, 81,
+ 85, 87, 90, 108, 119, 123, 124, 125, 126, 127,
+ 128, 136, 137, 68, 71, 133, 134, 135, 3, 4,
+ 46, 47, 70, 83, 84, 129, 137, 137, 137, 68,
+ 68, 70, 124, 137, 124, 124, 68, 126, 137, 1,
+ 115, 119, 49, 51, 128, 73, 75, 82, 92, 108,
+ 139, 143, 82, 88, 52, 10, 15, 41, 42, 43,
+ 54, 56, 57, 58, 121, 122, 12, 124, 59, 60,
+ 61, 62, 63, 66, 59, 60, 61, 62, 63, 66,
+ 13, 14, 44, 45, 53, 120, 1, 9, 89, 116,
+ 117, 118, 119, 115, 119, 17, 133, 50, 68, 57,
+ 110, 116, 116, 119, 44, 45, 138, 1, 56, 69,
+ 141, 145, 141, 1, 6, 79, 1, 6, 80, 108,
+ 109, 91, 109, 5, 89, 119, 136, 119, 119, 119,
+ 109, 119, 39, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124, 124, 124, 89, 14, 119, 141, 1,
+ 145, 72, 86, 124, 141, 141, 119, 109, 41, 1,
+ 119, 1, 92, 1, 92, 1, 20, 22, 23, 24,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 40,
+ 74, 93, 94, 96, 103, 107, 119, 139, 140, 143,
+ 55, 119, 129, 118, 1, 118, 1, 4, 111, 112,
+ 136, 68, 95, 4, 68, 68, 68, 109, 68, 92,
+ 92, 92, 113, 119, 92, 109, 92, 97, 91, 142,
+ 143, 109, 119, 141, 1, 145, 119, 113, 98, 4,
+ 119, 119, 93, 4, 96, 99, 92, 68, 104, 114,
+ 115, 140, 109, 109, 1, 4, 141, 92, 130, 131,
+ 132, 133, 69, 141, 141, 27, 41, 143, 115, 11,
+ 105, 109, 17, 132, 109, 109, 68, 136, 109, 141,
+ 106, 93, 139, 93, 119, 141, 119, 143, 123, 21,
+ 100, 141, 109, 143, 109, 109, 1, 25, 26, 101,
+ 109, 109, 93, 109, 99, 93, 7, 8, 59, 60,
+ 87, 89, 102, 55, 144, 140, 99, 141, 7, 7,
+ 144, 109, 141, 109, 109, 91, 109, 93, 91, 93
};
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 75, 76, 76, 76, 76, 76, 77, 77, 77,
- 77, 77, 78, 78, 78, 79, 79, 79, 80, 80,
- 80, 80, 80, 80, 80, 81, 82, 82, 82, 82,
- 83, 83, 84, 86, 85, 87, 87, 88, 88, 88,
- 89, 89, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 91, 91, 91, 91, 91, 92, 91, 91,
- 94, 93, 95, 93, 93, 93, 96, 96, 97, 97,
- 97, 98, 98, 99, 99, 99, 99, 99, 100, 100,
- 101, 101, 102, 103, 102, 104, 104, 105, 105, 106,
- 106, 107, 107, 108, 108, 109, 109, 109, 109, 109,
- 110, 110, 111, 111, 112, 112, 112, 112, 112, 112,
- 113, 113, 113, 113, 113, 113, 113, 113, 114, 114,
- 114, 115, 115, 116, 116, 117, 117, 117, 118, 118,
- 118, 118, 118, 118, 118, 118, 118, 118, 118, 119,
- 119, 119, 119, 119, 119, 119, 120, 120, 120, 120,
- 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
- 121, 121, 122, 123, 123, 124, 124, 125, 125, 126,
- 127, 128, 128, 129, 130, 130, 131, 131, 132, 132,
- 132, 133, 134, 135, 136, 136, 137, 138, 139
+ 0, 76, 77, 77, 77, 77, 77, 78, 78, 78,
+ 78, 78, 79, 79, 79, 80, 80, 80, 81, 81,
+ 81, 81, 81, 81, 81, 82, 83, 83, 83, 83,
+ 84, 84, 86, 85, 88, 87, 89, 90, 90, 91,
+ 91, 91, 92, 92, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 94, 94, 94, 94, 94, 95,
+ 94, 94, 97, 96, 98, 96, 96, 96, 99, 99,
+ 100, 100, 100, 101, 101, 102, 102, 102, 102, 102,
+ 102, 103, 103, 104, 104, 105, 106, 105, 107, 107,
+ 108, 108, 109, 109, 110, 110, 111, 111, 112, 112,
+ 112, 112, 112, 113, 113, 114, 114, 115, 115, 115,
+ 115, 115, 115, 116, 116, 117, 117, 117, 117, 117,
+ 117, 118, 118, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 120, 120, 120, 121, 121, 122, 122,
+ 123, 123, 123, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124, 124, 125, 125, 125, 125, 125, 125,
+ 125, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 127, 127, 128, 129, 129,
+ 130, 130, 131, 131, 132, 133, 134, 134, 135, 136,
+ 136, 137, 137, 138, 138, 138, 139, 140, 141, 142,
+ 142, 143, 144, 145
};
/* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
@@ -1146,22 +1194,24 @@ static const yytype_uint8 yyr2[] =
0, 2, 0, 2, 2, 2, 2, 2, 2, 2,
4, 4, 1, 2, 1, 1, 2, 1, 0, 1,
4, 1, 1, 1, 1, 5, 1, 1, 1, 2,
- 1, 1, 6, 0, 3, 1, 1, 0, 2, 2,
- 1, 2, 2, 3, 1, 9, 6, 8, 8, 12,
- 11, 1, 2, 2, 2, 2, 3, 0, 4, 2,
- 0, 4, 0, 4, 4, 1, 0, 1, 0, 2,
- 2, 5, 4, 1, 2, 2, 1, 1, 1, 1,
- 1, 3, 0, 0, 3, 6, 9, 1, 2, 0,
- 1, 0, 2, 0, 1, 1, 3, 1, 2, 3,
- 0, 1, 0, 1, 1, 3, 1, 2, 3, 3,
- 3, 3, 3, 3, 3, 3, 5, 1, 1, 1,
- 2, 1, 1, 1, 1, 1, 1, 2, 1, 3,
- 3, 3, 3, 3, 3, 3, 2, 2, 5, 4,
- 3, 3, 3, 3, 3, 3, 1, 2, 3, 4,
- 4, 1, 1, 1, 2, 2, 1, 1, 2, 2,
- 1, 2, 4, 0, 1, 0, 2, 1, 2, 1,
- 3, 1, 2, 2, 1, 2, 1, 3, 1, 1,
- 0, 2, 2, 1, 0, 1, 1, 1, 2
+ 1, 1, 0, 7, 0, 3, 1, 1, 1, 0,
+ 2, 2, 1, 2, 2, 3, 1, 9, 6, 8,
+ 8, 12, 11, 1, 2, 2, 2, 2, 3, 0,
+ 4, 2, 0, 4, 0, 4, 4, 1, 0, 1,
+ 0, 2, 2, 5, 4, 1, 2, 2, 1, 1,
+ 1, 1, 1, 1, 3, 0, 0, 3, 6, 9,
+ 1, 2, 0, 1, 0, 2, 0, 1, 1, 3,
+ 1, 2, 3, 0, 1, 0, 1, 1, 3, 1,
+ 2, 3, 3, 0, 1, 1, 3, 1, 2, 3,
+ 3, 1, 1, 3, 3, 3, 3, 3, 3, 3,
+ 3, 5, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 2, 1, 3, 3, 3, 3, 3, 3,
+ 3, 2, 2, 5, 4, 3, 3, 3, 3, 3,
+ 3, 1, 2, 3, 4, 4, 1, 1, 1, 2,
+ 2, 1, 1, 2, 2, 1, 2, 4, 0, 1,
+ 0, 2, 1, 2, 1, 3, 1, 2, 2, 1,
+ 2, 1, 3, 1, 1, 0, 2, 2, 1, 0,
+ 1, 1, 1, 2
};
@@ -1838,24 +1888,24 @@ yyreduce:
switch (yyn)
{
case 3:
-#line 197 "awkgram.y" /* yacc.c:1646 */
+#line 218 "awkgram.y" /* yacc.c:1646 */
{
rule = 0;
yyerrok;
}
-#line 1847 "awkgram.c" /* yacc.c:1646 */
+#line 1897 "awkgram.c" /* yacc.c:1646 */
break;
case 5:
-#line 203 "awkgram.y" /* yacc.c:1646 */
+#line 224 "awkgram.y" /* yacc.c:1646 */
{
next_sourcefile();
}
-#line 1855 "awkgram.c" /* yacc.c:1646 */
+#line 1905 "awkgram.c" /* yacc.c:1646 */
break;
case 6:
-#line 207 "awkgram.y" /* yacc.c:1646 */
+#line 228 "awkgram.y" /* yacc.c:1646 */
{
rule = 0;
/*
@@ -1864,19 +1914,20 @@ yyreduce:
*/
/* yyerrok; */
}
-#line 1868 "awkgram.c" /* yacc.c:1646 */
+#line 1918 "awkgram.c" /* yacc.c:1646 */
break;
case 7:
-#line 219 "awkgram.y" /* yacc.c:1646 */
+#line 240 "awkgram.y" /* yacc.c:1646 */
{
(void) append_rule((yyvsp[-1]), (yyvsp[0]));
+ first_rule = false;
}
-#line 1876 "awkgram.c" /* yacc.c:1646 */
+#line 1927 "awkgram.c" /* yacc.c:1646 */
break;
case 8:
-#line 223 "awkgram.y" /* yacc.c:1646 */
+#line 245 "awkgram.y" /* yacc.c:1646 */
{
if (rule != Rule) {
msg(_("%s blocks must have an action part"), ruletab[rule]);
@@ -1887,41 +1938,42 @@ yyreduce:
} else /* pattern rule with non-empty pattern */
(void) append_rule((yyvsp[-1]), NULL);
}
-#line 1891 "awkgram.c" /* yacc.c:1646 */
+#line 1942 "awkgram.c" /* yacc.c:1646 */
break;
case 9:
-#line 234 "awkgram.y" /* yacc.c:1646 */
+#line 256 "awkgram.y" /* yacc.c:1646 */
{
in_function = NULL;
(void) mk_function((yyvsp[-1]), (yyvsp[0]));
+ want_param_names = DONT_CHECK;
yyerrok;
}
-#line 1901 "awkgram.c" /* yacc.c:1646 */
+#line 1953 "awkgram.c" /* yacc.c:1646 */
break;
case 10:
-#line 240 "awkgram.y" /* yacc.c:1646 */
+#line 263 "awkgram.y" /* yacc.c:1646 */
{
want_source = false;
at_seen = false;
yyerrok;
}
-#line 1911 "awkgram.c" /* yacc.c:1646 */
+#line 1963 "awkgram.c" /* yacc.c:1646 */
break;
case 11:
-#line 246 "awkgram.y" /* yacc.c:1646 */
+#line 269 "awkgram.y" /* yacc.c:1646 */
{
want_source = false;
at_seen = false;
yyerrok;
}
-#line 1921 "awkgram.c" /* yacc.c:1646 */
+#line 1973 "awkgram.c" /* yacc.c:1646 */
break;
case 12:
-#line 255 "awkgram.y" /* yacc.c:1646 */
+#line 278 "awkgram.y" /* yacc.c:1646 */
{
if (include_source((yyvsp[0])) < 0)
YYABORT;
@@ -1929,23 +1981,23 @@ yyreduce:
bcfree((yyvsp[0]));
(yyval) = NULL;
}
-#line 1933 "awkgram.c" /* yacc.c:1646 */
+#line 1985 "awkgram.c" /* yacc.c:1646 */
break;
case 13:
-#line 263 "awkgram.y" /* yacc.c:1646 */
+#line 286 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1939 "awkgram.c" /* yacc.c:1646 */
+#line 1991 "awkgram.c" /* yacc.c:1646 */
break;
case 14:
-#line 265 "awkgram.y" /* yacc.c:1646 */
+#line 288 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1945 "awkgram.c" /* yacc.c:1646 */
+#line 1997 "awkgram.c" /* yacc.c:1646 */
break;
case 15:
-#line 270 "awkgram.y" /* yacc.c:1646 */
+#line 293 "awkgram.y" /* yacc.c:1646 */
{
if (load_library((yyvsp[0])) < 0)
YYABORT;
@@ -1953,35 +2005,49 @@ yyreduce:
bcfree((yyvsp[0]));
(yyval) = NULL;
}
-#line 1957 "awkgram.c" /* yacc.c:1646 */
+#line 2009 "awkgram.c" /* yacc.c:1646 */
break;
case 16:
-#line 278 "awkgram.y" /* yacc.c:1646 */
+#line 301 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1963 "awkgram.c" /* yacc.c:1646 */
+#line 2015 "awkgram.c" /* yacc.c:1646 */
break;
case 17:
-#line 280 "awkgram.y" /* yacc.c:1646 */
+#line 303 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 1969 "awkgram.c" /* yacc.c:1646 */
+#line 2021 "awkgram.c" /* yacc.c:1646 */
break;
case 18:
-#line 285 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = NULL; rule = Rule; }
-#line 1975 "awkgram.c" /* yacc.c:1646 */
+#line 308 "awkgram.y" /* yacc.c:1646 */
+ {
+ rule = Rule;
+ if (comment != NULL) {
+ (yyval) = list_create(comment);
+ comment = NULL;
+ } else
+ (yyval) = NULL;
+ }
+#line 2034 "awkgram.c" /* yacc.c:1646 */
break;
case 19:
-#line 287 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = (yyvsp[0]); rule = Rule; }
-#line 1981 "awkgram.c" /* yacc.c:1646 */
+#line 317 "awkgram.y" /* yacc.c:1646 */
+ {
+ rule = Rule;
+ if (comment != NULL) {
+ (yyval) = list_prepend((yyvsp[0]), comment);
+ comment = NULL;
+ } else
+ (yyval) = (yyvsp[0]);
+ }
+#line 2047 "awkgram.c" /* yacc.c:1646 */
break;
case 20:
-#line 289 "awkgram.y" /* yacc.c:1646 */
+#line 327 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *tp;
@@ -2004,127 +2070,176 @@ yyreduce:
((yyvsp[-3])->nexti + 1)->condpair_left = (yyvsp[-3])->lasti;
((yyvsp[-3])->nexti + 1)->condpair_right = (yyvsp[0])->lasti;
}
- (yyval) = list_append(list_merge((yyvsp[-3]), (yyvsp[0])), tp);
+ if (comment != NULL) {
+ (yyval) = list_append(list_merge(list_prepend((yyvsp[-3]), comment), (yyvsp[0])), tp);
+ comment = NULL;
+ } else
+ (yyval) = list_append(list_merge((yyvsp[-3]), (yyvsp[0])), tp);
rule = Rule;
}
-#line 2011 "awkgram.c" /* yacc.c:1646 */
+#line 2081 "awkgram.c" /* yacc.c:1646 */
break;
case 21:
-#line 315 "awkgram.y" /* yacc.c:1646 */
+#line 357 "awkgram.y" /* yacc.c:1646 */
{
static int begin_seen = 0;
+
+ func_first = false;
if (do_lint_old && ++begin_seen == 2)
warning_ln((yyvsp[0])->source_line,
_("old awk does not support multiple `BEGIN' or `END' rules"));
(yyvsp[0])->in_rule = rule = BEGIN;
(yyvsp[0])->source_file = source;
+ check_comment();
(yyval) = (yyvsp[0]);
}
-#line 2026 "awkgram.c" /* yacc.c:1646 */
+#line 2099 "awkgram.c" /* yacc.c:1646 */
break;
case 22:
-#line 326 "awkgram.y" /* yacc.c:1646 */
+#line 371 "awkgram.y" /* yacc.c:1646 */
{
static int end_seen = 0;
+
+ func_first = false;
if (do_lint_old && ++end_seen == 2)
warning_ln((yyvsp[0])->source_line,
_("old awk does not support multiple `BEGIN' or `END' rules"));
(yyvsp[0])->in_rule = rule = END;
(yyvsp[0])->source_file = source;
+ check_comment();
(yyval) = (yyvsp[0]);
}
-#line 2041 "awkgram.c" /* yacc.c:1646 */
+#line 2117 "awkgram.c" /* yacc.c:1646 */
break;
case 23:
-#line 337 "awkgram.y" /* yacc.c:1646 */
+#line 385 "awkgram.y" /* yacc.c:1646 */
{
+ func_first = false;
(yyvsp[0])->in_rule = rule = BEGINFILE;
(yyvsp[0])->source_file = source;
+ check_comment();
(yyval) = (yyvsp[0]);
}
-#line 2051 "awkgram.c" /* yacc.c:1646 */
+#line 2129 "awkgram.c" /* yacc.c:1646 */
break;
case 24:
-#line 343 "awkgram.y" /* yacc.c:1646 */
+#line 393 "awkgram.y" /* yacc.c:1646 */
{
+ func_first = false;
(yyvsp[0])->in_rule = rule = ENDFILE;
(yyvsp[0])->source_file = source;
+ check_comment();
(yyval) = (yyvsp[0]);
}
-#line 2061 "awkgram.c" /* yacc.c:1646 */
+#line 2141 "awkgram.c" /* yacc.c:1646 */
break;
case 25:
-#line 352 "awkgram.y" /* yacc.c:1646 */
+#line 404 "awkgram.y" /* yacc.c:1646 */
{
+ INSTRUCTION *ip;
if ((yyvsp[-3]) == NULL)
- (yyval) = list_create(instruction(Op_no_op));
+ ip = list_create(instruction(Op_no_op));
else
- (yyval) = (yyvsp[-3]);
+ ip = (yyvsp[-3]);
+ (yyval) = ip;
}
-#line 2072 "awkgram.c" /* yacc.c:1646 */
+#line 2154 "awkgram.c" /* yacc.c:1646 */
break;
case 26:
-#line 362 "awkgram.y" /* yacc.c:1646 */
+#line 416 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2078 "awkgram.c" /* yacc.c:1646 */
+#line 2160 "awkgram.c" /* yacc.c:1646 */
break;
case 27:
-#line 364 "awkgram.y" /* yacc.c:1646 */
+#line 418 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2084 "awkgram.c" /* yacc.c:1646 */
+#line 2166 "awkgram.c" /* yacc.c:1646 */
break;
case 28:
-#line 366 "awkgram.y" /* yacc.c:1646 */
+#line 420 "awkgram.y" /* yacc.c:1646 */
{
yyerror(_("`%s' is a built-in function, it cannot be redefined"),
tokstart);
YYABORT;
}
-#line 2094 "awkgram.c" /* yacc.c:1646 */
+#line 2176 "awkgram.c" /* yacc.c:1646 */
break;
case 29:
-#line 372 "awkgram.y" /* yacc.c:1646 */
+#line 426 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = (yyvsp[0]);
at_seen = false;
}
-#line 2103 "awkgram.c" /* yacc.c:1646 */
+#line 2185 "awkgram.c" /* yacc.c:1646 */
break;
case 32:
-#line 385 "awkgram.y" /* yacc.c:1646 */
+#line 438 "awkgram.y" /* yacc.c:1646 */
+ { want_param_names = FUNC_HEADER; }
+#line 2191 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 33:
+#line 439 "awkgram.y" /* yacc.c:1646 */
{
- (yyvsp[-5])->source_file = source;
- if (install_function((yyvsp[-4])->lextok, (yyvsp[-5]), (yyvsp[-2])) < 0)
+ /*
+ * treat any comments between BOF and the first function
+ * definition (with no intervening BEGIN etc block) as
+ * program comments. Special kludge: iff there are more
+ * than one such comments, treat the last as a function
+ * comment.
+ */
+ if (prior_comment != NULL) {
+ comment_to_save = prior_comment;
+ prior_comment = NULL;
+ } else if (comment != NULL) {
+ comment_to_save = comment;
+ comment = NULL;
+ } else
+ comment_to_save = NULL;
+
+ if (comment_to_save != NULL && func_first
+ && strstr(comment_to_save->memory->stptr, "\n\n") != NULL)
+ split_comment();
+
+ /* save any other pre-function comment as function comment */
+ if (comment_to_save != NULL) {
+ function_comment = comment_to_save;
+ comment_to_save = NULL;
+ }
+ func_first = false;
+ (yyvsp[-6])->source_file = source;
+ if (install_function((yyvsp[-5])->lextok, (yyvsp[-6]), (yyvsp[-2])) < 0)
YYABORT;
- in_function = (yyvsp[-4])->lextok;
- (yyvsp[-4])->lextok = NULL;
- bcfree((yyvsp[-4]));
- /* $4 already free'd in install_function */
- (yyval) = (yyvsp[-5]);
+ in_function = (yyvsp[-5])->lextok;
+ (yyvsp[-5])->lextok = NULL;
+ bcfree((yyvsp[-5]));
+ /* $5 already free'd in install_function */
+ (yyval) = (yyvsp[-6]);
+ want_param_names = FUNC_BODY;
}
-#line 2118 "awkgram.c" /* yacc.c:1646 */
+#line 2233 "awkgram.c" /* yacc.c:1646 */
break;
- case 33:
-#line 403 "awkgram.y" /* yacc.c:1646 */
+ case 34:
+#line 484 "awkgram.y" /* yacc.c:1646 */
{ want_regexp = true; }
-#line 2124 "awkgram.c" /* yacc.c:1646 */
+#line 2239 "awkgram.c" /* yacc.c:1646 */
break;
- case 34:
-#line 405 "awkgram.y" /* yacc.c:1646 */
+ case 35:
+#line 486 "awkgram.y" /* yacc.c:1646 */
{
NODE *n, *exp;
char *re;
@@ -2153,69 +2268,129 @@ yyreduce:
(yyval)->opcode = Op_match_rec;
(yyval)->memory = n;
}
-#line 2157 "awkgram.c" /* yacc.c:1646 */
+#line 2272 "awkgram.c" /* yacc.c:1646 */
break;
- case 35:
-#line 437 "awkgram.y" /* yacc.c:1646 */
- { bcfree((yyvsp[0])); }
-#line 2163 "awkgram.c" /* yacc.c:1646 */
+ case 36:
+#line 518 "awkgram.y" /* yacc.c:1646 */
+ {
+ char *re;
+ size_t len;
+
+ re = (yyvsp[0])->lextok;
+ (yyvsp[0])->lextok = NULL;
+ len = strlen(re);
+
+ (yyval) = (yyvsp[0]);
+ (yyval)->opcode = Op_push_re;
+ (yyval)->memory = make_typed_regex(re, len);
+ }
+#line 2289 "awkgram.c" /* yacc.c:1646 */
break;
case 37:
-#line 443 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = NULL; }
-#line 2169 "awkgram.c" /* yacc.c:1646 */
+#line 533 "awkgram.y" /* yacc.c:1646 */
+ { bcfree((yyvsp[0])); }
+#line 2295 "awkgram.c" /* yacc.c:1646 */
break;
- case 38:
-#line 445 "awkgram.y" /* yacc.c:1646 */
+ case 39:
+#line 539 "awkgram.y" /* yacc.c:1646 */
{
- if ((yyvsp[0]) == NULL)
- (yyval) = (yyvsp[-1]);
- else {
+ if (prior_comment != NULL) {
+ (yyval) = list_create(prior_comment);
+ prior_comment = NULL;
+ } else if (comment != NULL) {
+ (yyval) = list_create(comment);
+ comment = NULL;
+ } else
+ (yyval) = NULL;
+ }
+#line 2310 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 40:
+#line 550 "awkgram.y" /* yacc.c:1646 */
+ {
+ if ((yyvsp[0]) == NULL) {
+ if (prior_comment != NULL) {
+ (yyval) = list_append((yyvsp[-1]), prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ (yyval) = list_append((yyval), comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ (yyval) = list_append((yyvsp[-1]), comment);
+ comment = NULL;
+ } else
+ (yyval) = (yyvsp[-1]);
+ } else {
add_lint((yyvsp[0]), LINT_no_effect);
- if ((yyvsp[-1]) == NULL)
- (yyval) = (yyvsp[0]);
- else
+ if ((yyvsp[-1]) == NULL) {
+ if (prior_comment != NULL) {
+ (yyval) = list_append((yyvsp[0]), prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ (yyval) = list_append((yyval), comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ (yyval) = list_append((yyvsp[0]), comment);
+ comment = NULL;
+ } else
+ (yyval) = (yyvsp[0]);
+ } else {
+ if (prior_comment != NULL) {
+ list_append((yyvsp[0]), prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ list_append((yyvsp[0]), comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ list_append((yyvsp[0]), comment);
+ comment = NULL;
+ }
(yyval) = list_merge((yyvsp[-1]), (yyvsp[0]));
+ }
}
- yyerrok;
+ yyerrok;
}
-#line 2186 "awkgram.c" /* yacc.c:1646 */
+#line 2361 "awkgram.c" /* yacc.c:1646 */
break;
- case 39:
-#line 458 "awkgram.y" /* yacc.c:1646 */
+ case 41:
+#line 597 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2192 "awkgram.c" /* yacc.c:1646 */
+#line 2367 "awkgram.c" /* yacc.c:1646 */
break;
- case 42:
-#line 468 "awkgram.y" /* yacc.c:1646 */
+ case 44:
+#line 607 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2198 "awkgram.c" /* yacc.c:1646 */
+#line 2373 "awkgram.c" /* yacc.c:1646 */
break;
- case 43:
-#line 470 "awkgram.y" /* yacc.c:1646 */
+ case 45:
+#line 609 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 2204 "awkgram.c" /* yacc.c:1646 */
+#line 2379 "awkgram.c" /* yacc.c:1646 */
break;
- case 44:
-#line 472 "awkgram.y" /* yacc.c:1646 */
+ case 46:
+#line 611 "awkgram.y" /* yacc.c:1646 */
{
if (do_pretty_print)
(yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count));
else
(yyval) = (yyvsp[0]);
}
-#line 2215 "awkgram.c" /* yacc.c:1646 */
+#line 2390 "awkgram.c" /* yacc.c:1646 */
break;
- case 45:
-#line 479 "awkgram.y" /* yacc.c:1646 */
+ case 47:
+#line 618 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
INSTRUCTION *ip, *nextc, *tbreak;
@@ -2224,7 +2399,7 @@ yyreduce:
int case_count = 0;
int i;
- tbreak = instruction(Op_no_op);
+ tbreak = instruction(Op_no_op);
cstmt = list_create(tbreak);
cexp = list_create(instruction(Op_pop));
dflt = instruction(Op_jmp);
@@ -2236,7 +2411,7 @@ yyreduce:
} /* else
curr = NULL; */
- for(; curr != NULL; curr = nextc) {
+ for (; curr != NULL; curr = nextc) {
INSTRUCTION *caseexp = curr->case_exp;
INSTRUCTION *casestmt = curr->case_stmt;
@@ -2251,7 +2426,7 @@ yyreduce:
error_ln(curr->source_line,
_("duplicate case values in switch body: %s"), caseval);
}
-
+
if (case_values == NULL)
emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement");
else if (case_count >= maxcount) {
@@ -2302,22 +2477,22 @@ yyreduce:
(void) list_merge(ip, cexp);
(yyval) = list_merge(ip, cstmt);
- break_allowed--;
+ break_allowed--;
fix_break_continue(ip, tbreak, NULL);
}
-#line 2309 "awkgram.c" /* yacc.c:1646 */
+#line 2484 "awkgram.c" /* yacc.c:1646 */
break;
- case 46:
-#line 569 "awkgram.y" /* yacc.c:1646 */
- {
+ case 48:
+#line 708 "awkgram.y" /* yacc.c:1646 */
+ {
/*
* -----------------
* tc:
* cond
* -----------------
* [Op_jmp_false tb ]
- * -----------------
+ * -----------------
* body
* -----------------
* [Op_jmp tc ]
@@ -2351,18 +2526,18 @@ yyreduce:
continue_allowed--;
fix_break_continue(ip, tbreak, tcont);
}
-#line 2355 "awkgram.c" /* yacc.c:1646 */
+#line 2530 "awkgram.c" /* yacc.c:1646 */
break;
- case 47:
-#line 611 "awkgram.y" /* yacc.c:1646 */
+ case 49:
+#line 750 "awkgram.y" /* yacc.c:1646 */
{
/*
* -----------------
* z:
* body
* -----------------
- * tc:
+ * tc:
* cond
* -----------------
* [Op_jmp_true | z ]
@@ -2397,11 +2572,11 @@ yyreduce:
} /* else
$1 and $4 are NULLs */
}
-#line 2401 "awkgram.c" /* yacc.c:1646 */
+#line 2576 "awkgram.c" /* yacc.c:1646 */
break;
- case 48:
-#line 653 "awkgram.y" /* yacc.c:1646 */
+ case 50:
+#line 792 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *ip;
char *var_name = (yyvsp[-5])->lextok;
@@ -2413,7 +2588,7 @@ yyreduce:
&& ((yyvsp[0])->nexti->memory->type != Node_var || !((yyvsp[0])->nexti->memory->var_update))
&& strcmp((yyvsp[0])->nexti->memory->vname, var_name) == 0
) {
-
+
/* Efficiency hack. Recognize the special case of
*
* for (iggy in foo)
@@ -2425,10 +2600,10 @@ yyreduce:
*
* Check that the body is a `delete a[i]' statement,
* and that both the loop var and array names match.
- */
+ */
NODE *arr = NULL;
- ip = (yyvsp[0])->nexti->nexti;
+ ip = (yyvsp[0])->nexti->nexti;
if ((yyvsp[-3])->nexti->opcode == Op_push && (yyvsp[-3])->lasti == (yyvsp[-3])->nexti)
arr = (yyvsp[-3])->nexti->memory;
if (arr != NULL
@@ -2454,7 +2629,7 @@ yyreduce:
/* [ Op_push_array a ]
* [ Op_arrayfor_init | ib ]
- * ic:[ Op_arrayfor_incr | ib ]
+ * ic:[ Op_arrayfor_incr | ib ]
* [ Op_var_assign if any ]
*
* body
@@ -2483,7 +2658,7 @@ regular_loop:
} /* else
$1 is NULL */
- /* add update_FOO instruction if necessary */
+ /* add update_FOO instruction if necessary */
if ((yyvsp[-4])->array_var->type == Node_var && (yyvsp[-4])->array_var->var_update) {
(void) list_append(ip, instruction(Op_var_update));
ip->lasti->update_var = (yyvsp[-4])->array_var->var_update;
@@ -2499,7 +2674,7 @@ regular_loop:
if (do_pretty_print) {
(void) list_append(ip, instruction(Op_exec_count));
((yyvsp[-7]) + 1)->forloop_cond = (yyvsp[-4]);
- ((yyvsp[-7]) + 1)->forloop_body = ip->lasti;
+ ((yyvsp[-7]) + 1)->forloop_body = ip->lasti;
}
if ((yyvsp[0]) != NULL)
@@ -2509,75 +2684,78 @@ regular_loop:
ip->lasti->target_jmp = (yyvsp[-4]);
(yyval) = list_append(ip, tbreak);
fix_break_continue(ip, tbreak, tcont);
- }
+ }
break_allowed--;
continue_allowed--;
}
-#line 2518 "awkgram.c" /* yacc.c:1646 */
+#line 2693 "awkgram.c" /* yacc.c:1646 */
break;
- case 49:
-#line 766 "awkgram.y" /* yacc.c:1646 */
+ case 51:
+#line 905 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_for_loop((yyvsp[-11]), (yyvsp[-9]), (yyvsp[-6]), (yyvsp[-3]), (yyvsp[0]));
break_allowed--;
continue_allowed--;
}
-#line 2529 "awkgram.c" /* yacc.c:1646 */
+#line 2704 "awkgram.c" /* yacc.c:1646 */
break;
- case 50:
-#line 773 "awkgram.y" /* yacc.c:1646 */
+ case 52:
+#line 912 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_for_loop((yyvsp[-10]), (yyvsp[-8]), (INSTRUCTION *) NULL, (yyvsp[-3]), (yyvsp[0]));
break_allowed--;
continue_allowed--;
}
-#line 2540 "awkgram.c" /* yacc.c:1646 */
+#line 2715 "awkgram.c" /* yacc.c:1646 */
break;
- case 51:
-#line 780 "awkgram.y" /* yacc.c:1646 */
+ case 53:
+#line 919 "awkgram.y" /* yacc.c:1646 */
{
if (do_pretty_print)
(yyval) = list_prepend((yyvsp[0]), instruction(Op_exec_count));
else
(yyval) = (yyvsp[0]);
+ (yyval) = add_pending_comment((yyval));
}
-#line 2551 "awkgram.c" /* yacc.c:1646 */
+#line 2727 "awkgram.c" /* yacc.c:1646 */
break;
- case 52:
-#line 790 "awkgram.y" /* yacc.c:1646 */
- {
+ case 54:
+#line 930 "awkgram.y" /* yacc.c:1646 */
+ {
if (! break_allowed)
error_ln((yyvsp[-1])->source_line,
_("`break' is not allowed outside a loop or switch"));
(yyvsp[-1])->target_jmp = NULL;
(yyval) = list_create((yyvsp[-1]));
+ (yyval) = add_pending_comment((yyval));
}
-#line 2564 "awkgram.c" /* yacc.c:1646 */
+#line 2741 "awkgram.c" /* yacc.c:1646 */
break;
- case 53:
-#line 799 "awkgram.y" /* yacc.c:1646 */
+ case 55:
+#line 940 "awkgram.y" /* yacc.c:1646 */
{
if (! continue_allowed)
error_ln((yyvsp[-1])->source_line,
_("`continue' is not allowed outside a loop"));
(yyvsp[-1])->target_jmp = NULL;
(yyval) = list_create((yyvsp[-1]));
+ (yyval) = add_pending_comment((yyval));
}
-#line 2577 "awkgram.c" /* yacc.c:1646 */
+#line 2755 "awkgram.c" /* yacc.c:1646 */
break;
- case 54:
-#line 808 "awkgram.y" /* yacc.c:1646 */
+ case 56:
+#line 950 "awkgram.y" /* yacc.c:1646 */
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule && rule != Rule)
@@ -2585,12 +2763,13 @@ regular_loop:
_("`next' used in %s action"), ruletab[rule]);
(yyvsp[-1])->target_jmp = ip_rec;
(yyval) = list_create((yyvsp[-1]));
+ (yyval) = add_pending_comment((yyval));
}
-#line 2590 "awkgram.c" /* yacc.c:1646 */
+#line 2769 "awkgram.c" /* yacc.c:1646 */
break;
- case 55:
-#line 817 "awkgram.y" /* yacc.c:1646 */
+ case 57:
+#line 960 "awkgram.y" /* yacc.c:1646 */
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule == BEGIN || rule == END || rule == ENDFILE)
@@ -2600,15 +2779,16 @@ regular_loop:
(yyvsp[-1])->target_newfile = ip_newfile;
(yyvsp[-1])->target_endfile = ip_endfile;
(yyval) = list_create((yyvsp[-1]));
+ (yyval) = add_pending_comment((yyval));
}
-#line 2605 "awkgram.c" /* yacc.c:1646 */
+#line 2785 "awkgram.c" /* yacc.c:1646 */
break;
- case 56:
-#line 828 "awkgram.y" /* yacc.c:1646 */
+ case 58:
+#line 972 "awkgram.y" /* yacc.c:1646 */
{
/* Initialize the two possible jump targets, the actual target
- * is resolved at run-time.
+ * is resolved at run-time.
*/
(yyvsp[-2])->target_end = ip_end; /* first instruction in end_block */
(yyvsp[-2])->target_atexit = ip_atexit; /* cleanup and go home */
@@ -2619,21 +2799,22 @@ regular_loop:
(yyval)->nexti->memory = dupnode(Nnull_string);
} else
(yyval) = list_append((yyvsp[-1]), (yyvsp[-2]));
+ (yyval) = add_pending_comment((yyval));
}
-#line 2624 "awkgram.c" /* yacc.c:1646 */
+#line 2805 "awkgram.c" /* yacc.c:1646 */
break;
- case 57:
-#line 843 "awkgram.y" /* yacc.c:1646 */
+ case 59:
+#line 988 "awkgram.y" /* yacc.c:1646 */
{
if (! in_function)
yyerror(_("`return' used outside function context"));
}
-#line 2633 "awkgram.c" /* yacc.c:1646 */
+#line 2814 "awkgram.c" /* yacc.c:1646 */
break;
- case 58:
-#line 846 "awkgram.y" /* yacc.c:1646 */
+ case 60:
+#line 991 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-1]) == NULL) {
(yyval) = list_create((yyvsp[-3]));
@@ -2653,18 +2834,19 @@ regular_loop:
(yyval) = list_append((yyvsp[-1]), (yyvsp[-3]));
}
+ (yyval) = add_pending_comment((yyval));
}
-#line 2658 "awkgram.c" /* yacc.c:1646 */
+#line 2840 "awkgram.c" /* yacc.c:1646 */
break;
- case 60:
-#line 878 "awkgram.y" /* yacc.c:1646 */
+ case 62:
+#line 1024 "awkgram.y" /* yacc.c:1646 */
{ in_print = true; in_parens = 0; }
-#line 2664 "awkgram.c" /* yacc.c:1646 */
+#line 2846 "awkgram.c" /* yacc.c:1646 */
break;
- case 61:
-#line 879 "awkgram.y" /* yacc.c:1646 */
+ case 63:
+#line 1025 "awkgram.y" /* yacc.c:1646 */
{
/*
* Optimization: plain `print' has no expression list, so $3 is null.
@@ -2732,7 +2914,7 @@ regular_loop:
* [$1 | NULL | redir_type | expr_count]
*
*/
-regular_print:
+regular_print:
if ((yyvsp[0]) == NULL) { /* no redirection */
if ((yyvsp[-1]) == NULL) { /* printf without arg */
(yyvsp[-3])->expr_count = 0;
@@ -2760,18 +2942,19 @@ regular_print:
}
}
}
+ (yyval) = add_pending_comment((yyval));
}
-#line 2765 "awkgram.c" /* yacc.c:1646 */
+#line 2948 "awkgram.c" /* yacc.c:1646 */
break;
- case 62:
-#line 976 "awkgram.y" /* yacc.c:1646 */
+ case 64:
+#line 1123 "awkgram.y" /* yacc.c:1646 */
{ sub_counter = 0; }
-#line 2771 "awkgram.c" /* yacc.c:1646 */
+#line 2954 "awkgram.c" /* yacc.c:1646 */
break;
- case 63:
-#line 977 "awkgram.y" /* yacc.c:1646 */
+ case 65:
+#line 1124 "awkgram.y" /* yacc.c:1646 */
{
char *arr = (yyvsp[-2])->lextok;
@@ -2803,12 +2986,13 @@ regular_print:
(yyvsp[-3])->expr_count = sub_counter;
(yyval) = list_append(list_append((yyvsp[0]), (yyvsp[-2])), (yyvsp[-3]));
}
+ (yyval) = add_pending_comment((yyval));
}
-#line 2808 "awkgram.c" /* yacc.c:1646 */
+#line 2992 "awkgram.c" /* yacc.c:1646 */
break;
- case 64:
-#line 1014 "awkgram.y" /* yacc.c:1646 */
+ case 66:
+#line 1162 "awkgram.y" /* yacc.c:1646 */
{
static bool warned = false;
char *arr = (yyvsp[-1])->lextok;
@@ -2833,57 +3017,61 @@ regular_print:
else if ((yyvsp[-1])->memory == func_table)
fatal(_("`delete' is not allowed with FUNCTAB"));
}
+ (yyval) = add_pending_comment((yyval));
}
-#line 2838 "awkgram.c" /* yacc.c:1646 */
+#line 3023 "awkgram.c" /* yacc.c:1646 */
break;
- case 65:
-#line 1040 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = optimize_assignment((yyvsp[0])); }
-#line 2844 "awkgram.c" /* yacc.c:1646 */
+ case 67:
+#line 1189 "awkgram.y" /* yacc.c:1646 */
+ {
+ (yyval) = optimize_assignment((yyvsp[0]));
+ (yyval) = add_pending_comment((yyval));
+ }
+#line 3032 "awkgram.c" /* yacc.c:1646 */
break;
- case 66:
-#line 1045 "awkgram.y" /* yacc.c:1646 */
+ case 68:
+#line 1197 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2850 "awkgram.c" /* yacc.c:1646 */
+#line 3038 "awkgram.c" /* yacc.c:1646 */
break;
- case 67:
-#line 1047 "awkgram.y" /* yacc.c:1646 */
+ case 69:
+#line 1199 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2856 "awkgram.c" /* yacc.c:1646 */
+#line 3044 "awkgram.c" /* yacc.c:1646 */
break;
- case 68:
-#line 1052 "awkgram.y" /* yacc.c:1646 */
+ case 70:
+#line 1204 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2862 "awkgram.c" /* yacc.c:1646 */
+#line 3050 "awkgram.c" /* yacc.c:1646 */
break;
- case 69:
-#line 1054 "awkgram.y" /* yacc.c:1646 */
+ case 71:
+#line 1206 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-1]) == NULL)
(yyval) = list_create((yyvsp[0]));
else
(yyval) = list_prepend((yyvsp[-1]), (yyvsp[0]));
}
-#line 2873 "awkgram.c" /* yacc.c:1646 */
+#line 3061 "awkgram.c" /* yacc.c:1646 */
break;
- case 70:
-#line 1061 "awkgram.y" /* yacc.c:1646 */
+ case 72:
+#line 1213 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 2879 "awkgram.c" /* yacc.c:1646 */
+#line 3067 "awkgram.c" /* yacc.c:1646 */
break;
- case 71:
-#line 1066 "awkgram.y" /* yacc.c:1646 */
+ case 73:
+#line 1218 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *casestmt = (yyvsp[0]);
if ((yyvsp[0]) == NULL)
- casestmt = list_create(instruction(Op_no_op));
+ casestmt = list_create(instruction(Op_no_op));
if (do_pretty_print)
(void) list_prepend(casestmt, instruction(Op_exec_count));
(yyvsp[-4])->case_exp = (yyvsp[-3]);
@@ -2891,11 +3079,11 @@ regular_print:
bcfree((yyvsp[-2]));
(yyval) = (yyvsp[-4]);
}
-#line 2895 "awkgram.c" /* yacc.c:1646 */
+#line 3083 "awkgram.c" /* yacc.c:1646 */
break;
- case 72:
-#line 1078 "awkgram.y" /* yacc.c:1646 */
+ case 74:
+#line 1230 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *casestmt = (yyvsp[0]);
if ((yyvsp[0]) == NULL)
@@ -2906,89 +3094,104 @@ regular_print:
(yyvsp[-3])->case_stmt = casestmt;
(yyval) = (yyvsp[-3]);
}
-#line 2910 "awkgram.c" /* yacc.c:1646 */
+#line 3098 "awkgram.c" /* yacc.c:1646 */
break;
- case 73:
-#line 1092 "awkgram.y" /* yacc.c:1646 */
+ case 75:
+#line 1244 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2916 "awkgram.c" /* yacc.c:1646 */
+#line 3104 "awkgram.c" /* yacc.c:1646 */
break;
- case 74:
-#line 1094 "awkgram.y" /* yacc.c:1646 */
- {
+ case 76:
+#line 1246 "awkgram.y" /* yacc.c:1646 */
+ {
NODE *n = (yyvsp[0])->memory;
(void) force_number(n);
negate_num(n);
bcfree((yyvsp[-1]));
(yyval) = (yyvsp[0]);
}
-#line 2928 "awkgram.c" /* yacc.c:1646 */
+#line 3116 "awkgram.c" /* yacc.c:1646 */
break;
- case 75:
-#line 1102 "awkgram.y" /* yacc.c:1646 */
+ case 77:
+#line 1254 "awkgram.y" /* yacc.c:1646 */
{
+ NODE *n = (yyvsp[0])->lasti->memory;
bcfree((yyvsp[-1]));
+ add_sign_to_num(n, '+');
(yyval) = (yyvsp[0]);
}
-#line 2937 "awkgram.c" /* yacc.c:1646 */
+#line 3127 "awkgram.c" /* yacc.c:1646 */
break;
- case 76:
-#line 1107 "awkgram.y" /* yacc.c:1646 */
+ case 78:
+#line 1261 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2943 "awkgram.c" /* yacc.c:1646 */
+#line 3133 "awkgram.c" /* yacc.c:1646 */
break;
- case 77:
-#line 1109 "awkgram.y" /* yacc.c:1646 */
+ case 79:
+#line 1263 "awkgram.y" /* yacc.c:1646 */
{
+ if ((yyvsp[0])->memory->type == Node_regex)
+ (yyvsp[0])->opcode = Op_push_re;
+ else
+ (yyvsp[0])->opcode = Op_push;
+ (yyval) = (yyvsp[0]);
+ }
+#line 3145 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 80:
+#line 1271 "awkgram.y" /* yacc.c:1646 */
+ {
+ assert(((yyvsp[0])->memory->flags & REGEX) == REGEX);
(yyvsp[0])->opcode = Op_push_re;
(yyval) = (yyvsp[0]);
}
-#line 2952 "awkgram.c" /* yacc.c:1646 */
+#line 3155 "awkgram.c" /* yacc.c:1646 */
break;
- case 78:
-#line 1117 "awkgram.y" /* yacc.c:1646 */
+ case 81:
+#line 1280 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2958 "awkgram.c" /* yacc.c:1646 */
+#line 3161 "awkgram.c" /* yacc.c:1646 */
break;
- case 79:
-#line 1119 "awkgram.y" /* yacc.c:1646 */
+ case 82:
+#line 1282 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 2964 "awkgram.c" /* yacc.c:1646 */
+#line 3167 "awkgram.c" /* yacc.c:1646 */
break;
- case 81:
-#line 1129 "awkgram.y" /* yacc.c:1646 */
+ case 84:
+#line 1292 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = (yyvsp[-1]);
}
-#line 2972 "awkgram.c" /* yacc.c:1646 */
+#line 3175 "awkgram.c" /* yacc.c:1646 */
break;
- case 82:
-#line 1136 "awkgram.y" /* yacc.c:1646 */
+ case 85:
+#line 1299 "awkgram.y" /* yacc.c:1646 */
{
in_print = false;
in_parens = 0;
(yyval) = NULL;
}
-#line 2982 "awkgram.c" /* yacc.c:1646 */
+#line 3185 "awkgram.c" /* yacc.c:1646 */
break;
- case 83:
-#line 1141 "awkgram.y" /* yacc.c:1646 */
+ case 86:
+#line 1304 "awkgram.y" /* yacc.c:1646 */
{ in_print = false; in_parens = 0; }
-#line 2988 "awkgram.c" /* yacc.c:1646 */
+#line 3191 "awkgram.c" /* yacc.c:1646 */
break;
- case 84:
-#line 1142 "awkgram.y" /* yacc.c:1646 */
+ case 87:
+#line 1305 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-2])->redir_type == redirect_twoway
&& (yyvsp[0])->lasti->opcode == Op_K_getline_redir
@@ -2996,63 +3199,63 @@ regular_print:
yyerror(_("multistage two-way pipelines don't work"));
(yyval) = list_prepend((yyvsp[0]), (yyvsp[-2]));
}
-#line 3000 "awkgram.c" /* yacc.c:1646 */
+#line 3203 "awkgram.c" /* yacc.c:1646 */
break;
- case 85:
-#line 1153 "awkgram.y" /* yacc.c:1646 */
+ case 88:
+#line 1316 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_condition((yyvsp[-3]), (yyvsp[-5]), (yyvsp[0]), NULL, NULL);
}
-#line 3008 "awkgram.c" /* yacc.c:1646 */
+#line 3211 "awkgram.c" /* yacc.c:1646 */
break;
- case 86:
-#line 1158 "awkgram.y" /* yacc.c:1646 */
+ case 89:
+#line 1321 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_condition((yyvsp[-6]), (yyvsp[-8]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[0]));
}
-#line 3016 "awkgram.c" /* yacc.c:1646 */
+#line 3219 "awkgram.c" /* yacc.c:1646 */
break;
- case 91:
-#line 1175 "awkgram.y" /* yacc.c:1646 */
+ case 94:
+#line 1338 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3022 "awkgram.c" /* yacc.c:1646 */
+#line 3225 "awkgram.c" /* yacc.c:1646 */
break;
- case 92:
-#line 1177 "awkgram.y" /* yacc.c:1646 */
+ case 95:
+#line 1340 "awkgram.y" /* yacc.c:1646 */
{
bcfree((yyvsp[-1]));
(yyval) = (yyvsp[0]);
}
-#line 3031 "awkgram.c" /* yacc.c:1646 */
+#line 3234 "awkgram.c" /* yacc.c:1646 */
break;
- case 93:
-#line 1185 "awkgram.y" /* yacc.c:1646 */
+ case 96:
+#line 1348 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3037 "awkgram.c" /* yacc.c:1646 */
+#line 3240 "awkgram.c" /* yacc.c:1646 */
break;
- case 94:
-#line 1187 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = (yyvsp[0]) ; }
-#line 3043 "awkgram.c" /* yacc.c:1646 */
+ case 97:
+#line 1350 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = (yyvsp[0]); }
+#line 3246 "awkgram.c" /* yacc.c:1646 */
break;
- case 95:
-#line 1192 "awkgram.y" /* yacc.c:1646 */
+ case 98:
+#line 1355 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->param_count = 0;
(yyval) = list_create((yyvsp[0]));
}
-#line 3052 "awkgram.c" /* yacc.c:1646 */
+#line 3255 "awkgram.c" /* yacc.c:1646 */
break;
- case 96:
-#line 1197 "awkgram.y" /* yacc.c:1646 */
+ case 99:
+#line 1360 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-2]) != NULL && (yyvsp[0]) != NULL) {
(yyvsp[0])->param_count = (yyvsp[-2])->lasti->param_count + 1;
@@ -3061,74 +3264,74 @@ regular_print:
} else
(yyval) = NULL;
}
-#line 3065 "awkgram.c" /* yacc.c:1646 */
+#line 3268 "awkgram.c" /* yacc.c:1646 */
break;
- case 97:
-#line 1206 "awkgram.y" /* yacc.c:1646 */
+ case 100:
+#line 1369 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3071 "awkgram.c" /* yacc.c:1646 */
+#line 3274 "awkgram.c" /* yacc.c:1646 */
break;
- case 98:
-#line 1208 "awkgram.y" /* yacc.c:1646 */
+ case 101:
+#line 1371 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3077 "awkgram.c" /* yacc.c:1646 */
+#line 3280 "awkgram.c" /* yacc.c:1646 */
break;
- case 99:
-#line 1210 "awkgram.y" /* yacc.c:1646 */
+ case 102:
+#line 1373 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-2]); }
-#line 3083 "awkgram.c" /* yacc.c:1646 */
+#line 3286 "awkgram.c" /* yacc.c:1646 */
break;
- case 100:
-#line 1216 "awkgram.y" /* yacc.c:1646 */
+ case 103:
+#line 1379 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3089 "awkgram.c" /* yacc.c:1646 */
+#line 3292 "awkgram.c" /* yacc.c:1646 */
break;
- case 101:
-#line 1218 "awkgram.y" /* yacc.c:1646 */
+ case 104:
+#line 1381 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3095 "awkgram.c" /* yacc.c:1646 */
+#line 3298 "awkgram.c" /* yacc.c:1646 */
break;
- case 102:
-#line 1223 "awkgram.y" /* yacc.c:1646 */
+ case 105:
+#line 1386 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3101 "awkgram.c" /* yacc.c:1646 */
+#line 3304 "awkgram.c" /* yacc.c:1646 */
break;
- case 103:
-#line 1225 "awkgram.y" /* yacc.c:1646 */
+ case 106:
+#line 1388 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3107 "awkgram.c" /* yacc.c:1646 */
+#line 3310 "awkgram.c" /* yacc.c:1646 */
break;
- case 104:
-#line 1230 "awkgram.y" /* yacc.c:1646 */
+ case 107:
+#line 1393 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_expression_list(NULL, (yyvsp[0])); }
-#line 3113 "awkgram.c" /* yacc.c:1646 */
+#line 3316 "awkgram.c" /* yacc.c:1646 */
break;
- case 105:
-#line 1232 "awkgram.y" /* yacc.c:1646 */
+ case 108:
+#line 1395 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0]));
yyerrok;
}
-#line 3122 "awkgram.c" /* yacc.c:1646 */
+#line 3325 "awkgram.c" /* yacc.c:1646 */
break;
- case 106:
-#line 1237 "awkgram.y" /* yacc.c:1646 */
+ case 109:
+#line 1400 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3128 "awkgram.c" /* yacc.c:1646 */
+#line 3331 "awkgram.c" /* yacc.c:1646 */
break;
- case 107:
-#line 1239 "awkgram.y" /* yacc.c:1646 */
+ case 110:
+#line 1402 "awkgram.y" /* yacc.c:1646 */
{
/*
* Returning the expression list instead of NULL lets
@@ -3136,58 +3339,159 @@ regular_print:
*/
(yyval) = (yyvsp[-1]);
}
-#line 3140 "awkgram.c" /* yacc.c:1646 */
+#line 3343 "awkgram.c" /* yacc.c:1646 */
break;
- case 108:
-#line 1247 "awkgram.y" /* yacc.c:1646 */
+ case 111:
+#line 1410 "awkgram.y" /* yacc.c:1646 */
{
/* Ditto */
(yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0]));
}
-#line 3149 "awkgram.c" /* yacc.c:1646 */
+#line 3352 "awkgram.c" /* yacc.c:1646 */
break;
- case 109:
-#line 1252 "awkgram.y" /* yacc.c:1646 */
+ case 112:
+#line 1415 "awkgram.y" /* yacc.c:1646 */
{
/* Ditto */
(yyval) = (yyvsp[-2]);
}
-#line 3158 "awkgram.c" /* yacc.c:1646 */
+#line 3361 "awkgram.c" /* yacc.c:1646 */
break;
- case 110:
-#line 1261 "awkgram.y" /* yacc.c:1646 */
+ case 113:
+#line 1423 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = NULL; }
+#line 3367 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 114:
+#line 1425 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = (yyvsp[0]); }
+#line 3373 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 115:
+#line 1430 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = mk_expression_list(NULL, (yyvsp[0])); }
+#line 3379 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 116:
+#line 1432 "awkgram.y" /* yacc.c:1646 */
+ {
+ (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0]));
+ yyerrok;
+ }
+#line 3388 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 117:
+#line 1437 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = NULL; }
+#line 3394 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 118:
+#line 1439 "awkgram.y" /* yacc.c:1646 */
+ {
+ /*
+ * Returning the expression list instead of NULL lets
+ * snode get a list of arguments that it can count.
+ */
+ (yyval) = (yyvsp[-1]);
+ }
+#line 3406 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 119:
+#line 1447 "awkgram.y" /* yacc.c:1646 */
+ {
+ /* Ditto */
+ (yyval) = mk_expression_list((yyvsp[-2]), (yyvsp[0]));
+ }
+#line 3415 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 120:
+#line 1452 "awkgram.y" /* yacc.c:1646 */
+ {
+ /* Ditto */
+ (yyval) = (yyvsp[-2]);
+ }
+#line 3424 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 121:
+#line 1459 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = (yyvsp[0]); }
+#line 3430 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 122:
+#line 1460 "awkgram.y" /* yacc.c:1646 */
+ { (yyval) = list_create((yyvsp[0])); }
+#line 3436 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 123:
+#line 1466 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint && (yyvsp[0])->lasti->opcode == Op_match_rec)
lintwarn_ln((yyvsp[-1])->source_line,
_("regular expression on right of assignment"));
(yyval) = mk_assignment((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1]));
}
-#line 3169 "awkgram.c" /* yacc.c:1646 */
+#line 3447 "awkgram.c" /* yacc.c:1646 */
break;
- case 111:
-#line 1268 "awkgram.y" /* yacc.c:1646 */
+ case 124:
+#line 1473 "awkgram.y" /* yacc.c:1646 */
+ {
+ (yyval) = mk_assignment((yyvsp[-2]), list_create((yyvsp[0])), (yyvsp[-1]));
+ }
+#line 3455 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 125:
+#line 1477 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3175 "awkgram.c" /* yacc.c:1646 */
+#line 3461 "awkgram.c" /* yacc.c:1646 */
break;
- case 112:
-#line 1270 "awkgram.y" /* yacc.c:1646 */
+ case 126:
+#line 1479 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_boolean((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3181 "awkgram.c" /* yacc.c:1646 */
+#line 3467 "awkgram.c" /* yacc.c:1646 */
break;
- case 113:
-#line 1272 "awkgram.y" /* yacc.c:1646 */
+ case 127:
+#line 1481 "awkgram.y" /* yacc.c:1646 */
+ {
+ if ((yyvsp[-2])->lasti->opcode == Op_match_rec)
+ warning_ln((yyvsp[-1])->source_line,
+ _("regular expression on left of `~' or `!~' operator"));
+
+ assert((yyvsp[0])->opcode == Op_push_re
+ && ((yyvsp[0])->memory->flags & REGEX) != 0);
+ /* RHS is @/.../ */
+ (yyvsp[-1])->memory = (yyvsp[0])->memory;
+ bcfree((yyvsp[0]));
+ (yyval) = list_append((yyvsp[-2]), (yyvsp[-1]));
+ }
+#line 3484 "awkgram.c" /* yacc.c:1646 */
+ break;
+
+ case 128:
+#line 1494 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[-2])->lasti->opcode == Op_match_rec)
warning_ln((yyvsp[-1])->source_line,
_("regular expression on left of `~' or `!~' operator"));
if ((yyvsp[0])->lasti == (yyvsp[0])->nexti && (yyvsp[0])->nexti->opcode == Op_match_rec) {
+ /* RHS is /.../ */
(yyvsp[-1])->memory = (yyvsp[0])->nexti->memory;
bcfree((yyvsp[0])->nexti); /* Op_match_rec */
bcfree((yyvsp[0])); /* Op_list */
@@ -3197,11 +3501,11 @@ regular_print:
(yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1]));
}
}
-#line 3201 "awkgram.c" /* yacc.c:1646 */
+#line 3505 "awkgram.c" /* yacc.c:1646 */
break;
- case 114:
-#line 1288 "awkgram.y" /* yacc.c:1646 */
+ case 129:
+#line 1511 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint_old)
warning_ln((yyvsp[-1])->source_line,
@@ -3211,91 +3515,91 @@ regular_print:
(yyvsp[-1])->expr_count = 1;
(yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1]));
}
-#line 3215 "awkgram.c" /* yacc.c:1646 */
+#line 3519 "awkgram.c" /* yacc.c:1646 */
break;
- case 115:
-#line 1298 "awkgram.y" /* yacc.c:1646 */
+ case 130:
+#line 1521 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint && (yyvsp[0])->lasti->opcode == Op_match_rec)
lintwarn_ln((yyvsp[-1])->source_line,
_("regular expression on right of comparison"));
(yyval) = list_append(list_merge((yyvsp[-2]), (yyvsp[0])), (yyvsp[-1]));
}
-#line 3226 "awkgram.c" /* yacc.c:1646 */
+#line 3530 "awkgram.c" /* yacc.c:1646 */
break;
- case 116:
-#line 1305 "awkgram.y" /* yacc.c:1646 */
+ case 131:
+#line 1528 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_condition((yyvsp[-4]), (yyvsp[-3]), (yyvsp[-2]), (yyvsp[-1]), (yyvsp[0])); }
-#line 3232 "awkgram.c" /* yacc.c:1646 */
+#line 3536 "awkgram.c" /* yacc.c:1646 */
break;
- case 117:
-#line 1307 "awkgram.y" /* yacc.c:1646 */
+ case 132:
+#line 1530 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3238 "awkgram.c" /* yacc.c:1646 */
+#line 3542 "awkgram.c" /* yacc.c:1646 */
break;
- case 118:
-#line 1312 "awkgram.y" /* yacc.c:1646 */
+ case 133:
+#line 1535 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3244 "awkgram.c" /* yacc.c:1646 */
+#line 3548 "awkgram.c" /* yacc.c:1646 */
break;
- case 119:
-#line 1314 "awkgram.y" /* yacc.c:1646 */
+ case 134:
+#line 1537 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3250 "awkgram.c" /* yacc.c:1646 */
+#line 3554 "awkgram.c" /* yacc.c:1646 */
break;
- case 120:
-#line 1316 "awkgram.y" /* yacc.c:1646 */
- {
+ case 135:
+#line 1539 "awkgram.y" /* yacc.c:1646 */
+ {
(yyvsp[0])->opcode = Op_assign_quotient;
(yyval) = (yyvsp[0]);
}
-#line 3259 "awkgram.c" /* yacc.c:1646 */
+#line 3563 "awkgram.c" /* yacc.c:1646 */
break;
- case 121:
-#line 1324 "awkgram.y" /* yacc.c:1646 */
+ case 136:
+#line 1547 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3265 "awkgram.c" /* yacc.c:1646 */
+#line 3569 "awkgram.c" /* yacc.c:1646 */
break;
- case 122:
-#line 1326 "awkgram.y" /* yacc.c:1646 */
+ case 137:
+#line 1549 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3271 "awkgram.c" /* yacc.c:1646 */
+#line 3575 "awkgram.c" /* yacc.c:1646 */
break;
- case 123:
-#line 1331 "awkgram.y" /* yacc.c:1646 */
+ case 138:
+#line 1554 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3277 "awkgram.c" /* yacc.c:1646 */
+#line 3581 "awkgram.c" /* yacc.c:1646 */
break;
- case 124:
-#line 1333 "awkgram.y" /* yacc.c:1646 */
+ case 139:
+#line 1556 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3283 "awkgram.c" /* yacc.c:1646 */
+#line 3587 "awkgram.c" /* yacc.c:1646 */
break;
- case 125:
-#line 1338 "awkgram.y" /* yacc.c:1646 */
+ case 140:
+#line 1561 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3289 "awkgram.c" /* yacc.c:1646 */
+#line 3593 "awkgram.c" /* yacc.c:1646 */
break;
- case 126:
-#line 1340 "awkgram.y" /* yacc.c:1646 */
+ case 141:
+#line 1563 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3295 "awkgram.c" /* yacc.c:1646 */
+#line 3599 "awkgram.c" /* yacc.c:1646 */
break;
- case 127:
-#line 1342 "awkgram.y" /* yacc.c:1646 */
+ case 142:
+#line 1565 "awkgram.y" /* yacc.c:1646 */
{
int count = 2;
bool is_simple_var = false;
@@ -3321,10 +3625,15 @@ regular_print:
NODE *n2 = (yyvsp[0])->nexti->memory;
size_t nlen;
+ // 1.5 "" # can't fold this if program mucks with CONVFMT.
+ // See test #12 in test/posix.awk.
+ if ((n1->flags & (NUMBER|NUMINT)) != 0 || (n2->flags & (NUMBER|NUMINT)) != 0)
+ goto plain_concat;
+
n1 = force_string(n1);
n2 = force_string(n2);
nlen = n1->stlen + n2->stlen;
- erealloc(n1->stptr, char *, nlen + 2, "constant fold");
+ erealloc(n1->stptr, char *, nlen + 1, "constant fold");
memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
n1->stlen = nlen;
n1->stptr[nlen] = '\0';
@@ -3335,6 +3644,7 @@ regular_print:
bcfree((yyvsp[0]));
(yyval) = (yyvsp[-1]);
} else {
+ plain_concat:
(yyval) = list_append(list_merge((yyvsp[-1]), (yyvsp[0])), instruction(Op_concat));
(yyval)->lasti->concat_flag = (is_simple_var ? CSVAR : 0);
(yyval)->lasti->expr_count = count;
@@ -3342,47 +3652,47 @@ regular_print:
max_args = count;
}
}
-#line 3346 "awkgram.c" /* yacc.c:1646 */
+#line 3656 "awkgram.c" /* yacc.c:1646 */
break;
- case 129:
-#line 1394 "awkgram.y" /* yacc.c:1646 */
+ case 144:
+#line 1623 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3352 "awkgram.c" /* yacc.c:1646 */
+#line 3662 "awkgram.c" /* yacc.c:1646 */
break;
- case 130:
-#line 1396 "awkgram.y" /* yacc.c:1646 */
+ case 145:
+#line 1625 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3358 "awkgram.c" /* yacc.c:1646 */
+#line 3668 "awkgram.c" /* yacc.c:1646 */
break;
- case 131:
-#line 1398 "awkgram.y" /* yacc.c:1646 */
+ case 146:
+#line 1627 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3364 "awkgram.c" /* yacc.c:1646 */
+#line 3674 "awkgram.c" /* yacc.c:1646 */
break;
- case 132:
-#line 1400 "awkgram.y" /* yacc.c:1646 */
+ case 147:
+#line 1629 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3370 "awkgram.c" /* yacc.c:1646 */
+#line 3680 "awkgram.c" /* yacc.c:1646 */
break;
- case 133:
-#line 1402 "awkgram.y" /* yacc.c:1646 */
+ case 148:
+#line 1631 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3376 "awkgram.c" /* yacc.c:1646 */
+#line 3686 "awkgram.c" /* yacc.c:1646 */
break;
- case 134:
-#line 1404 "awkgram.y" /* yacc.c:1646 */
+ case 149:
+#line 1633 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3382 "awkgram.c" /* yacc.c:1646 */
+#line 3692 "awkgram.c" /* yacc.c:1646 */
break;
- case 135:
-#line 1406 "awkgram.y" /* yacc.c:1646 */
+ case 150:
+#line 1635 "awkgram.y" /* yacc.c:1646 */
{
/*
* In BEGINFILE/ENDFILE, allow `getline [var] < file'
@@ -3396,29 +3706,29 @@ regular_print:
_("non-redirected `getline' undefined inside END action"));
(yyval) = mk_getline((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), redirect_input);
}
-#line 3400 "awkgram.c" /* yacc.c:1646 */
+#line 3710 "awkgram.c" /* yacc.c:1646 */
break;
- case 136:
-#line 1420 "awkgram.y" /* yacc.c:1646 */
+ case 151:
+#line 1649 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postincrement;
(yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0]));
}
-#line 3409 "awkgram.c" /* yacc.c:1646 */
+#line 3719 "awkgram.c" /* yacc.c:1646 */
break;
- case 137:
-#line 1425 "awkgram.y" /* yacc.c:1646 */
+ case 152:
+#line 1654 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postdecrement;
(yyval) = mk_assignment((yyvsp[-1]), NULL, (yyvsp[0]));
}
-#line 3418 "awkgram.c" /* yacc.c:1646 */
+#line 3728 "awkgram.c" /* yacc.c:1646 */
break;
- case 138:
-#line 1430 "awkgram.y" /* yacc.c:1646 */
+ case 153:
+#line 1659 "awkgram.y" /* yacc.c:1646 */
{
if (do_lint_old) {
warning_ln((yyvsp[-1])->source_line,
@@ -3438,69 +3748,69 @@ regular_print:
(yyval) = list_append(list_merge(t, (yyvsp[0])), (yyvsp[-1]));
}
}
-#line 3442 "awkgram.c" /* yacc.c:1646 */
+#line 3752 "awkgram.c" /* yacc.c:1646 */
break;
- case 139:
-#line 1455 "awkgram.y" /* yacc.c:1646 */
+ case 154:
+#line 1684 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = mk_getline((yyvsp[-1]), (yyvsp[0]), (yyvsp[-3]), (yyvsp[-2])->redir_type);
bcfree((yyvsp[-2]));
}
-#line 3451 "awkgram.c" /* yacc.c:1646 */
+#line 3761 "awkgram.c" /* yacc.c:1646 */
break;
- case 140:
-#line 1461 "awkgram.y" /* yacc.c:1646 */
+ case 155:
+#line 1690 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3457 "awkgram.c" /* yacc.c:1646 */
+#line 3767 "awkgram.c" /* yacc.c:1646 */
break;
- case 141:
-#line 1463 "awkgram.y" /* yacc.c:1646 */
+ case 156:
+#line 1692 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3463 "awkgram.c" /* yacc.c:1646 */
+#line 3773 "awkgram.c" /* yacc.c:1646 */
break;
- case 142:
-#line 1465 "awkgram.y" /* yacc.c:1646 */
+ case 157:
+#line 1694 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3469 "awkgram.c" /* yacc.c:1646 */
+#line 3779 "awkgram.c" /* yacc.c:1646 */
break;
- case 143:
-#line 1467 "awkgram.y" /* yacc.c:1646 */
+ case 158:
+#line 1696 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3475 "awkgram.c" /* yacc.c:1646 */
+#line 3785 "awkgram.c" /* yacc.c:1646 */
break;
- case 144:
-#line 1469 "awkgram.y" /* yacc.c:1646 */
+ case 159:
+#line 1698 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3481 "awkgram.c" /* yacc.c:1646 */
+#line 3791 "awkgram.c" /* yacc.c:1646 */
break;
- case 145:
-#line 1471 "awkgram.y" /* yacc.c:1646 */
+ case 160:
+#line 1700 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = mk_binary((yyvsp[-2]), (yyvsp[0]), (yyvsp[-1])); }
-#line 3487 "awkgram.c" /* yacc.c:1646 */
+#line 3797 "awkgram.c" /* yacc.c:1646 */
break;
- case 146:
-#line 1476 "awkgram.y" /* yacc.c:1646 */
+ case 161:
+#line 1705 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_create((yyvsp[0]));
}
-#line 3495 "awkgram.c" /* yacc.c:1646 */
+#line 3805 "awkgram.c" /* yacc.c:1646 */
break;
- case 147:
-#line 1480 "awkgram.y" /* yacc.c:1646 */
+ case 162:
+#line 1709 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[0])->opcode == Op_match_rec) {
(yyvsp[0])->opcode = Op_nomatch;
(yyvsp[-1])->opcode = Op_push_i;
- (yyvsp[-1])->memory = make_number(0.0);
+ (yyvsp[-1])->memory = set_profile_text(make_number(0.0), "0", 1);
(yyval) = list_append(list_append(list_create((yyvsp[-1])),
instruction(Op_field_spec)), (yyvsp[0]));
} else {
@@ -3509,7 +3819,7 @@ regular_print:
&& ((yyvsp[0])->nexti->memory->flags & (MPFN|MPZN)) == 0
) {
NODE *n = (yyvsp[0])->nexti->memory;
- if ((n->flags & (STRCUR|STRING)) != 0) {
+ if ((n->flags & STRING) != 0) {
n->numbr = (AWKNUM) (n->stlen == 0);
n->flags &= ~(STRCUR|STRING);
n->flags |= (NUMCUR|NUMBER);
@@ -3527,37 +3837,42 @@ regular_print:
}
}
}
-#line 3531 "awkgram.c" /* yacc.c:1646 */
+#line 3841 "awkgram.c" /* yacc.c:1646 */
break;
- case 148:
-#line 1512 "awkgram.y" /* yacc.c:1646 */
- { (yyval) = (yyvsp[-1]); }
-#line 3537 "awkgram.c" /* yacc.c:1646 */
+ case 163:
+#line 1741 "awkgram.y" /* yacc.c:1646 */
+ {
+ if (do_pretty_print)
+ (yyval) = list_append((yyvsp[-1]), bcalloc(Op_parens, 1, sourceline));
+ else
+ (yyval) = (yyvsp[-1]);
+ }
+#line 3852 "awkgram.c" /* yacc.c:1646 */
break;
- case 149:
-#line 1514 "awkgram.y" /* yacc.c:1646 */
+ case 164:
+#line 1748 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = snode((yyvsp[-1]), (yyvsp[-3]));
if ((yyval) == NULL)
YYABORT;
}
-#line 3547 "awkgram.c" /* yacc.c:1646 */
+#line 3862 "awkgram.c" /* yacc.c:1646 */
break;
- case 150:
-#line 1520 "awkgram.y" /* yacc.c:1646 */
+ case 165:
+#line 1754 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = snode((yyvsp[-1]), (yyvsp[-3]));
if ((yyval) == NULL)
YYABORT;
}
-#line 3557 "awkgram.c" /* yacc.c:1646 */
+#line 3872 "awkgram.c" /* yacc.c:1646 */
break;
- case 151:
-#line 1526 "awkgram.y" /* yacc.c:1646 */
+ case 166:
+#line 1760 "awkgram.y" /* yacc.c:1646 */
{
static bool warned = false;
@@ -3570,52 +3885,52 @@ regular_print:
if ((yyval) == NULL)
YYABORT;
}
-#line 3574 "awkgram.c" /* yacc.c:1646 */
+#line 3889 "awkgram.c" /* yacc.c:1646 */
break;
- case 154:
-#line 1541 "awkgram.y" /* yacc.c:1646 */
+ case 169:
+#line 1775 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[-1])->opcode = Op_preincrement;
(yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1]));
}
-#line 3583 "awkgram.c" /* yacc.c:1646 */
+#line 3898 "awkgram.c" /* yacc.c:1646 */
break;
- case 155:
-#line 1546 "awkgram.y" /* yacc.c:1646 */
+ case 170:
+#line 1780 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[-1])->opcode = Op_predecrement;
(yyval) = mk_assignment((yyvsp[0]), NULL, (yyvsp[-1]));
}
-#line 3592 "awkgram.c" /* yacc.c:1646 */
+#line 3907 "awkgram.c" /* yacc.c:1646 */
break;
- case 156:
-#line 1551 "awkgram.y" /* yacc.c:1646 */
+ case 171:
+#line 1785 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_create((yyvsp[0]));
}
-#line 3600 "awkgram.c" /* yacc.c:1646 */
+#line 3915 "awkgram.c" /* yacc.c:1646 */
break;
- case 157:
-#line 1555 "awkgram.y" /* yacc.c:1646 */
+ case 172:
+#line 1789 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_create((yyvsp[0]));
}
-#line 3608 "awkgram.c" /* yacc.c:1646 */
+#line 3923 "awkgram.c" /* yacc.c:1646 */
break;
- case 158:
-#line 1559 "awkgram.y" /* yacc.c:1646 */
+ case 173:
+#line 1793 "awkgram.y" /* yacc.c:1646 */
{
if ((yyvsp[0])->lasti->opcode == Op_push_i
- && ((yyvsp[0])->lasti->memory->flags & (STRCUR|STRING)) == 0
+ && ((yyvsp[0])->lasti->memory->flags & STRING) == 0
) {
NODE *n = (yyvsp[0])->lasti->memory;
(void) force_number(n);
- negate_num(n);
+ negate_num(n);
(yyval) = (yyvsp[0]);
bcfree((yyvsp[-1]));
} else {
@@ -3623,34 +3938,42 @@ regular_print:
(yyval) = list_append((yyvsp[0]), (yyvsp[-1]));
}
}
-#line 3627 "awkgram.c" /* yacc.c:1646 */
+#line 3942 "awkgram.c" /* yacc.c:1646 */
break;
- case 159:
-#line 1574 "awkgram.y" /* yacc.c:1646 */
+ case 174:
+#line 1808 "awkgram.y" /* yacc.c:1646 */
{
- /*
- * was: $$ = $2
- * POSIX semantics: force a conversion to numeric type
- */
- (yyvsp[-1])->opcode = Op_plus_i;
- (yyvsp[-1])->memory = make_number(0.0);
- (yyval) = list_append((yyvsp[0]), (yyvsp[-1]));
+ if ((yyvsp[0])->lasti->opcode == Op_push_i
+ && ((yyvsp[0])->lasti->memory->flags & STRING) == 0
+ && ((yyvsp[0])->lasti->memory->flags & NUMCONSTSTR) != 0) {
+ NODE *n = (yyvsp[0])->lasti->memory;
+ add_sign_to_num(n, '+');
+ (yyval) = (yyvsp[0]);
+ bcfree((yyvsp[-1]));
+ } else {
+ /*
+ * was: $$ = $2
+ * POSIX semantics: force a conversion to numeric type
+ */
+ (yyvsp[-1])->opcode = Op_unary_plus;
+ (yyval) = list_append((yyvsp[0]), (yyvsp[-1]));
+ }
}
-#line 3641 "awkgram.c" /* yacc.c:1646 */
+#line 3964 "awkgram.c" /* yacc.c:1646 */
break;
- case 160:
-#line 1587 "awkgram.y" /* yacc.c:1646 */
+ case 175:
+#line 1829 "awkgram.y" /* yacc.c:1646 */
{
func_use((yyvsp[0])->lasti->func_name, FUNC_USE);
(yyval) = (yyvsp[0]);
}
-#line 3650 "awkgram.c" /* yacc.c:1646 */
+#line 3973 "awkgram.c" /* yacc.c:1646 */
break;
- case 161:
-#line 1592 "awkgram.y" /* yacc.c:1646 */
+ case 176:
+#line 1834 "awkgram.y" /* yacc.c:1646 */
{
/* indirect function call */
INSTRUCTION *f, *t;
@@ -3665,7 +3988,7 @@ regular_print:
warned = true;
lintwarn("%s", msg);
}
-
+
f = (yyvsp[0])->lasti;
f->opcode = Op_indirect_func_call;
name = estrdup(f->func_name, strlen(f->func_name));
@@ -3684,18 +4007,18 @@ regular_print:
(yyval) = list_prepend((yyvsp[0]), t);
at_seen = false;
}
-#line 3688 "awkgram.c" /* yacc.c:1646 */
+#line 4011 "awkgram.c" /* yacc.c:1646 */
break;
- case 162:
-#line 1629 "awkgram.y" /* yacc.c:1646 */
+ case 177:
+#line 1871 "awkgram.y" /* yacc.c:1646 */
{
NODE *n;
if (! at_seen) {
n = lookup((yyvsp[-3])->func_name);
if (n != NULL && n->type != Node_func
- && n->type != Node_ext_func && n->type != Node_old_ext_func) {
+ && n->type != Node_ext_func) {
error_ln((yyvsp[-3])->source_line,
_("attempt to use non-function `%s' in function call"),
(yyvsp[-3])->func_name);
@@ -3709,55 +4032,55 @@ regular_print:
(yyval) = list_create((yyvsp[-3]));
} else {
INSTRUCTION *t = (yyvsp[-1]);
- ((yyvsp[-3]) + 1)->expr_count = count_expressions(&t, true);
+ ((yyvsp[-3]) + 1)->expr_count = count_expressions(&t, true);
(yyval) = list_append(t, (yyvsp[-3]));
}
}
-#line 3717 "awkgram.c" /* yacc.c:1646 */
+#line 4040 "awkgram.c" /* yacc.c:1646 */
break;
- case 163:
-#line 1657 "awkgram.y" /* yacc.c:1646 */
+ case 178:
+#line 1899 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3723 "awkgram.c" /* yacc.c:1646 */
+#line 4046 "awkgram.c" /* yacc.c:1646 */
break;
- case 164:
-#line 1659 "awkgram.y" /* yacc.c:1646 */
+ case 179:
+#line 1901 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3729 "awkgram.c" /* yacc.c:1646 */
+#line 4052 "awkgram.c" /* yacc.c:1646 */
break;
- case 165:
-#line 1664 "awkgram.y" /* yacc.c:1646 */
+ case 180:
+#line 1906 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3735 "awkgram.c" /* yacc.c:1646 */
+#line 4058 "awkgram.c" /* yacc.c:1646 */
break;
- case 166:
-#line 1666 "awkgram.y" /* yacc.c:1646 */
+ case 181:
+#line 1908 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3741 "awkgram.c" /* yacc.c:1646 */
+#line 4064 "awkgram.c" /* yacc.c:1646 */
break;
- case 167:
-#line 1671 "awkgram.y" /* yacc.c:1646 */
+ case 182:
+#line 1913 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3747 "awkgram.c" /* yacc.c:1646 */
+#line 4070 "awkgram.c" /* yacc.c:1646 */
break;
- case 168:
-#line 1673 "awkgram.y" /* yacc.c:1646 */
+ case 183:
+#line 1915 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_merge((yyvsp[-1]), (yyvsp[0]));
}
-#line 3755 "awkgram.c" /* yacc.c:1646 */
+#line 4078 "awkgram.c" /* yacc.c:1646 */
break;
- case 169:
-#line 1680 "awkgram.y" /* yacc.c:1646 */
+ case 184:
+#line 1922 "awkgram.y" /* yacc.c:1646 */
{
- INSTRUCTION *ip = (yyvsp[0])->lasti;
+ INSTRUCTION *ip = (yyvsp[0])->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated expressions */
if (count > 1) {
/* change Op_subscript or Op_sub_array to Op_concat */
@@ -3769,11 +4092,11 @@ regular_print:
sub_counter++; /* count # of dimensions */
(yyval) = (yyvsp[0]);
}
-#line 3773 "awkgram.c" /* yacc.c:1646 */
+#line 4096 "awkgram.c" /* yacc.c:1646 */
break;
- case 170:
-#line 1697 "awkgram.y" /* yacc.c:1646 */
+ case 185:
+#line 1939 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *t = (yyvsp[-1]);
if ((yyvsp[-1]) == NULL) {
@@ -3782,36 +4105,36 @@ regular_print:
/* install Null string as subscript. */
t = list_create(instruction(Op_push_i));
t->nexti->memory = dupnode(Nnull_string);
- (yyvsp[0])->sub_count = 1;
+ (yyvsp[0])->sub_count = 1;
} else
(yyvsp[0])->sub_count = count_expressions(&t, false);
(yyval) = list_append(t, (yyvsp[0]));
}
-#line 3791 "awkgram.c" /* yacc.c:1646 */
+#line 4114 "awkgram.c" /* yacc.c:1646 */
break;
- case 171:
-#line 1714 "awkgram.y" /* yacc.c:1646 */
+ case 186:
+#line 1956 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); }
-#line 3797 "awkgram.c" /* yacc.c:1646 */
+#line 4120 "awkgram.c" /* yacc.c:1646 */
break;
- case 172:
-#line 1716 "awkgram.y" /* yacc.c:1646 */
+ case 187:
+#line 1958 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_merge((yyvsp[-1]), (yyvsp[0]));
}
-#line 3805 "awkgram.c" /* yacc.c:1646 */
+#line 4128 "awkgram.c" /* yacc.c:1646 */
break;
- case 173:
-#line 1723 "awkgram.y" /* yacc.c:1646 */
+ case 188:
+#line 1965 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[-1]); }
-#line 3811 "awkgram.c" /* yacc.c:1646 */
+#line 4134 "awkgram.c" /* yacc.c:1646 */
break;
- case 174:
-#line 1728 "awkgram.y" /* yacc.c:1646 */
+ case 189:
+#line 1970 "awkgram.y" /* yacc.c:1646 */
{
char *var_name = (yyvsp[0])->lextok;
@@ -3819,22 +4142,22 @@ regular_print:
(yyvsp[0])->memory = variable((yyvsp[0])->source_line, var_name, Node_var_new);
(yyval) = list_create((yyvsp[0]));
}
-#line 3823 "awkgram.c" /* yacc.c:1646 */
+#line 4146 "awkgram.c" /* yacc.c:1646 */
break;
- case 175:
-#line 1736 "awkgram.y" /* yacc.c:1646 */
+ case 190:
+#line 1978 "awkgram.y" /* yacc.c:1646 */
{
char *arr = (yyvsp[-1])->lextok;
(yyvsp[-1])->memory = variable((yyvsp[-1])->source_line, arr, Node_var_new);
(yyvsp[-1])->opcode = Op_push_array;
(yyval) = list_prepend((yyvsp[0]), (yyvsp[-1]));
}
-#line 3834 "awkgram.c" /* yacc.c:1646 */
+#line 4157 "awkgram.c" /* yacc.c:1646 */
break;
- case 176:
-#line 1746 "awkgram.y" /* yacc.c:1646 */
+ case 191:
+#line 1988 "awkgram.y" /* yacc.c:1646 */
{
INSTRUCTION *ip = (yyvsp[0])->nexti;
if (ip->opcode == Op_push
@@ -3846,73 +4169,73 @@ regular_print:
} else
(yyval) = (yyvsp[0]);
}
-#line 3850 "awkgram.c" /* yacc.c:1646 */
+#line 4173 "awkgram.c" /* yacc.c:1646 */
break;
- case 177:
-#line 1758 "awkgram.y" /* yacc.c:1646 */
+ case 192:
+#line 2000 "awkgram.y" /* yacc.c:1646 */
{
(yyval) = list_append((yyvsp[-1]), (yyvsp[-2]));
if ((yyvsp[0]) != NULL)
mk_assignment((yyvsp[-1]), NULL, (yyvsp[0]));
}
-#line 3860 "awkgram.c" /* yacc.c:1646 */
+#line 4183 "awkgram.c" /* yacc.c:1646 */
break;
- case 178:
-#line 1767 "awkgram.y" /* yacc.c:1646 */
+ case 193:
+#line 2009 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postincrement;
}
-#line 3868 "awkgram.c" /* yacc.c:1646 */
+#line 4191 "awkgram.c" /* yacc.c:1646 */
break;
- case 179:
-#line 1771 "awkgram.y" /* yacc.c:1646 */
+ case 194:
+#line 2013 "awkgram.y" /* yacc.c:1646 */
{
(yyvsp[0])->opcode = Op_postdecrement;
}
-#line 3876 "awkgram.c" /* yacc.c:1646 */
+#line 4199 "awkgram.c" /* yacc.c:1646 */
break;
- case 180:
-#line 1774 "awkgram.y" /* yacc.c:1646 */
+ case 195:
+#line 2016 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = NULL; }
-#line 3882 "awkgram.c" /* yacc.c:1646 */
+#line 4205 "awkgram.c" /* yacc.c:1646 */
break;
- case 182:
-#line 1782 "awkgram.y" /* yacc.c:1646 */
+ case 197:
+#line 2024 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3888 "awkgram.c" /* yacc.c:1646 */
+#line 4211 "awkgram.c" /* yacc.c:1646 */
break;
- case 183:
-#line 1786 "awkgram.y" /* yacc.c:1646 */
+ case 198:
+#line 2028 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3894 "awkgram.c" /* yacc.c:1646 */
+#line 4217 "awkgram.c" /* yacc.c:1646 */
break;
- case 186:
-#line 1795 "awkgram.y" /* yacc.c:1646 */
+ case 201:
+#line 2037 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3900 "awkgram.c" /* yacc.c:1646 */
+#line 4223 "awkgram.c" /* yacc.c:1646 */
break;
- case 187:
-#line 1799 "awkgram.y" /* yacc.c:1646 */
+ case 202:
+#line 2041 "awkgram.y" /* yacc.c:1646 */
{ (yyval) = (yyvsp[0]); yyerrok; }
-#line 3906 "awkgram.c" /* yacc.c:1646 */
+#line 4229 "awkgram.c" /* yacc.c:1646 */
break;
- case 188:
-#line 1803 "awkgram.y" /* yacc.c:1646 */
+ case 203:
+#line 2045 "awkgram.y" /* yacc.c:1646 */
{ yyerrok; }
-#line 3912 "awkgram.c" /* yacc.c:1646 */
+#line 4235 "awkgram.c" /* yacc.c:1646 */
break;
-#line 3916 "awkgram.c" /* yacc.c:1646 */
+#line 4239 "awkgram.c" /* yacc.c:1646 */
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -4140,7 +4463,7 @@ yyreturn:
#endif
return yyresult;
}
-#line 1805 "awkgram.y" /* yacc.c:1906 */
+#line 2047 "awkgram.y" /* yacc.c:1906 */
struct token {
@@ -4157,7 +4480,7 @@ struct token {
# 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 */
};
@@ -4217,9 +4540,6 @@ static const struct token tokentab[] = {
{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
-#ifdef DYNAMIC
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
-#endif
{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0},
{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
@@ -4232,13 +4552,14 @@ static const struct token tokentab[] = {
{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0, 0},
{"index", Op_builtin, LEX_BUILTIN, A(2), do_index, 0},
{"int", Op_builtin, LEX_BUILTIN, A(1), do_int, MPF(int)},
+{"intdiv", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_intdiv, MPF(intdiv)},
{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray, 0},
{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length, 0},
{"load", Op_symbol, LEX_LOAD, GAWKX, 0, 0},
{"log", Op_builtin, LEX_BUILTIN, A(1), do_log, MPF(log)},
{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)},
{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0},
-{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime, 0},
+{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_mktime, 0},
{"next", Op_K_next, LEX_NEXT, 0, 0, 0},
{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0},
{"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)},
@@ -4265,6 +4586,7 @@ static const struct token tokentab[] = {
{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0},
{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0},
{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0},
+{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_typeof, 0},
{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0},
{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)},
};
@@ -4290,7 +4612,7 @@ getfname(NODE *(*fptr)(int))
j = sizeof(tokentab) / sizeof(tokentab[0]);
/* linear search, no other way to do it */
- for (i = 0; i < j; i++)
+ for (i = 0; i < j; i++)
if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr)
return tokentab[i].operator;
@@ -4306,6 +4628,8 @@ negate_num(NODE *n)
int tval = 0;
#endif
+ add_sign_to_num(n, '-');
+
if (! is_mpg_number(n)) {
n->numbr = -n->numbr;
return;
@@ -4338,6 +4662,21 @@ negate_num(NODE *n)
#endif
}
+/* add_sign_to_num --- make a constant unary plus or minus for profiling */
+
+static void
+add_sign_to_num(NODE *n, char sign)
+{
+ if ((n->flags & NUMCONSTSTR) != 0) {
+ char *s;
+
+ s = n->stptr;
+ memmove(& s[1], & s[0], n->stlen + 1);
+ s[0] = sign;
+ n->stlen++;
+ }
+}
+
/* print_included_from --- print `Included from ..' file names and locations */
static void
@@ -4346,7 +4685,7 @@ print_included_from()
int saveline, line;
SRCFILE *s;
- /* suppress current file name, line # from `.. included from ..' msgs */
+ /* suppress current file name, line # from `.. included from ..' msgs */
saveline = sourceline;
sourceline = 0;
@@ -4440,7 +4779,6 @@ yyerror(const char *m, ...)
char *buf;
int count;
static char end_of_file_line[] = "(END OF FILE)";
- char save;
print_included_from();
@@ -4471,25 +4809,16 @@ yyerror(const char *m, ...)
bp = thisline + strlen(thisline);
}
- /*
- * Saving and restoring *bp keeps valgrind happy,
- * since the guts of glibc uses strlen, even though
- * we're passing an explict precision. Sigh.
- *
- * 8/2003: We may not need this anymore.
- */
- save = *bp;
- *bp = '\0';
-
msg("%.*s", (int) (bp - thisline), thisline);
- *bp = save;
va_start(args, m);
if (mesg == NULL)
mesg = m;
- count = (bp - thisline) + strlen(mesg) + 2 + 1;
- emalloc(buf, char *, count, "yyerror");
+ count = strlen(mesg) + 1;
+ if (lexptr != NULL)
+ count += (lexeme - thisline) + 2;
+ ezalloc(buf, char *, count+1, "yyerror");
bp = buf;
@@ -4556,7 +4885,7 @@ mk_program()
if (prog_block == NULL) {
if (end_block->nexti == end_block->lasti
- && beginfile_block->nexti == beginfile_block->lasti
+ && beginfile_block->nexti == beginfile_block->lasti
&& endfile_block->nexti == endfile_block->lasti
) {
/* no pattern-action and (real) end, beginfile or endfile blocks */
@@ -4571,6 +4900,11 @@ mk_program()
cp = end_block;
else
cp = list_merge(begin_block, end_block);
+ if (program_comment != NULL) {
+ (void) list_prepend(cp, program_comment);
+ }
+ if (comment != NULL)
+ (void) list_append(cp, comment);
(void) list_append(cp, ip_atexit);
(void) list_append(cp, instruction(Op_stop));
@@ -4593,7 +4927,7 @@ mk_program()
(void) list_prepend(prog_block, ip_rec);
(void) list_append(prog_block, instruction(Op_jmp));
prog_block->lasti->target_jmp = ip_rec;
-
+
list_append(beginfile_block, instruction(Op_after_beginfile));
cp = list_merge(beginfile_block, prog_block);
@@ -4603,6 +4937,12 @@ mk_program()
if (begin_block != NULL)
cp = list_merge(begin_block, cp);
+ if (program_comment != NULL) {
+ (void) list_prepend(cp, program_comment);
+ }
+ if (comment != NULL) {
+ (void) list_append(cp, comment);
+ }
(void) list_append(cp, ip_atexit);
(void) list_append(cp, instruction(Op_stop));
@@ -4610,13 +4950,17 @@ out:
/* delete the Op_list, not needed */
tmp = cp->nexti;
bcfree(cp);
+ /* these variables are not used again but zap them anyway. */
+ comment = NULL;
+ function_comment = NULL;
+ program_comment = NULL;
return tmp;
#undef begin_block
#undef end_block
#undef prog_block
#undef beginfile_block
-#undef endfile_block
+#undef endfile_block
}
/* parse_program --- read in the program and convert into a list of instructions */
@@ -4636,7 +4980,7 @@ parse_program(INSTRUCTION **pcode)
ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL;
else {
ip_endfile = instruction(Op_no_op);
- ip_beginfile = instruction(Op_no_op);
+ main_beginfile = ip_beginfile = instruction(Op_no_op);
ip_rec = instruction(Op_get_record); /* target for `next', also ip_newfile */
ip_newfile = bcalloc(Op_newfile, 2, 0); /* target for `nextfile' */
ip_newfile->target_jmp = ip_end;
@@ -4693,8 +5037,7 @@ do_add_srcfile(enum srctype stype, char *src, char *path, SRCFILE *thisfile)
{
SRCFILE *s;
- emalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile");
- memset(s, 0, sizeof(SRCFILE));
+ ezalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile");
s->src = estrdup(src, strlen(src));
s->fullpath = path;
s->stype = stype;
@@ -4767,7 +5110,7 @@ add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_incl
*already_included = true;
return NULL;
} else {
- /* duplicates are allowed for -f */
+ /* duplicates are allowed for -f */
if (s->stype == SRC_INC)
fatal(_("can't include `%s' and use it as a program file"), src);
/* no need to scan for further matches, since
@@ -4818,11 +5161,11 @@ include_source(INSTRUCTION *file)
sourcefile->srclines = sourceline;
sourcefile->lexptr = lexptr;
sourcefile->lexend = lexend;
- sourcefile->lexptr_begin = lexptr_begin;
+ sourcefile->lexptr_begin = lexptr_begin;
sourcefile->lexeme = lexeme;
sourcefile->lasttok = lasttok;
- /* included file becomes the current source */
+ /* included file becomes the current source */
sourcefile = s;
lexptr = NULL;
sourceline = 0;
@@ -5107,7 +5450,7 @@ get_src_buf()
lexend = lexptr + n;
if (n == 0) {
static bool warned = false;
- if (do_lint && newfile && ! warned){
+ if (do_lint && newfile && ! warned) {
warned = true;
sourceline = 0;
lintwarn(_("source file `%s' is empty"), source);
@@ -5129,7 +5472,7 @@ tokexpand()
{
static int toksize;
int tokoffset;
-
+
if (tokstart != NULL) {
tokoffset = tok - tokstart;
toksize *= 2;
@@ -5179,8 +5522,17 @@ nextc(bool check_for_bad)
{
if (gawk_mb_cur_max > 1) {
again:
+#ifdef NO_CONTINUE_SOURCE_STRINGS
if (lexeof)
return END_FILE;
+#else
+ if (lexeof) {
+ if (sourcefile->next == srcfiles)
+ return END_FILE;
+ else
+ next_sourcefile();
+ }
+#endif
if (lexptr == NULL || lexptr >= lexend) {
if (get_src_buf())
goto again;
@@ -5197,8 +5549,8 @@ again:
int idx, work_ring_idx = cur_ring_idx;
mbstate_t tmp_state;
size_t mbclen;
-
- for (idx = 0 ; lexptr + idx < lexend ; idx++) {
+
+ for (idx = 0; lexptr + idx < lexend; idx++) {
tmp_state = cur_mbstate;
mbclen = mbrlen(lexptr, idx + 1, &tmp_state);
@@ -5232,8 +5584,17 @@ again:
return (int) (unsigned char) *lexptr++;
} else {
do {
+#ifdef NO_CONTINUE_SOURCE_STRINGS
if (lexeof)
return END_FILE;
+#else
+ if (lexeof) {
+ if (sourcefile->next == srcfiles)
+ return END_FILE;
+ else
+ next_sourcefile();
+ }
+#endif
if (lexptr && lexptr < lexend) {
if (check_for_bad || *lexptr == '\0')
check_bad_char(*lexptr);
@@ -5255,6 +5616,122 @@ pushback(void)
(! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr);
}
+/* check_comment --- check for block comment */
+
+void
+check_comment(void)
+{
+ if (comment != NULL) {
+ if (first_rule) {
+ program_comment = comment;
+ } else
+ block_comment = comment;
+ comment = NULL;
+ }
+ first_rule = false;
+}
+
+/*
+ * get_comment --- collect comment text.
+ * Flag = EOL_COMMENT for end-of-line comments.
+ * Flag = FULL_COMMENT for self-contained comments.
+ */
+
+int
+get_comment(int flag)
+{
+ int c;
+ int sl;
+ tok = tokstart;
+ tokadd('#');
+ sl = sourceline;
+ char *p1;
+ char *p2;
+
+ while (true) {
+ while ((c = nextc(false)) != '\n' && c != END_FILE) {
+ /* ignore \r characters */
+ if (c != '\r')
+ tokadd(c);
+ }
+ if (flag == EOL_COMMENT) {
+ /* comment at end of line. */
+ if (c == '\n')
+ tokadd(c);
+ break;
+ }
+ if (c == '\n') {
+ tokadd(c);
+ sourceline++;
+ do {
+ c = nextc(false);
+ if (c == '\n') {
+ sourceline++;
+ tokadd(c);
+ }
+ } while (isspace(c) && c != END_FILE);
+ if (c == END_FILE)
+ break;
+ else if (c != '#') {
+ pushback();
+ sourceline--;
+ break;
+ } else
+ tokadd(c);
+ } else
+ break;
+ }
+
+ if (comment != NULL)
+ prior_comment = comment;
+
+ /* remove any trailing blank lines (consecutive \n) from comment */
+ p1 = tok - 1;
+ p2 = tok - 2;
+ while (*p1 == '\n' && *p2 == '\n') {
+ p1--;
+ p2--;
+ tok--;
+ }
+
+ comment = bcalloc(Op_comment, 1, sl);
+ comment->source_file = source;
+ comment->memory = make_str_node(tokstart, tok - tokstart, 0);
+ comment->memory->comment_type = flag;
+
+ return c;
+}
+
+/* split_comment --- split initial comment text into program and function parts */
+
+static void
+split_comment(void)
+{
+ char *p;
+ int l;
+ NODE *n;
+
+ p = comment_to_save->memory->stptr;
+ l = comment_to_save->memory->stlen - 3;
+ /* have at least two comments so split at last blank line (\n\n) */
+ while (l >= 0) {
+ if (p[l] == '\n' && p[l+1] == '\n') {
+ function_comment = comment_to_save;
+ n = function_comment->memory;
+ function_comment->memory = make_string(p + l + 2, n->stlen - l - 2);
+ /* create program comment */
+ program_comment = bcalloc(Op_comment, 1, sourceline);
+ program_comment->source_file = comment_to_save->source_file;
+ p[l + 2] = 0;
+ program_comment->memory = make_str_node(p, l + 2, 0);
+ comment_to_save = NULL;
+ freenode(n);
+ break;
+ }
+ else
+ l--;
+ }
+}
/* allow_newline --- allow newline after &&, ||, ? and : */
@@ -5270,8 +5747,13 @@ allow_newline(void)
break;
}
if (c == '#') {
- while ((c = nextc(false)) != '\n' && c != END_FILE)
- continue;
+ if (do_pretty_print && ! do_profile) {
+ /* collect comment byte code iff doing pretty print but not profiling. */
+ c = get_comment(EOL_COMMENT);
+ } else {
+ while ((c = nextc(false)) != '\n' && c != END_FILE)
+ continue;
+ }
if (c == END_FILE) {
pushback();
break;
@@ -5294,7 +5776,8 @@ allow_newline(void)
* removes the warnings.
*/
-static int newline_eof()
+static int
+newline_eof()
{
/* NB: a newline at end does not start a source line. */
if (lasttok != NEWLINE) {
@@ -5332,6 +5815,7 @@ yylex(void)
bool inhex = false;
bool intlstr = false;
AWKNUM d;
+ bool collecting_typed_regexp = false;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -5342,7 +5826,7 @@ yylex(void)
lasttok = 0;
return SUBSCRIPT;
}
-
+
if (lasttok == LEX_EOF) /* error earlier in current source, must give up !! */
return 0;
@@ -5366,6 +5850,8 @@ yylex(void)
lexeme = lexptr;
thisline = NULL;
+
+collect_regexp:
if (want_regexp) {
int in_brack = 0; /* count brackets, [[:alnum:]] allowed */
int b_index = -1;
@@ -5376,7 +5862,7 @@ yylex(void)
*
* [..[..] []] [^]] [.../...]
* [...\[...] [...\]...] [...\/...]
- *
+ *
* (Remember that all of the above are inside /.../)
*
* The code for \ handles \[, \] and \/.
@@ -5405,7 +5891,7 @@ yylex(void)
break;
case ']':
if (in_brack > 0
- && (cur_index == b_index + 1
+ && (cur_index == b_index + 1
|| (cur_index == b_index + 2 && tok[-1] == '^')))
; /* do nothing */
else {
@@ -5452,7 +5938,13 @@ end_regexp:
peek);
}
}
- return lasttok = REGEXP;
+ if (collecting_typed_regexp) {
+ collecting_typed_regexp = false;
+ lasttok = TYPED_REGEXP;
+ } else
+ lasttok = REGEXP;
+
+ return lasttok;
case '\n':
pushback();
yyerror(_("unterminated regexp"));
@@ -5488,21 +5980,42 @@ retry:
return lasttok = NEWLINE;
case '#': /* it's a comment */
- while ((c = nextc(false)) != '\n') {
+ if (do_pretty_print && ! do_profile) {
+ /*
+ * Collect comment byte code iff doing pretty print
+ * but not profiling.
+ */
+ if (lasttok == NEWLINE || lasttok == 0)
+ c = get_comment(FULL_COMMENT);
+ else
+ c = get_comment(EOL_COMMENT);
+
if (c == END_FILE)
return lasttok = NEWLINE_EOF;
+ } else {
+ while ((c = nextc(false)) != '\n') {
+ if (c == END_FILE)
+ return lasttok = NEWLINE_EOF;
+ }
}
sourceline++;
return lasttok = NEWLINE;
case '@':
+ c = nextc(true);
+ if (c == '/') {
+ want_regexp = true;
+ collecting_typed_regexp = true;
+ goto collect_regexp;
+ }
+ pushback();
at_seen = true;
return lasttok = '@';
case '\\':
#ifdef RELAXED_CONTINUATION
/*
- * This code puports to allow comments and/or whitespace
+ * This code purports to allow comments and/or whitespace
* after the `\' at the end of a line used for continuation.
* Use it at your own risk. We think it's a bad idea, which
* is why it's not on by default.
@@ -5519,9 +6032,13 @@ retry:
lintwarn(
_("use of `\\ #...' line continuation is not portable"));
}
- while ((c = nextc(false)) != '\n')
- if (c == END_FILE)
- break;
+ if (do_pretty_print && ! do_profile)
+ c = get_comment(EOL_COMMENT);
+ else {
+ while ((c = nextc(false)) != '\n')
+ if (c == END_FILE)
+ break;
+ }
}
pushback();
}
@@ -5553,7 +6070,7 @@ retry:
in_parens--;
return lasttok = c;
- case '(':
+ case '(':
in_parens++;
return lasttok = c;
case '$':
@@ -5656,7 +6173,7 @@ retry:
did_warn_op = true;
warning(_("operator `^' is not supported in old awk"));
}
- yylval = GET_INSTRUCTION(Op_exp);
+ yylval = GET_INSTRUCTION(Op_exp);
return lasttok = '^';
}
@@ -5779,7 +6296,7 @@ retry:
yylval->lextok = estrdup(tokstart, tok - tokstart);
return lasttok = FILENAME;
}
-
+
yylval->opcode = Op_push_i;
yylval->memory = make_str_node(tokstart,
tok - tokstart, esc_seen ? SCAN : 0);
@@ -5918,7 +6435,7 @@ retry:
base = 10;
if (! do_traditional) {
- base = get_numbase(tokstart, false);
+ base = get_numbase(tokstart, strlen(tokstart)-1, false);
if (do_lint) {
if (base == 8)
lintwarn("numeric constant `%.*s' treated as octal",
@@ -5944,15 +6461,15 @@ retry:
errno = 0;
IEEE_FMT(r->mpg_numbr, tval);
}
- yylval->memory = r;
+ yylval->memory = set_profile_text(r, tokstart, strlen(tokstart)-1);
return lasttok = YNUMBER;
}
#endif
if (base != 10)
- d = nondec2awknum(tokstart, strlen(tokstart));
+ d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL);
else
d = atof(tokstart);
- yylval->memory = make_number(d);
+ yylval->memory = set_profile_text(make_number(d), tokstart, strlen(tokstart) - 1);
if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
yylval->memory->flags |= NUMINT;
return lasttok = YNUMBER;
@@ -6035,6 +6552,33 @@ retry:
&& lasttok != '@')
goto out;
+ /* allow parameter names to shadow the names of gawk extension built-ins */
+ if ((tokentab[mid].flags & GAWKX) != 0) {
+ NODE *f;
+
+ switch (want_param_names) {
+ case FUNC_HEADER:
+ /* in header, defining parameter names */
+ goto out;
+ case FUNC_BODY:
+ /* in body, name must be in symbol table for it to be a parameter */
+ if ((f = lookup(tokstart)) != NULL) {
+ if (f->type == Node_builtin_func)
+ break;
+ else
+ goto out;
+ }
+ /* else
+ fall through */
+ case DONT_CHECK:
+ /* regular code */
+ break;
+ default:
+ cant_happen();
+ break;
+ }
+ }
+
if (do_lint) {
if ((tokentab[mid].flags & GAWKX) != 0 && (warntab[mid] & GAWKX) == 0) {
lintwarn(_("`%s' is a gawk extension"),
@@ -6079,7 +6623,7 @@ retry:
case LEX_BEGIN:
case LEX_END:
case LEX_BEGINFILE:
- case LEX_ENDFILE:
+ case LEX_ENDFILE:
yylval = bcalloc(tokentab[mid].value, 3, sourceline);
break;
@@ -6128,7 +6672,7 @@ out:
tokkey = estrdup(tokstart, tok - tokstart);
if (*lexptr == '(') {
yylval = bcalloc(Op_token, 2, sourceline);
- yylval->lextok = tokkey;
+ yylval->lextok = tokkey;
return lasttok = FUNC_CALL;
} else {
static bool goto_warned = false;
@@ -6204,7 +6748,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
nexp++;
}
assert(nexp > 0);
- }
+ }
/* check against how many args. are allowed for this builtin */
args_allowed = tokentab[idx].flags & ARGS;
@@ -6235,7 +6779,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
INSTRUCTION *expr;
expr = list_create(instruction(Op_push_i));
- expr->nexti->memory = make_number(0.0);
+ expr->nexti->memory = set_profile_text(make_number(0.0), "0", 1);
(void) mk_expression_list(subn,
list_append(expr, instruction(Op_field_spec)));
}
@@ -6275,7 +6819,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
subn->lasti->assign_ctxt = Op_sub_builtin;
}
- return subn;
+ return subn;
} else {
/* gensub */
@@ -6283,7 +6827,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
r->sub_flags |= GENSUB;
if (nexp == 3) {
ip = instruction(Op_push_i);
- ip->memory = make_number(0.0);
+ ip->memory = set_profile_text(make_number(0.0), "0", 1);
(void) mk_expression_list(subn,
list_append(list_create(ip), instruction(Op_field_spec)));
}
@@ -6294,7 +6838,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
#ifdef HAVE_MPFR
- /* N.B.: There isn't any special processing for an alternate function below */
+ /* N.B.: If necessary, add special processing for alternate builtin, below */
if (do_mpfr && tokentab[idx].ptr2)
r->builtin = tokentab[idx].ptr2;
else
@@ -6304,25 +6848,34 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
/* special case processing for a few builtins */
if (r->builtin == do_length) {
- if (nexp == 0) {
+ if (nexp == 0) {
/* no args. Use $0 */
INSTRUCTION *list;
- r->expr_count = 1;
+ r->expr_count = 1;
list = list_create(r);
(void) list_prepend(list, instruction(Op_field_spec));
(void) list_prepend(list, instruction(Op_push_i));
- list->nexti->memory = make_number(0.0);
- return list;
+ list->nexti->memory = set_profile_text(make_number(0.0), "0", 1);
+ return list;
} else {
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
arg->nexti->opcode = Op_push_arg; /* argument may be array */
}
- } else if (r->builtin == do_isarray) {
+ } else if (r->builtin == do_isarray || r->builtin == do_typeof) {
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
- arg->nexti->opcode = Op_push_arg; /* argument may be array */
+ arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */
+ } else if (r->builtin == do_intdiv
+#ifdef HAVE_MPFR
+ || r->builtin == MPF(intdiv)
+#endif
+ ) {
+ arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
+ ip = arg->lasti;
+ if (ip->opcode == Op_push)
+ ip->opcode = Op_push_array;
} else if (r->builtin == do_match) {
static bool warned = false;
@@ -6399,7 +6952,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
} else if (do_intl /* --gen-po */
&& r->builtin == do_dcgettext /* dcgettext(...) */
&& subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */
- && (subn->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */
+ && (subn->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */
/* ala xgettext, dcgettext("some string" ...) dumps the string */
NODE *str = subn->nexti->lasti->memory;
@@ -6411,9 +6964,9 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
} else if (do_intl /* --gen-po */
&& r->builtin == do_dcngettext /* dcngettext(...) */
&& subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */
- && (subn->nexti->lasti->memory->flags & STRCUR) != 0 /* it's a string constant */
+ && (subn->nexti->lasti->memory->flags & STRING) != 0 /* it's a string constant */
&& subn->nexti->lasti->nexti->lasti->opcode == Op_push_i /* 2nd arg is constant too */
- && (subn->nexti->lasti->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */
+ && (subn->nexti->lasti->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */
/* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */
NODE *str1 = subn->nexti->lasti->memory;
NODE *str2 = subn->nexti->lasti->nexti->lasti->memory;
@@ -6508,6 +7061,8 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
{
if (n == Nnull_string)
print_func(fp, "uninitialized scalar\n");
+ else if ((n->flags & REGEX) != 0)
+ print_func(fp, "@/%.*s/\n", n->stlen, n->stptr);
else if ((n->flags & STRING) != 0) {
pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
print_func(fp, "\n");
@@ -6520,18 +7075,6 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
else
#endif
print_func(fp, "%.17g\n", n->numbr);
- } else if ((n->flags & STRCUR) != 0) {
- pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
- print_func(fp, "\n");
- } else if ((n->flags & NUMCUR) != 0) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
} else
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
@@ -6620,6 +7163,14 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
(t + 1)->tail_call = true;
}
+ /* add any pre-function comment to start of action for profile.c */
+
+ if (function_comment != NULL) {
+ function_comment->source_line = 0;
+ (void) list_prepend(def, function_comment);
+ function_comment = NULL;
+ }
+
/* add an implicit return at end;
* also used by 'return' command in debugger
*/
@@ -6649,7 +7200,7 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
return fi;
}
-/*
+/*
* install_function:
* install function name in the symbol table.
* Extra work, build up and install a list of the parameter names.
@@ -6673,7 +7224,7 @@ install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
fi->func_body = f;
f->param_cnt = pcount;
f->code_ptr = fi;
- f->fparms = NULL;
+ f->fparms = NULL;
if (pcount > 0) {
char **pnames;
pnames = check_params(fname, pcount, plist); /* frees plist */
@@ -6730,7 +7281,7 @@ check_params(char *fname, int pcount, INSTRUCTION *list)
}
bcfree(list);
- return pnames;
+ return pnames;
}
@@ -6738,7 +7289,7 @@ check_params(char *fname, int pcount, INSTRUCTION *list)
undef HASHSIZE
#endif
#define HASHSIZE 1021
-
+
static struct fdesc {
char *name;
short used;
@@ -6765,8 +7316,7 @@ func_use(const char *name, enum defref how)
/* not in the table, fall through to allocate a new one */
- emalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
- memset(fp, '\0', sizeof(struct fdesc));
+ ezalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
emalloc(fp->name, char *, len + 1, "func_use");
strcpy(fp->name, name);
fp->next = ftable[ind];
@@ -6800,7 +7350,7 @@ check_funcs()
if (! in_main_context())
goto free_mem;
-
+
for (i = 0; i < HASHSIZE; i++) {
for (fp = ftable[i]; fp != NULL; fp = fp->next) {
#ifdef REALLYMEAN
@@ -6881,14 +7431,21 @@ make_regnode(int type, NODE *exp)
{
NODE *n;
+ assert(type == Node_regex || type == Node_dynregex);
getnode(n);
memset(n, 0, sizeof(NODE));
n->type = type;
n->re_cnt = 1;
if (type == Node_regex) {
- n->re_reg = make_regexp(exp->stptr, exp->stlen, false, true, false);
- if (n->re_reg == NULL) {
+ n->re_reg[0] = make_regexp(exp->stptr, exp->stlen, false, true, false);
+ if (n->re_reg[0] == NULL) {
+ freenode(n);
+ return NULL;
+ }
+ n->re_reg[1] = make_regexp(exp->stptr, exp->stlen, true, true, false);
+ if (n->re_reg[1] == NULL) {
+ refree(n->re_reg[0]);
freenode(n);
return NULL;
}
@@ -6909,6 +7466,8 @@ mk_rexp(INSTRUCTION *list)
ip = list->nexti;
if (ip == list->lasti && ip->opcode == Op_match_rec)
ip->opcode = Op_push_re;
+ else if (ip == list->lasti && ip->opcode == Op_push_re)
+ ; /* do nothing --- @/.../ */
else {
ip = instruction(Op_push_re);
ip->memory = make_regnode(Node_dynregex, NULL);
@@ -7103,6 +7662,8 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
}
op->opcode = Op_push_i;
+ // We don't need to call set_profile_text() here since
+ // optimizing is disabled when doing pretty printing.
op->memory = make_number(res);
unref(n1);
unref(n2);
@@ -7135,7 +7696,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
break;
default:
goto regular;
- }
+ }
op->memory = ip2->memory;
bcfree(ip2);
@@ -7151,7 +7712,7 @@ regular:
}
/* mk_boolean --- instructions for boolean and, or */
-
+
static INSTRUCTION *
mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
{
@@ -7179,7 +7740,7 @@ mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
right->lasti->target_stmt = left->lasti;
} else { /* optimization for x || y || z || ... */
INSTRUCTION *ip;
-
+
op->opcode = final_opc;
(void) list_append(right, op);
op->target_stmt = tp;
@@ -7216,7 +7777,7 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
*
* ----------------
* [Op_jmp y]
- * ----------------
+ * ----------------
* f:
* false_branch
* ----------------
@@ -7324,7 +7885,11 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
(rp + 1)->lasti = action->lasti;
(rp + 2)->first_line = pattern->source_line;
(rp + 2)->last_line = lastline;
- ip = list_prepend(action, rp);
+ if (block_comment != NULL) {
+ ip = list_prepend(list_prepend(action, block_comment), rp);
+ block_comment = NULL;
+ } else
+ ip = list_prepend(action, rp);
} else {
rp = bcalloc(Op_rule, 3, 0);
@@ -7366,7 +7931,6 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
action),
tp);
}
-
}
list_append(rule_list, rp + 1);
@@ -7375,7 +7939,7 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
rule_block[rule] = ip;
else
(void) list_merge(rule_block[rule], ip);
-
+
return rule_block[rule];
}
@@ -7397,7 +7961,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op)
break;
case Op_push:
case Op_push_array:
- tp->opcode = Op_push_lhs;
+ tp->opcode = Op_push_lhs;
break;
case Op_field_assign:
yyerror(_("cannot assign a value to the result of a field post-increment expression"));
@@ -7452,7 +8016,7 @@ optimize_assignment(INSTRUCTION *exp)
* Replaces Op_push_array + Op_subscript_lhs + Op_assign + Op_pop
* with single instruction Op_store_sub.
* Limitation: 1 dimension and sub is simple var/value.
- *
+ *
* 2) Simple variable assignment var = x:
* Replaces Op_push_lhs + Op_assign + Op_pop with Op_store_var.
*
@@ -7476,7 +8040,7 @@ optimize_assignment(INSTRUCTION *exp)
i1 = exp->lasti;
if ( i1->opcode != Op_assign
- && i1->opcode != Op_field_assign)
+ && i1->opcode != Op_field_assign)
return list_append(exp, instruction(Op_pop));
for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {
@@ -7551,7 +8115,7 @@ optimize_assignment(INSTRUCTION *exp)
* so use expr_count instead.
*/
i3->nexti = NULL;
- i2->opcode = Op_no_op;
+ i2->opcode = Op_no_op;
bcfree(i1); /* Op_assign */
exp->lasti = i3; /* update Op_list */
return exp;
@@ -7574,7 +8138,7 @@ optimize_assignment(INSTRUCTION *exp)
&& (i3->memory->flags & INTLSTR) == 0
&& i3->nexti == i2
) {
- /* constant initializer */
+ /* constant initializer */
i2->initval = i3->memory;
bcfree(i3);
exp->nexti = i2;
@@ -7610,7 +8174,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
* [ file (simp_exp)]
* [ [ var ] ]
* [ Op_K_getline_redir|NULL|redir_type|into_var]
- * [ [var_assign] ]
+ * [ [var_assign] ]
*
*/
@@ -7619,7 +8183,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
bcfree(op);
op = bcalloc(Op_K_getline, 2, sline);
(op + 1)->target_endfile = ip_endfile;
- (op + 1)->target_beginfile = ip_beginfile;
+ (op + 1)->target_beginfile = ip_beginfile;
}
if (var != NULL) {
@@ -7677,11 +8241,11 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
* ------------------------
* body (may be NULL)
* ------------------------
- * tc:
+ * tc:
* incr (may be NULL)
- * [ Op_jmp x ]
+ * [ Op_jmp x ]
* ------------------------
- * tb:[ Op_no_op ]
+ * tb:[ Op_no_op ]
*/
INSTRUCTION *ip, *tbreak, *tcont;
@@ -7762,12 +8326,22 @@ add_lint(INSTRUCTION *list, LINTTYPE linttype)
case LINT_no_effect:
if (list->lasti->opcode == Op_pop && list->nexti != list->lasti) {
- for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti)
- ;
+ int line = 0;
+
+ // Get down to the last instruction (FIXME: why?)
+ for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) {
+ // along the way track line numbers, we will use the line
+ // closest to the opcode if that opcode doesn't have one
+ if (ip->source_line != 0)
+ line = ip->source_line;
+ }
if (do_lint) { /* compile-time warning */
- if (isnoeffect(ip->opcode))
- lintwarn_ln(ip->source_line, ("statement may have no effect"));
+ if (isnoeffect(ip->opcode)) {
+ if (ip->source_line != 0)
+ line = ip->source_line;
+ lintwarn_ln(line, ("statement may have no effect"));
+ }
}
if (ip->opcode == Op_push) { /* run-time warning */
@@ -7793,7 +8367,7 @@ mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1)
/* we can't just combine all bytecodes, since we need to
* process individual expressions for a few builtins in snode() (-:
*/
-
+
/* -- list of lists */
/* [Op_list| ... ]------
* |
@@ -7849,7 +8423,7 @@ count_expressions(INSTRUCTION **list, bool isarg)
(void) list_merge(r, expr);
expr = t2->nexti;
}
-
+
assert(count > 0);
if (! isarg && count > max_args)
max_args = count;
@@ -7936,6 +8510,26 @@ list_merge(INSTRUCTION *l1, INSTRUCTION *l2)
return l1;
}
+/* add_pending_comment --- add a pending comment to a statement */
+
+static inline INSTRUCTION *
+add_pending_comment(INSTRUCTION *stmt)
+{
+ INSTRUCTION *ret = stmt;
+
+ if (prior_comment != NULL) {
+ if (function_comment != prior_comment)
+ ret = list_append(stmt, prior_comment);
+ prior_comment = NULL;
+ } else if (comment != NULL && comment->memory->comment_type == EOL_COMMENT) {
+ if (function_comment != comment)
+ ret = list_append(stmt, comment);
+ comment = NULL;
+ }
+
+ return ret;
+}
+
/* See if name is a special token. */
int
@@ -8095,7 +8689,7 @@ install_builtins(void)
* The scene of the murder was grisly to look upon. When the inspector
* arrived, the sergeant turned to him and said, "Another programmer stabbed
* in the back. He never knew what happened."
- *
+ *
* The inspector replied, "Looks like the MO of isalpha, and his even meaner
* big brother, isalnum. The Locale brothers." The sergeant merely
* shuddered in horror.
@@ -8141,3 +8735,26 @@ is_identchar(int c)
{
return (is_alnum(c) || c == '_');
}
+
+/* set_profile_text --- make a number that can be printed when profiling */
+
+static NODE *
+set_profile_text(NODE *n, const char *str, size_t len)
+{
+ if (do_pretty_print) {
+ // two extra bytes: one for NUL termination, and another in
+ // case we need to add a leading minus sign in add_sign_to_num
+ emalloc(n->stptr, char *, len + 2, "set_profile_text");
+ memcpy(n->stptr, str, len);
+ n->stptr[len] = '\0';
+ n->stlen = len;
+ // Set STRCUR and n->stfmt for use when profiling
+ // (i.e., actually running the program) so that
+ // force_string() on this item will work ok.
+ // Thanks and a tip of the hatlo to valgrind.
+ n->flags |= (NUMCONSTSTR|STRCUR);
+ n->stfmt = STFMT_UNUSED;
+ }
+
+ return n;
+}
diff --git a/awkgram.y b/awkgram.y
index b0dd2830..d06faf8d 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -2,7 +2,7 @@
* awkgram.y --- yacc/bison parser
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
@@ -40,7 +40,7 @@ static void lintwarn_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
static void warning_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
static char *get_src_buf(void);
static int yylex(void);
-int yyparse(void);
+int yyparse(void);
static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
static char **check_params(char *fname, int pcount, INSTRUCTION *list);
static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist);
@@ -57,6 +57,7 @@ static int include_source(INSTRUCTION *file);
static int load_library(INSTRUCTION *file);
static void next_sourcefile(void);
static char *tokexpand(void);
+static NODE *set_profile_text(NODE *n, const char *str, size_t len);
#define instruction(t) bcalloc(t, 1, 0)
@@ -83,10 +84,18 @@ static void check_funcs(void);
static ssize_t read_one_line(int fd, void *buffer, size_t count);
static int one_line_close(int fd);
+static void split_comment(void);
+static void check_comment(void);
+static void add_sign_to_num(NODE *n, char sign);
static bool at_seen = false;
static bool want_source = false;
static bool want_regexp = false; /* lexical scanning kludge */
+static enum {
+ FUNC_HEADER,
+ FUNC_BODY,
+ DONT_CHECK
+} want_param_names = DONT_CHECK; /* ditto */
static char *in_function; /* parsing kludge */
static int rule = 0;
@@ -106,7 +115,7 @@ static char *lexptr; /* pointer to next char during parsing */
static char *lexend; /* end of buffer */
static char *lexptr_begin; /* keep track of where we were for error msgs */
static char *lexeme; /* beginning of lexeme for debugging */
-static bool lexeof; /* seen EOF for current source? */
+static bool lexeof; /* seen EOF for current source? */
static char *thisline = NULL;
static int in_braces = 0; /* count braces for firstline, lastline in an 'action' */
static int lastline = 0;
@@ -141,11 +150,23 @@ static INSTRUCTION *ip_atexit = NULL;
static INSTRUCTION *ip_end;
static INSTRUCTION *ip_endfile;
static INSTRUCTION *ip_beginfile;
+INSTRUCTION *main_beginfile;
+
+static INSTRUCTION *comment = NULL;
+static INSTRUCTION *prior_comment = NULL;
+static INSTRUCTION *comment_to_save = NULL;
+static INSTRUCTION *program_comment = NULL;
+static INSTRUCTION *function_comment = NULL;
+static INSTRUCTION *block_comment = NULL;
+
+static bool func_first = true;
+static bool first_rule = true;
static inline INSTRUCTION *list_create(INSTRUCTION *x);
static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x);
static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x);
static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2);
+static inline INSTRUCTION *add_pending_comment(INSTRUCTION *stmt);
extern double fmod(double x, double y);
@@ -153,14 +174,14 @@ extern double fmod(double x, double y);
%}
%token FUNC_CALL NAME REGEXP FILENAME
-%token YNUMBER YSTRING
+%token YNUMBER YSTRING TYPED_REGEXP
%token RELOP IO_OUT IO_IN
%token ASSIGNOP ASSIGN MATCHOP CONCAT_OP
%token SUBSCRIPT
%token LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
%token LEX_SWITCH LEX_CASE LEX_DEFAULT LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
%token LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
-%token LEX_BEGINFILE LEX_ENDFILE
+%token LEX_BEGINFILE LEX_ENDFILE
%token LEX_GETLINE LEX_NEXTFILE
%token LEX_IN
%token LEX_AND LEX_OR INCREMENT DECREMENT
@@ -181,7 +202,7 @@ extern double fmod(double x, double y);
%left MATCHOP
%nonassoc RELOP '<' '>' IO_IN IO_OUT
%left CONCAT_OP
-%left YSTRING YNUMBER
+%left YSTRING YNUMBER TYPED_REGEXP
%left '+' '-'
%left '*' '/' '%'
%right '!' UNARY
@@ -218,6 +239,7 @@ rule
: pattern action
{
(void) append_rule($1, $2);
+ first_rule = false;
}
| pattern statement_term
{
@@ -234,6 +256,7 @@ rule
{
in_function = NULL;
(void) mk_function($1, $2);
+ want_param_names = DONT_CHECK;
yyerrok;
}
| '@' LEX_INCLUDE source statement_term
@@ -282,9 +305,24 @@ library
pattern
: /* empty */
- { $$ = NULL; rule = Rule; }
+ {
+ rule = Rule;
+ if (comment != NULL) {
+ $$ = list_create(comment);
+ comment = NULL;
+ } else
+ $$ = NULL;
+ }
| exp
- { $$ = $1; rule = Rule; }
+ {
+ rule = Rule;
+ if (comment != NULL) {
+ $$ = list_prepend($1, comment);
+ comment = NULL;
+ } else
+ $$ = $1;
+ }
+
| exp ',' opt_nls exp
{
INSTRUCTION *tp;
@@ -308,41 +346,55 @@ pattern
($1->nexti + 1)->condpair_left = $1->lasti;
($1->nexti + 1)->condpair_right = $4->lasti;
}
- $$ = list_append(list_merge($1, $4), tp);
+ if (comment != NULL) {
+ $$ = list_append(list_merge(list_prepend($1, comment), $4), tp);
+ comment = NULL;
+ } else
+ $$ = list_append(list_merge($1, $4), tp);
rule = Rule;
}
| LEX_BEGIN
{
static int begin_seen = 0;
+
+ func_first = false;
if (do_lint_old && ++begin_seen == 2)
warning_ln($1->source_line,
_("old awk does not support multiple `BEGIN' or `END' rules"));
$1->in_rule = rule = BEGIN;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
| LEX_END
{
static int end_seen = 0;
+
+ func_first = false;
if (do_lint_old && ++end_seen == 2)
warning_ln($1->source_line,
_("old awk does not support multiple `BEGIN' or `END' rules"));
$1->in_rule = rule = END;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
| LEX_BEGINFILE
{
+ func_first = false;
$1->in_rule = rule = BEGINFILE;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
| LEX_ENDFILE
{
+ func_first = false;
$1->in_rule = rule = ENDFILE;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
;
@@ -350,10 +402,12 @@ pattern
action
: l_brace statements r_brace opt_semi opt_nls
{
+ INSTRUCTION *ip;
if ($2 == NULL)
- $$ = list_create(instruction(Op_no_op));
+ ip = list_create(instruction(Op_no_op));
else
- $$ = $2;
+ ip = $2;
+ $$ = ip;
}
;
@@ -379,18 +433,45 @@ lex_builtin
: LEX_BUILTIN
| LEX_LENGTH
;
-
+
function_prologue
- : LEX_FUNCTION func_name '(' opt_param_list r_paren opt_nls
+ : LEX_FUNCTION func_name '(' { want_param_names = FUNC_HEADER; } opt_param_list r_paren opt_nls
{
+ /*
+ * treat any comments between BOF and the first function
+ * definition (with no intervening BEGIN etc block) as
+ * program comments. Special kludge: iff there are more
+ * than one such comments, treat the last as a function
+ * comment.
+ */
+ if (prior_comment != NULL) {
+ comment_to_save = prior_comment;
+ prior_comment = NULL;
+ } else if (comment != NULL) {
+ comment_to_save = comment;
+ comment = NULL;
+ } else
+ comment_to_save = NULL;
+
+ if (comment_to_save != NULL && func_first
+ && strstr(comment_to_save->memory->stptr, "\n\n") != NULL)
+ split_comment();
+
+ /* save any other pre-function comment as function comment */
+ if (comment_to_save != NULL) {
+ function_comment = comment_to_save;
+ comment_to_save = NULL;
+ }
+ func_first = false;
$1->source_file = source;
- if (install_function($2->lextok, $1, $4) < 0)
+ if (install_function($2->lextok, $1, $5) < 0)
YYABORT;
in_function = $2->lextok;
$2->lextok = NULL;
bcfree($2);
- /* $4 already free'd in install_function */
+ /* $5 already free'd in install_function */
$$ = $1;
+ want_param_names = FUNC_BODY;
}
;
@@ -432,6 +513,21 @@ regexp
}
;
+typed_regexp
+ : TYPED_REGEXP
+ {
+ char *re;
+ size_t len;
+
+ re = $1->lextok;
+ $1->lextok = NULL;
+ len = strlen(re);
+
+ $$ = $1;
+ $$->opcode = Op_push_re;
+ $$->memory = make_typed_regex(re, len);
+ }
+
a_slash
: '/'
{ bcfree($1); }
@@ -440,19 +536,62 @@ a_slash
statements
: /* empty */
- { $$ = NULL; }
+ {
+ if (prior_comment != NULL) {
+ $$ = list_create(prior_comment);
+ prior_comment = NULL;
+ } else if (comment != NULL) {
+ $$ = list_create(comment);
+ comment = NULL;
+ } else
+ $$ = NULL;
+ }
| statements statement
{
- if ($2 == NULL)
- $$ = $1;
- else {
+ if ($2 == NULL) {
+ if (prior_comment != NULL) {
+ $$ = list_append($1, prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ $$ = list_append($$, comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ $$ = list_append($1, comment);
+ comment = NULL;
+ } else
+ $$ = $1;
+ } else {
add_lint($2, LINT_no_effect);
- if ($1 == NULL)
- $$ = $2;
- else
+ if ($1 == NULL) {
+ if (prior_comment != NULL) {
+ $$ = list_append($2, prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ $$ = list_append($$, comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ $$ = list_append($2, comment);
+ comment = NULL;
+ } else
+ $$ = $2;
+ } else {
+ if (prior_comment != NULL) {
+ list_append($2, prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ list_append($2, comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ list_append($2, comment);
+ comment = NULL;
+ }
$$ = list_merge($1, $2);
+ }
}
- yyerrok;
+ yyerrok;
}
| statements error
{ $$ = NULL; }
@@ -484,7 +623,7 @@ statement
int case_count = 0;
int i;
- tbreak = instruction(Op_no_op);
+ tbreak = instruction(Op_no_op);
cstmt = list_create(tbreak);
cexp = list_create(instruction(Op_pop));
dflt = instruction(Op_jmp);
@@ -496,7 +635,7 @@ statement
} /* else
curr = NULL; */
- for(; curr != NULL; curr = nextc) {
+ for (; curr != NULL; curr = nextc) {
INSTRUCTION *caseexp = curr->case_exp;
INSTRUCTION *casestmt = curr->case_stmt;
@@ -511,7 +650,7 @@ statement
error_ln(curr->source_line,
_("duplicate case values in switch body: %s"), caseval);
}
-
+
if (case_values == NULL)
emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement");
else if (case_count >= maxcount) {
@@ -562,18 +701,18 @@ statement
(void) list_merge(ip, cexp);
$$ = list_merge(ip, cstmt);
- break_allowed--;
+ break_allowed--;
fix_break_continue(ip, tbreak, NULL);
}
| LEX_WHILE '(' exp r_paren opt_nls statement
- {
+ {
/*
* -----------------
* tc:
* cond
* -----------------
* [Op_jmp_false tb ]
- * -----------------
+ * -----------------
* body
* -----------------
* [Op_jmp tc ]
@@ -614,7 +753,7 @@ statement
* z:
* body
* -----------------
- * tc:
+ * tc:
* cond
* -----------------
* [Op_jmp_true | z ]
@@ -661,7 +800,7 @@ statement
&& ($8->nexti->memory->type != Node_var || !($8->nexti->memory->var_update))
&& strcmp($8->nexti->memory->vname, var_name) == 0
) {
-
+
/* Efficiency hack. Recognize the special case of
*
* for (iggy in foo)
@@ -673,10 +812,10 @@ statement
*
* Check that the body is a `delete a[i]' statement,
* and that both the loop var and array names match.
- */
+ */
NODE *arr = NULL;
- ip = $8->nexti->nexti;
+ ip = $8->nexti->nexti;
if ($5->nexti->opcode == Op_push && $5->lasti == $5->nexti)
arr = $5->nexti->memory;
if (arr != NULL
@@ -702,7 +841,7 @@ statement
/* [ Op_push_array a ]
* [ Op_arrayfor_init | ib ]
- * ic:[ Op_arrayfor_incr | ib ]
+ * ic:[ Op_arrayfor_incr | ib ]
* [ Op_var_assign if any ]
*
* body
@@ -731,7 +870,7 @@ regular_loop:
} /* else
$1 is NULL */
- /* add update_FOO instruction if necessary */
+ /* add update_FOO instruction if necessary */
if ($4->array_var->type == Node_var && $4->array_var->var_update) {
(void) list_append(ip, instruction(Op_var_update));
ip->lasti->update_var = $4->array_var->var_update;
@@ -747,7 +886,7 @@ regular_loop:
if (do_pretty_print) {
(void) list_append(ip, instruction(Op_exec_count));
($1 + 1)->forloop_cond = $4;
- ($1 + 1)->forloop_body = ip->lasti;
+ ($1 + 1)->forloop_body = ip->lasti;
}
if ($8 != NULL)
@@ -757,7 +896,7 @@ regular_loop:
ip->lasti->target_jmp = $4;
$$ = list_append(ip, tbreak);
fix_break_continue(ip, tbreak, tcont);
- }
+ }
break_allowed--;
continue_allowed--;
@@ -782,17 +921,19 @@ regular_loop:
$$ = list_prepend($1, instruction(Op_exec_count));
else
$$ = $1;
+ $$ = add_pending_comment($$);
}
;
non_compound_stmt
: LEX_BREAK statement_term
- {
+ {
if (! break_allowed)
error_ln($1->source_line,
_("`break' is not allowed outside a loop or switch"));
$1->target_jmp = NULL;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_CONTINUE statement_term
@@ -802,6 +943,7 @@ non_compound_stmt
_("`continue' is not allowed outside a loop"));
$1->target_jmp = NULL;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_NEXT statement_term
@@ -812,6 +954,7 @@ non_compound_stmt
_("`next' used in %s action"), ruletab[rule]);
$1->target_jmp = ip_rec;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_NEXTFILE statement_term
{
@@ -823,11 +966,12 @@ non_compound_stmt
$1->target_newfile = ip_newfile;
$1->target_endfile = ip_endfile;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_EXIT opt_exp statement_term
{
/* Initialize the two possible jump targets, the actual target
- * is resolved at run-time.
+ * is resolved at run-time.
*/
$1->target_end = ip_end; /* first instruction in end_block */
$1->target_atexit = ip_atexit; /* cleanup and go home */
@@ -838,6 +982,7 @@ non_compound_stmt
$$->nexti->memory = dupnode(Nnull_string);
} else
$$ = list_append($2, $1);
+ $$ = add_pending_comment($$);
}
| LEX_RETURN
{
@@ -862,6 +1007,7 @@ non_compound_stmt
$$ = list_append($3, $1);
}
+ $$ = add_pending_comment($$);
}
| simple_stmt statement_term
;
@@ -943,7 +1089,7 @@ simple_stmt
* [$1 | NULL | redir_type | expr_count]
*
*/
-regular_print:
+regular_print:
if ($4 == NULL) { /* no redirection */
if ($3 == NULL) { /* printf without arg */
$1->expr_count = 0;
@@ -971,6 +1117,7 @@ regular_print:
}
}
}
+ $$ = add_pending_comment($$);
}
| LEX_DELETE NAME { sub_counter = 0; } delete_subscript_list
@@ -1005,7 +1152,8 @@ regular_print:
$1->expr_count = sub_counter;
$$ = list_append(list_append($4, $2), $1);
}
- }
+ $$ = add_pending_comment($$);
+ }
| LEX_DELETE '(' NAME ')'
/*
* this is for tawk compatibility. maybe the warnings
@@ -1035,9 +1183,13 @@ regular_print:
else if ($3->memory == func_table)
fatal(_("`delete' is not allowed with FUNCTAB"));
}
+ $$ = add_pending_comment($$);
}
| exp
- { $$ = optimize_assignment($1); }
+ {
+ $$ = optimize_assignment($1);
+ $$ = add_pending_comment($$);
+ }
;
opt_simple_stmt
@@ -1066,7 +1218,7 @@ case_statement
{
INSTRUCTION *casestmt = $5;
if ($5 == NULL)
- casestmt = list_create(instruction(Op_no_op));
+ casestmt = list_create(instruction(Op_no_op));
if (do_pretty_print)
(void) list_prepend(casestmt, instruction(Op_exec_count));
$1->case_exp = $2;
@@ -1091,7 +1243,7 @@ case_value
: YNUMBER
{ $$ = $1; }
| '-' YNUMBER %prec UNARY
- {
+ {
NODE *n = $2->memory;
(void) force_number(n);
negate_num(n);
@@ -1100,13 +1252,24 @@ case_value
}
| '+' YNUMBER %prec UNARY
{
+ NODE *n = $2->lasti->memory;
bcfree($1);
+ add_sign_to_num(n, '+');
$$ = $2;
}
- | YSTRING
+ | YSTRING
{ $$ = $1; }
- | regexp
+ | regexp
{
+ if ($1->memory->type == Node_regex)
+ $1->opcode = Op_push_re;
+ else
+ $1->opcode = Op_push;
+ $$ = $1;
+ }
+ | typed_regexp
+ {
+ assert(($1->memory->flags & REGEX) == REGEX);
$1->opcode = Op_push_re;
$$ = $1;
}
@@ -1184,7 +1347,7 @@ opt_param_list
: /* empty */
{ $$ = NULL; }
| param_list
- { $$ = $1 ; }
+ { $$ = $1; }
;
param_list
@@ -1255,6 +1418,48 @@ expression_list
}
;
+opt_fcall_expression_list
+ : /* empty */
+ { $$ = NULL; }
+ | fcall_expression_list
+ { $$ = $1; }
+ ;
+
+fcall_expression_list
+ : fcall_exp
+ { $$ = mk_expression_list(NULL, $1); }
+ | fcall_expression_list comma fcall_exp
+ {
+ $$ = mk_expression_list($1, $3);
+ yyerrok;
+ }
+ | error
+ { $$ = NULL; }
+ | fcall_expression_list error
+ {
+ /*
+ * Returning the expression list instead of NULL lets
+ * snode get a list of arguments that it can count.
+ */
+ $$ = $1;
+ }
+ | fcall_expression_list error fcall_exp
+ {
+ /* Ditto */
+ $$ = mk_expression_list($1, $3);
+ }
+ | fcall_expression_list comma error
+ {
+ /* Ditto */
+ $$ = $1;
+ }
+ ;
+
+fcall_exp
+ : exp { $$ = $1; }
+ | typed_regexp { $$ = list_create($1); }
+ ;
+
/* Expressions, not including the comma operator. */
exp
: variable assign_operator exp %prec ASSIGNOP
@@ -1264,10 +1469,27 @@ exp
_("regular expression on right of assignment"));
$$ = mk_assignment($1, $3, $2);
}
+ | variable ASSIGN typed_regexp %prec ASSIGNOP
+ {
+ $$ = mk_assignment($1, list_create($3), $2);
+ }
| exp LEX_AND exp
{ $$ = mk_boolean($1, $3, $2); }
| exp LEX_OR exp
{ $$ = mk_boolean($1, $3, $2); }
+ | exp MATCHOP typed_regexp
+ {
+ if ($1->lasti->opcode == Op_match_rec)
+ warning_ln($2->source_line,
+ _("regular expression on left of `~' or `!~' operator"));
+
+ assert($3->opcode == Op_push_re
+ && ($3->memory->flags & REGEX) != 0);
+ /* RHS is @/.../ */
+ $2->memory = $3->memory;
+ bcfree($3);
+ $$ = list_append($1, $2);
+ }
| exp MATCHOP exp
{
if ($1->lasti->opcode == Op_match_rec)
@@ -1275,6 +1497,7 @@ exp
_("regular expression on left of `~' or `!~' operator"));
if ($3->lasti == $3->nexti && $3->nexti->opcode == Op_match_rec) {
+ /* RHS is /.../ */
$2->memory = $3->nexti->memory;
bcfree($3->nexti); /* Op_match_rec */
bcfree($3); /* Op_list */
@@ -1313,7 +1536,7 @@ assign_operator
| ASSIGNOP
{ $$ = $1; }
| SLASH_BEFORE_EQUAL ASSIGN /* `/=' */
- {
+ {
$2->opcode = Op_assign_quotient;
$$ = $2;
}
@@ -1364,10 +1587,15 @@ common_exp
NODE *n2 = $2->nexti->memory;
size_t nlen;
+ // 1.5 "" # can't fold this if program mucks with CONVFMT.
+ // See test #12 in test/posix.awk.
+ if ((n1->flags & (NUMBER|NUMINT)) != 0 || (n2->flags & (NUMBER|NUMINT)) != 0)
+ goto plain_concat;
+
n1 = force_string(n1);
n2 = force_string(n2);
nlen = n1->stlen + n2->stlen;
- erealloc(n1->stptr, char *, nlen + 2, "constant fold");
+ erealloc(n1->stptr, char *, nlen + 1, "constant fold");
memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
n1->stlen = nlen;
n1->stptr[nlen] = '\0';
@@ -1378,6 +1606,7 @@ common_exp
bcfree($2);
$$ = $1;
} else {
+ plain_concat:
$$ = list_append(list_merge($1, $2), instruction(Op_concat));
$$->lasti->concat_flag = (is_simple_var ? CSVAR : 0);
$$->lasti->expr_count = count;
@@ -1481,7 +1710,7 @@ non_post_simp_exp
if ($2->opcode == Op_match_rec) {
$2->opcode = Op_nomatch;
$1->opcode = Op_push_i;
- $1->memory = make_number(0.0);
+ $1->memory = set_profile_text(make_number(0.0), "0", 1);
$$ = list_append(list_append(list_create($1),
instruction(Op_field_spec)), $2);
} else {
@@ -1490,7 +1719,7 @@ non_post_simp_exp
&& ($2->nexti->memory->flags & (MPFN|MPZN)) == 0
) {
NODE *n = $2->nexti->memory;
- if ((n->flags & (STRCUR|STRING)) != 0) {
+ if ((n->flags & STRING) != 0) {
n->numbr = (AWKNUM) (n->stlen == 0);
n->flags &= ~(STRCUR|STRING);
n->flags |= (NUMCUR|NUMBER);
@@ -1509,14 +1738,19 @@ non_post_simp_exp
}
}
| '(' exp r_paren
- { $$ = $2; }
- | LEX_BUILTIN '(' opt_expression_list r_paren
+ {
+ if (do_pretty_print)
+ $$ = list_append($2, bcalloc(Op_parens, 1, sourceline));
+ else
+ $$ = $2;
+ }
+ | LEX_BUILTIN '(' opt_fcall_expression_list r_paren
{
$$ = snode($3, $1);
if ($$ == NULL)
YYABORT;
}
- | LEX_LENGTH '(' opt_expression_list r_paren
+ | LEX_LENGTH '(' opt_fcall_expression_list r_paren
{
$$ = snode($3, $1);
if ($$ == NULL)
@@ -1558,11 +1792,11 @@ non_post_simp_exp
| '-' simp_exp %prec UNARY
{
if ($2->lasti->opcode == Op_push_i
- && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0
+ && ($2->lasti->memory->flags & STRING) == 0
) {
NODE *n = $2->lasti->memory;
(void) force_number(n);
- negate_num(n);
+ negate_num(n);
$$ = $2;
bcfree($1);
} else {
@@ -1572,13 +1806,21 @@ non_post_simp_exp
}
| '+' simp_exp %prec UNARY
{
- /*
- * was: $$ = $2
- * POSIX semantics: force a conversion to numeric type
- */
- $1->opcode = Op_plus_i;
- $1->memory = make_number(0.0);
- $$ = list_append($2, $1);
+ if ($2->lasti->opcode == Op_push_i
+ && ($2->lasti->memory->flags & STRING) == 0
+ && ($2->lasti->memory->flags & NUMCONSTSTR) != 0) {
+ NODE *n = $2->lasti->memory;
+ add_sign_to_num(n, '+');
+ $$ = $2;
+ bcfree($1);
+ } else {
+ /*
+ * was: $$ = $2
+ * POSIX semantics: force a conversion to numeric type
+ */
+ $1->opcode = Op_unary_plus;
+ $$ = list_append($2, $1);
+ }
}
;
@@ -1603,7 +1845,7 @@ func_call
warned = true;
lintwarn("%s", msg);
}
-
+
f = $2->lasti;
f->opcode = Op_indirect_func_call;
name = estrdup(f->func_name, strlen(f->func_name));
@@ -1625,14 +1867,14 @@ func_call
;
direct_func_call
- : FUNC_CALL '(' opt_expression_list r_paren
+ : FUNC_CALL '(' opt_fcall_expression_list r_paren
{
NODE *n;
if (! at_seen) {
n = lookup($1->func_name);
if (n != NULL && n->type != Node_func
- && n->type != Node_ext_func && n->type != Node_old_ext_func) {
+ && n->type != Node_ext_func) {
error_ln($1->source_line,
_("attempt to use non-function `%s' in function call"),
$1->func_name);
@@ -1646,7 +1888,7 @@ direct_func_call
$$ = list_create($1);
} else {
INSTRUCTION *t = $3;
- ($1 + 1)->expr_count = count_expressions(&t, true);
+ ($1 + 1)->expr_count = count_expressions(&t, true);
$$ = list_append(t, $1);
}
}
@@ -1678,7 +1920,7 @@ delete_subscript
delete_exp_list
: bracketed_exp_list
{
- INSTRUCTION *ip = $1->lasti;
+ INSTRUCTION *ip = $1->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated expressions */
if (count > 1) {
/* change Op_subscript or Op_sub_array to Op_concat */
@@ -1702,7 +1944,7 @@ bracketed_exp_list
/* install Null string as subscript. */
t = list_create(instruction(Op_push_i));
t->nexti->memory = dupnode(Nnull_string);
- $3->sub_count = 1;
+ $3->sub_count = 1;
} else
$3->sub_count = count_expressions(&t, false);
$$ = list_append(t, $3);
@@ -1818,7 +2060,7 @@ struct token {
# 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 */
};
@@ -1878,9 +2120,6 @@ static const struct token tokentab[] = {
{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
-#ifdef DYNAMIC
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
-#endif
{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0},
{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
@@ -1893,13 +2132,14 @@ static const struct token tokentab[] = {
{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0, 0},
{"index", Op_builtin, LEX_BUILTIN, A(2), do_index, 0},
{"int", Op_builtin, LEX_BUILTIN, A(1), do_int, MPF(int)},
+{"intdiv", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_intdiv, MPF(intdiv)},
{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray, 0},
{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length, 0},
{"load", Op_symbol, LEX_LOAD, GAWKX, 0, 0},
{"log", Op_builtin, LEX_BUILTIN, A(1), do_log, MPF(log)},
{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)},
{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0},
-{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime, 0},
+{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_mktime, 0},
{"next", Op_K_next, LEX_NEXT, 0, 0, 0},
{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0},
{"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)},
@@ -1926,6 +2166,7 @@ static const struct token tokentab[] = {
{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0},
{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0},
{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0},
+{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_typeof, 0},
{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0},
{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)},
};
@@ -1951,7 +2192,7 @@ getfname(NODE *(*fptr)(int))
j = sizeof(tokentab) / sizeof(tokentab[0]);
/* linear search, no other way to do it */
- for (i = 0; i < j; i++)
+ for (i = 0; i < j; i++)
if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr)
return tokentab[i].operator;
@@ -1967,6 +2208,8 @@ negate_num(NODE *n)
int tval = 0;
#endif
+ add_sign_to_num(n, '-');
+
if (! is_mpg_number(n)) {
n->numbr = -n->numbr;
return;
@@ -1999,6 +2242,21 @@ negate_num(NODE *n)
#endif
}
+/* add_sign_to_num --- make a constant unary plus or minus for profiling */
+
+static void
+add_sign_to_num(NODE *n, char sign)
+{
+ if ((n->flags & NUMCONSTSTR) != 0) {
+ char *s;
+
+ s = n->stptr;
+ memmove(& s[1], & s[0], n->stlen + 1);
+ s[0] = sign;
+ n->stlen++;
+ }
+}
+
/* print_included_from --- print `Included from ..' file names and locations */
static void
@@ -2007,7 +2265,7 @@ print_included_from()
int saveline, line;
SRCFILE *s;
- /* suppress current file name, line # from `.. included from ..' msgs */
+ /* suppress current file name, line # from `.. included from ..' msgs */
saveline = sourceline;
sourceline = 0;
@@ -2101,7 +2359,6 @@ yyerror(const char *m, ...)
char *buf;
int count;
static char end_of_file_line[] = "(END OF FILE)";
- char save;
print_included_from();
@@ -2132,25 +2389,16 @@ yyerror(const char *m, ...)
bp = thisline + strlen(thisline);
}
- /*
- * Saving and restoring *bp keeps valgrind happy,
- * since the guts of glibc uses strlen, even though
- * we're passing an explict precision. Sigh.
- *
- * 8/2003: We may not need this anymore.
- */
- save = *bp;
- *bp = '\0';
-
msg("%.*s", (int) (bp - thisline), thisline);
- *bp = save;
va_start(args, m);
if (mesg == NULL)
mesg = m;
- count = (bp - thisline) + strlen(mesg) + 2 + 1;
- emalloc(buf, char *, count, "yyerror");
+ count = strlen(mesg) + 1;
+ if (lexptr != NULL)
+ count += (lexeme - thisline) + 2;
+ ezalloc(buf, char *, count+1, "yyerror");
bp = buf;
@@ -2217,7 +2465,7 @@ mk_program()
if (prog_block == NULL) {
if (end_block->nexti == end_block->lasti
- && beginfile_block->nexti == beginfile_block->lasti
+ && beginfile_block->nexti == beginfile_block->lasti
&& endfile_block->nexti == endfile_block->lasti
) {
/* no pattern-action and (real) end, beginfile or endfile blocks */
@@ -2232,6 +2480,11 @@ mk_program()
cp = end_block;
else
cp = list_merge(begin_block, end_block);
+ if (program_comment != NULL) {
+ (void) list_prepend(cp, program_comment);
+ }
+ if (comment != NULL)
+ (void) list_append(cp, comment);
(void) list_append(cp, ip_atexit);
(void) list_append(cp, instruction(Op_stop));
@@ -2254,7 +2507,7 @@ mk_program()
(void) list_prepend(prog_block, ip_rec);
(void) list_append(prog_block, instruction(Op_jmp));
prog_block->lasti->target_jmp = ip_rec;
-
+
list_append(beginfile_block, instruction(Op_after_beginfile));
cp = list_merge(beginfile_block, prog_block);
@@ -2264,6 +2517,12 @@ mk_program()
if (begin_block != NULL)
cp = list_merge(begin_block, cp);
+ if (program_comment != NULL) {
+ (void) list_prepend(cp, program_comment);
+ }
+ if (comment != NULL) {
+ (void) list_append(cp, comment);
+ }
(void) list_append(cp, ip_atexit);
(void) list_append(cp, instruction(Op_stop));
@@ -2271,13 +2530,17 @@ out:
/* delete the Op_list, not needed */
tmp = cp->nexti;
bcfree(cp);
+ /* these variables are not used again but zap them anyway. */
+ comment = NULL;
+ function_comment = NULL;
+ program_comment = NULL;
return tmp;
#undef begin_block
#undef end_block
#undef prog_block
#undef beginfile_block
-#undef endfile_block
+#undef endfile_block
}
/* parse_program --- read in the program and convert into a list of instructions */
@@ -2297,7 +2560,7 @@ parse_program(INSTRUCTION **pcode)
ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL;
else {
ip_endfile = instruction(Op_no_op);
- ip_beginfile = instruction(Op_no_op);
+ main_beginfile = ip_beginfile = instruction(Op_no_op);
ip_rec = instruction(Op_get_record); /* target for `next', also ip_newfile */
ip_newfile = bcalloc(Op_newfile, 2, 0); /* target for `nextfile' */
ip_newfile->target_jmp = ip_end;
@@ -2354,8 +2617,7 @@ do_add_srcfile(enum srctype stype, char *src, char *path, SRCFILE *thisfile)
{
SRCFILE *s;
- emalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile");
- memset(s, 0, sizeof(SRCFILE));
+ ezalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile");
s->src = estrdup(src, strlen(src));
s->fullpath = path;
s->stype = stype;
@@ -2428,7 +2690,7 @@ add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_incl
*already_included = true;
return NULL;
} else {
- /* duplicates are allowed for -f */
+ /* duplicates are allowed for -f */
if (s->stype == SRC_INC)
fatal(_("can't include `%s' and use it as a program file"), src);
/* no need to scan for further matches, since
@@ -2479,11 +2741,11 @@ include_source(INSTRUCTION *file)
sourcefile->srclines = sourceline;
sourcefile->lexptr = lexptr;
sourcefile->lexend = lexend;
- sourcefile->lexptr_begin = lexptr_begin;
+ sourcefile->lexptr_begin = lexptr_begin;
sourcefile->lexeme = lexeme;
sourcefile->lasttok = lasttok;
- /* included file becomes the current source */
+ /* included file becomes the current source */
sourcefile = s;
lexptr = NULL;
sourceline = 0;
@@ -2768,7 +3030,7 @@ get_src_buf()
lexend = lexptr + n;
if (n == 0) {
static bool warned = false;
- if (do_lint && newfile && ! warned){
+ if (do_lint && newfile && ! warned) {
warned = true;
sourceline = 0;
lintwarn(_("source file `%s' is empty"), source);
@@ -2790,7 +3052,7 @@ tokexpand()
{
static int toksize;
int tokoffset;
-
+
if (tokstart != NULL) {
tokoffset = tok - tokstart;
toksize *= 2;
@@ -2840,8 +3102,17 @@ nextc(bool check_for_bad)
{
if (gawk_mb_cur_max > 1) {
again:
+#ifdef NO_CONTINUE_SOURCE_STRINGS
if (lexeof)
return END_FILE;
+#else
+ if (lexeof) {
+ if (sourcefile->next == srcfiles)
+ return END_FILE;
+ else
+ next_sourcefile();
+ }
+#endif
if (lexptr == NULL || lexptr >= lexend) {
if (get_src_buf())
goto again;
@@ -2858,8 +3129,8 @@ again:
int idx, work_ring_idx = cur_ring_idx;
mbstate_t tmp_state;
size_t mbclen;
-
- for (idx = 0 ; lexptr + idx < lexend ; idx++) {
+
+ for (idx = 0; lexptr + idx < lexend; idx++) {
tmp_state = cur_mbstate;
mbclen = mbrlen(lexptr, idx + 1, &tmp_state);
@@ -2893,8 +3164,17 @@ again:
return (int) (unsigned char) *lexptr++;
} else {
do {
+#ifdef NO_CONTINUE_SOURCE_STRINGS
if (lexeof)
return END_FILE;
+#else
+ if (lexeof) {
+ if (sourcefile->next == srcfiles)
+ return END_FILE;
+ else
+ next_sourcefile();
+ }
+#endif
if (lexptr && lexptr < lexend) {
if (check_for_bad || *lexptr == '\0')
check_bad_char(*lexptr);
@@ -2916,6 +3196,122 @@ pushback(void)
(! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr);
}
+/* check_comment --- check for block comment */
+
+void
+check_comment(void)
+{
+ if (comment != NULL) {
+ if (first_rule) {
+ program_comment = comment;
+ } else
+ block_comment = comment;
+ comment = NULL;
+ }
+ first_rule = false;
+}
+
+/*
+ * get_comment --- collect comment text.
+ * Flag = EOL_COMMENT for end-of-line comments.
+ * Flag = FULL_COMMENT for self-contained comments.
+ */
+
+int
+get_comment(int flag)
+{
+ int c;
+ int sl;
+ tok = tokstart;
+ tokadd('#');
+ sl = sourceline;
+ char *p1;
+ char *p2;
+
+ while (true) {
+ while ((c = nextc(false)) != '\n' && c != END_FILE) {
+ /* ignore \r characters */
+ if (c != '\r')
+ tokadd(c);
+ }
+ if (flag == EOL_COMMENT) {
+ /* comment at end of line. */
+ if (c == '\n')
+ tokadd(c);
+ break;
+ }
+ if (c == '\n') {
+ tokadd(c);
+ sourceline++;
+ do {
+ c = nextc(false);
+ if (c == '\n') {
+ sourceline++;
+ tokadd(c);
+ }
+ } while (isspace(c) && c != END_FILE);
+ if (c == END_FILE)
+ break;
+ else if (c != '#') {
+ pushback();
+ sourceline--;
+ break;
+ } else
+ tokadd(c);
+ } else
+ break;
+ }
+
+ if (comment != NULL)
+ prior_comment = comment;
+
+ /* remove any trailing blank lines (consecutive \n) from comment */
+ p1 = tok - 1;
+ p2 = tok - 2;
+ while (*p1 == '\n' && *p2 == '\n') {
+ p1--;
+ p2--;
+ tok--;
+ }
+
+ comment = bcalloc(Op_comment, 1, sl);
+ comment->source_file = source;
+ comment->memory = make_str_node(tokstart, tok - tokstart, 0);
+ comment->memory->comment_type = flag;
+
+ return c;
+}
+
+/* split_comment --- split initial comment text into program and function parts */
+
+static void
+split_comment(void)
+{
+ char *p;
+ int l;
+ NODE *n;
+
+ p = comment_to_save->memory->stptr;
+ l = comment_to_save->memory->stlen - 3;
+ /* have at least two comments so split at last blank line (\n\n) */
+ while (l >= 0) {
+ if (p[l] == '\n' && p[l+1] == '\n') {
+ function_comment = comment_to_save;
+ n = function_comment->memory;
+ function_comment->memory = make_string(p + l + 2, n->stlen - l - 2);
+ /* create program comment */
+ program_comment = bcalloc(Op_comment, 1, sourceline);
+ program_comment->source_file = comment_to_save->source_file;
+ p[l + 2] = 0;
+ program_comment->memory = make_str_node(p, l + 2, 0);
+ comment_to_save = NULL;
+ freenode(n);
+ break;
+ }
+ else
+ l--;
+ }
+}
/* allow_newline --- allow newline after &&, ||, ? and : */
@@ -2931,8 +3327,13 @@ allow_newline(void)
break;
}
if (c == '#') {
- while ((c = nextc(false)) != '\n' && c != END_FILE)
- continue;
+ if (do_pretty_print && ! do_profile) {
+ /* collect comment byte code iff doing pretty print but not profiling. */
+ c = get_comment(EOL_COMMENT);
+ } else {
+ while ((c = nextc(false)) != '\n' && c != END_FILE)
+ continue;
+ }
if (c == END_FILE) {
pushback();
break;
@@ -2955,7 +3356,8 @@ allow_newline(void)
* removes the warnings.
*/
-static int newline_eof()
+static int
+newline_eof()
{
/* NB: a newline at end does not start a source line. */
if (lasttok != NEWLINE) {
@@ -2993,6 +3395,7 @@ yylex(void)
bool inhex = false;
bool intlstr = false;
AWKNUM d;
+ bool collecting_typed_regexp = false;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -3003,7 +3406,7 @@ yylex(void)
lasttok = 0;
return SUBSCRIPT;
}
-
+
if (lasttok == LEX_EOF) /* error earlier in current source, must give up !! */
return 0;
@@ -3027,6 +3430,8 @@ yylex(void)
lexeme = lexptr;
thisline = NULL;
+
+collect_regexp:
if (want_regexp) {
int in_brack = 0; /* count brackets, [[:alnum:]] allowed */
int b_index = -1;
@@ -3037,7 +3442,7 @@ yylex(void)
*
* [..[..] []] [^]] [.../...]
* [...\[...] [...\]...] [...\/...]
- *
+ *
* (Remember that all of the above are inside /.../)
*
* The code for \ handles \[, \] and \/.
@@ -3066,7 +3471,7 @@ yylex(void)
break;
case ']':
if (in_brack > 0
- && (cur_index == b_index + 1
+ && (cur_index == b_index + 1
|| (cur_index == b_index + 2 && tok[-1] == '^')))
; /* do nothing */
else {
@@ -3113,7 +3518,13 @@ end_regexp:
peek);
}
}
- return lasttok = REGEXP;
+ if (collecting_typed_regexp) {
+ collecting_typed_regexp = false;
+ lasttok = TYPED_REGEXP;
+ } else
+ lasttok = REGEXP;
+
+ return lasttok;
case '\n':
pushback();
yyerror(_("unterminated regexp"));
@@ -3149,21 +3560,42 @@ retry:
return lasttok = NEWLINE;
case '#': /* it's a comment */
- while ((c = nextc(false)) != '\n') {
+ if (do_pretty_print && ! do_profile) {
+ /*
+ * Collect comment byte code iff doing pretty print
+ * but not profiling.
+ */
+ if (lasttok == NEWLINE || lasttok == 0)
+ c = get_comment(FULL_COMMENT);
+ else
+ c = get_comment(EOL_COMMENT);
+
if (c == END_FILE)
return lasttok = NEWLINE_EOF;
+ } else {
+ while ((c = nextc(false)) != '\n') {
+ if (c == END_FILE)
+ return lasttok = NEWLINE_EOF;
+ }
}
sourceline++;
return lasttok = NEWLINE;
case '@':
+ c = nextc(true);
+ if (c == '/') {
+ want_regexp = true;
+ collecting_typed_regexp = true;
+ goto collect_regexp;
+ }
+ pushback();
at_seen = true;
return lasttok = '@';
case '\\':
#ifdef RELAXED_CONTINUATION
/*
- * This code puports to allow comments and/or whitespace
+ * This code purports to allow comments and/or whitespace
* after the `\' at the end of a line used for continuation.
* Use it at your own risk. We think it's a bad idea, which
* is why it's not on by default.
@@ -3180,9 +3612,13 @@ retry:
lintwarn(
_("use of `\\ #...' line continuation is not portable"));
}
- while ((c = nextc(false)) != '\n')
- if (c == END_FILE)
- break;
+ if (do_pretty_print && ! do_profile)
+ c = get_comment(EOL_COMMENT);
+ else {
+ while ((c = nextc(false)) != '\n')
+ if (c == END_FILE)
+ break;
+ }
}
pushback();
}
@@ -3214,7 +3650,7 @@ retry:
in_parens--;
return lasttok = c;
- case '(':
+ case '(':
in_parens++;
return lasttok = c;
case '$':
@@ -3317,7 +3753,7 @@ retry:
did_warn_op = true;
warning(_("operator `^' is not supported in old awk"));
}
- yylval = GET_INSTRUCTION(Op_exp);
+ yylval = GET_INSTRUCTION(Op_exp);
return lasttok = '^';
}
@@ -3440,7 +3876,7 @@ retry:
yylval->lextok = estrdup(tokstart, tok - tokstart);
return lasttok = FILENAME;
}
-
+
yylval->opcode = Op_push_i;
yylval->memory = make_str_node(tokstart,
tok - tokstart, esc_seen ? SCAN : 0);
@@ -3579,7 +4015,7 @@ retry:
base = 10;
if (! do_traditional) {
- base = get_numbase(tokstart, false);
+ base = get_numbase(tokstart, strlen(tokstart)-1, false);
if (do_lint) {
if (base == 8)
lintwarn("numeric constant `%.*s' treated as octal",
@@ -3605,15 +4041,15 @@ retry:
errno = 0;
IEEE_FMT(r->mpg_numbr, tval);
}
- yylval->memory = r;
+ yylval->memory = set_profile_text(r, tokstart, strlen(tokstart)-1);
return lasttok = YNUMBER;
}
#endif
if (base != 10)
- d = nondec2awknum(tokstart, strlen(tokstart));
+ d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL);
else
d = atof(tokstart);
- yylval->memory = make_number(d);
+ yylval->memory = set_profile_text(make_number(d), tokstart, strlen(tokstart) - 1);
if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
yylval->memory->flags |= NUMINT;
return lasttok = YNUMBER;
@@ -3696,6 +4132,33 @@ retry:
&& lasttok != '@')
goto out;
+ /* allow parameter names to shadow the names of gawk extension built-ins */
+ if ((tokentab[mid].flags & GAWKX) != 0) {
+ NODE *f;
+
+ switch (want_param_names) {
+ case FUNC_HEADER:
+ /* in header, defining parameter names */
+ goto out;
+ case FUNC_BODY:
+ /* in body, name must be in symbol table for it to be a parameter */
+ if ((f = lookup(tokstart)) != NULL) {
+ if (f->type == Node_builtin_func)
+ break;
+ else
+ goto out;
+ }
+ /* else
+ fall through */
+ case DONT_CHECK:
+ /* regular code */
+ break;
+ default:
+ cant_happen();
+ break;
+ }
+ }
+
if (do_lint) {
if ((tokentab[mid].flags & GAWKX) != 0 && (warntab[mid] & GAWKX) == 0) {
lintwarn(_("`%s' is a gawk extension"),
@@ -3740,7 +4203,7 @@ retry:
case LEX_BEGIN:
case LEX_END:
case LEX_BEGINFILE:
- case LEX_ENDFILE:
+ case LEX_ENDFILE:
yylval = bcalloc(tokentab[mid].value, 3, sourceline);
break;
@@ -3789,7 +4252,7 @@ out:
tokkey = estrdup(tokstart, tok - tokstart);
if (*lexptr == '(') {
yylval = bcalloc(Op_token, 2, sourceline);
- yylval->lextok = tokkey;
+ yylval->lextok = tokkey;
return lasttok = FUNC_CALL;
} else {
static bool goto_warned = false;
@@ -3865,7 +4328,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
nexp++;
}
assert(nexp > 0);
- }
+ }
/* check against how many args. are allowed for this builtin */
args_allowed = tokentab[idx].flags & ARGS;
@@ -3896,7 +4359,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
INSTRUCTION *expr;
expr = list_create(instruction(Op_push_i));
- expr->nexti->memory = make_number(0.0);
+ expr->nexti->memory = set_profile_text(make_number(0.0), "0", 1);
(void) mk_expression_list(subn,
list_append(expr, instruction(Op_field_spec)));
}
@@ -3936,7 +4399,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
subn->lasti->assign_ctxt = Op_sub_builtin;
}
- return subn;
+ return subn;
} else {
/* gensub */
@@ -3944,7 +4407,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
r->sub_flags |= GENSUB;
if (nexp == 3) {
ip = instruction(Op_push_i);
- ip->memory = make_number(0.0);
+ ip->memory = set_profile_text(make_number(0.0), "0", 1);
(void) mk_expression_list(subn,
list_append(list_create(ip), instruction(Op_field_spec)));
}
@@ -3955,7 +4418,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
#ifdef HAVE_MPFR
- /* N.B.: There isn't any special processing for an alternate function below */
+ /* N.B.: If necessary, add special processing for alternate builtin, below */
if (do_mpfr && tokentab[idx].ptr2)
r->builtin = tokentab[idx].ptr2;
else
@@ -3965,25 +4428,34 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
/* special case processing for a few builtins */
if (r->builtin == do_length) {
- if (nexp == 0) {
+ if (nexp == 0) {
/* no args. Use $0 */
INSTRUCTION *list;
- r->expr_count = 1;
+ r->expr_count = 1;
list = list_create(r);
(void) list_prepend(list, instruction(Op_field_spec));
(void) list_prepend(list, instruction(Op_push_i));
- list->nexti->memory = make_number(0.0);
- return list;
+ list->nexti->memory = set_profile_text(make_number(0.0), "0", 1);
+ return list;
} else {
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
arg->nexti->opcode = Op_push_arg; /* argument may be array */
}
- } else if (r->builtin == do_isarray) {
+ } else if (r->builtin == do_isarray || r->builtin == do_typeof) {
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
- arg->nexti->opcode = Op_push_arg; /* argument may be array */
+ arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */
+ } else if (r->builtin == do_intdiv
+#ifdef HAVE_MPFR
+ || r->builtin == MPF(intdiv)
+#endif
+ ) {
+ arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
+ ip = arg->lasti;
+ if (ip->opcode == Op_push)
+ ip->opcode = Op_push_array;
} else if (r->builtin == do_match) {
static bool warned = false;
@@ -4060,7 +4532,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
} else if (do_intl /* --gen-po */
&& r->builtin == do_dcgettext /* dcgettext(...) */
&& subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */
- && (subn->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */
+ && (subn->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */
/* ala xgettext, dcgettext("some string" ...) dumps the string */
NODE *str = subn->nexti->lasti->memory;
@@ -4072,9 +4544,9 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
} else if (do_intl /* --gen-po */
&& r->builtin == do_dcngettext /* dcngettext(...) */
&& subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */
- && (subn->nexti->lasti->memory->flags & STRCUR) != 0 /* it's a string constant */
+ && (subn->nexti->lasti->memory->flags & STRING) != 0 /* it's a string constant */
&& subn->nexti->lasti->nexti->lasti->opcode == Op_push_i /* 2nd arg is constant too */
- && (subn->nexti->lasti->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */
+ && (subn->nexti->lasti->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */
/* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */
NODE *str1 = subn->nexti->lasti->memory;
NODE *str2 = subn->nexti->lasti->nexti->lasti->memory;
@@ -4169,6 +4641,8 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
{
if (n == Nnull_string)
print_func(fp, "uninitialized scalar\n");
+ else if ((n->flags & REGEX) != 0)
+ print_func(fp, "@/%.*s/\n", n->stlen, n->stptr);
else if ((n->flags & STRING) != 0) {
pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
print_func(fp, "\n");
@@ -4181,18 +4655,6 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
else
#endif
print_func(fp, "%.17g\n", n->numbr);
- } else if ((n->flags & STRCUR) != 0) {
- pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
- print_func(fp, "\n");
- } else if ((n->flags & NUMCUR) != 0) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
} else
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
@@ -4281,6 +4743,14 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
(t + 1)->tail_call = true;
}
+ /* add any pre-function comment to start of action for profile.c */
+
+ if (function_comment != NULL) {
+ function_comment->source_line = 0;
+ (void) list_prepend(def, function_comment);
+ function_comment = NULL;
+ }
+
/* add an implicit return at end;
* also used by 'return' command in debugger
*/
@@ -4310,7 +4780,7 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
return fi;
}
-/*
+/*
* install_function:
* install function name in the symbol table.
* Extra work, build up and install a list of the parameter names.
@@ -4334,7 +4804,7 @@ install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
fi->func_body = f;
f->param_cnt = pcount;
f->code_ptr = fi;
- f->fparms = NULL;
+ f->fparms = NULL;
if (pcount > 0) {
char **pnames;
pnames = check_params(fname, pcount, plist); /* frees plist */
@@ -4391,7 +4861,7 @@ check_params(char *fname, int pcount, INSTRUCTION *list)
}
bcfree(list);
- return pnames;
+ return pnames;
}
@@ -4399,7 +4869,7 @@ check_params(char *fname, int pcount, INSTRUCTION *list)
undef HASHSIZE
#endif
#define HASHSIZE 1021
-
+
static struct fdesc {
char *name;
short used;
@@ -4426,8 +4896,7 @@ func_use(const char *name, enum defref how)
/* not in the table, fall through to allocate a new one */
- emalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
- memset(fp, '\0', sizeof(struct fdesc));
+ ezalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
emalloc(fp->name, char *, len + 1, "func_use");
strcpy(fp->name, name);
fp->next = ftable[ind];
@@ -4461,7 +4930,7 @@ check_funcs()
if (! in_main_context())
goto free_mem;
-
+
for (i = 0; i < HASHSIZE; i++) {
for (fp = ftable[i]; fp != NULL; fp = fp->next) {
#ifdef REALLYMEAN
@@ -4542,14 +5011,21 @@ make_regnode(int type, NODE *exp)
{
NODE *n;
+ assert(type == Node_regex || type == Node_dynregex);
getnode(n);
memset(n, 0, sizeof(NODE));
n->type = type;
n->re_cnt = 1;
if (type == Node_regex) {
- n->re_reg = make_regexp(exp->stptr, exp->stlen, false, true, false);
- if (n->re_reg == NULL) {
+ n->re_reg[0] = make_regexp(exp->stptr, exp->stlen, false, true, false);
+ if (n->re_reg[0] == NULL) {
+ freenode(n);
+ return NULL;
+ }
+ n->re_reg[1] = make_regexp(exp->stptr, exp->stlen, true, true, false);
+ if (n->re_reg[1] == NULL) {
+ refree(n->re_reg[0]);
freenode(n);
return NULL;
}
@@ -4570,6 +5046,8 @@ mk_rexp(INSTRUCTION *list)
ip = list->nexti;
if (ip == list->lasti && ip->opcode == Op_match_rec)
ip->opcode = Op_push_re;
+ else if (ip == list->lasti && ip->opcode == Op_push_re)
+ ; /* do nothing --- @/.../ */
else {
ip = instruction(Op_push_re);
ip->memory = make_regnode(Node_dynregex, NULL);
@@ -4764,6 +5242,8 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
}
op->opcode = Op_push_i;
+ // We don't need to call set_profile_text() here since
+ // optimizing is disabled when doing pretty printing.
op->memory = make_number(res);
unref(n1);
unref(n2);
@@ -4796,7 +5276,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
break;
default:
goto regular;
- }
+ }
op->memory = ip2->memory;
bcfree(ip2);
@@ -4812,7 +5292,7 @@ regular:
}
/* mk_boolean --- instructions for boolean and, or */
-
+
static INSTRUCTION *
mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
{
@@ -4840,7 +5320,7 @@ mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
right->lasti->target_stmt = left->lasti;
} else { /* optimization for x || y || z || ... */
INSTRUCTION *ip;
-
+
op->opcode = final_opc;
(void) list_append(right, op);
op->target_stmt = tp;
@@ -4877,7 +5357,7 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
*
* ----------------
* [Op_jmp y]
- * ----------------
+ * ----------------
* f:
* false_branch
* ----------------
@@ -4985,7 +5465,11 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
(rp + 1)->lasti = action->lasti;
(rp + 2)->first_line = pattern->source_line;
(rp + 2)->last_line = lastline;
- ip = list_prepend(action, rp);
+ if (block_comment != NULL) {
+ ip = list_prepend(list_prepend(action, block_comment), rp);
+ block_comment = NULL;
+ } else
+ ip = list_prepend(action, rp);
} else {
rp = bcalloc(Op_rule, 3, 0);
@@ -5027,7 +5511,6 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
action),
tp);
}
-
}
list_append(rule_list, rp + 1);
@@ -5036,7 +5519,7 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
rule_block[rule] = ip;
else
(void) list_merge(rule_block[rule], ip);
-
+
return rule_block[rule];
}
@@ -5058,7 +5541,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op)
break;
case Op_push:
case Op_push_array:
- tp->opcode = Op_push_lhs;
+ tp->opcode = Op_push_lhs;
break;
case Op_field_assign:
yyerror(_("cannot assign a value to the result of a field post-increment expression"));
@@ -5113,7 +5596,7 @@ optimize_assignment(INSTRUCTION *exp)
* Replaces Op_push_array + Op_subscript_lhs + Op_assign + Op_pop
* with single instruction Op_store_sub.
* Limitation: 1 dimension and sub is simple var/value.
- *
+ *
* 2) Simple variable assignment var = x:
* Replaces Op_push_lhs + Op_assign + Op_pop with Op_store_var.
*
@@ -5137,7 +5620,7 @@ optimize_assignment(INSTRUCTION *exp)
i1 = exp->lasti;
if ( i1->opcode != Op_assign
- && i1->opcode != Op_field_assign)
+ && i1->opcode != Op_field_assign)
return list_append(exp, instruction(Op_pop));
for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {
@@ -5212,7 +5695,7 @@ optimize_assignment(INSTRUCTION *exp)
* so use expr_count instead.
*/
i3->nexti = NULL;
- i2->opcode = Op_no_op;
+ i2->opcode = Op_no_op;
bcfree(i1); /* Op_assign */
exp->lasti = i3; /* update Op_list */
return exp;
@@ -5235,7 +5718,7 @@ optimize_assignment(INSTRUCTION *exp)
&& (i3->memory->flags & INTLSTR) == 0
&& i3->nexti == i2
) {
- /* constant initializer */
+ /* constant initializer */
i2->initval = i3->memory;
bcfree(i3);
exp->nexti = i2;
@@ -5271,7 +5754,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
* [ file (simp_exp)]
* [ [ var ] ]
* [ Op_K_getline_redir|NULL|redir_type|into_var]
- * [ [var_assign] ]
+ * [ [var_assign] ]
*
*/
@@ -5280,7 +5763,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
bcfree(op);
op = bcalloc(Op_K_getline, 2, sline);
(op + 1)->target_endfile = ip_endfile;
- (op + 1)->target_beginfile = ip_beginfile;
+ (op + 1)->target_beginfile = ip_beginfile;
}
if (var != NULL) {
@@ -5338,11 +5821,11 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
* ------------------------
* body (may be NULL)
* ------------------------
- * tc:
+ * tc:
* incr (may be NULL)
- * [ Op_jmp x ]
+ * [ Op_jmp x ]
* ------------------------
- * tb:[ Op_no_op ]
+ * tb:[ Op_no_op ]
*/
INSTRUCTION *ip, *tbreak, *tcont;
@@ -5423,12 +5906,22 @@ add_lint(INSTRUCTION *list, LINTTYPE linttype)
case LINT_no_effect:
if (list->lasti->opcode == Op_pop && list->nexti != list->lasti) {
- for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti)
- ;
+ int line = 0;
+
+ // Get down to the last instruction (FIXME: why?)
+ for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) {
+ // along the way track line numbers, we will use the line
+ // closest to the opcode if that opcode doesn't have one
+ if (ip->source_line != 0)
+ line = ip->source_line;
+ }
if (do_lint) { /* compile-time warning */
- if (isnoeffect(ip->opcode))
- lintwarn_ln(ip->source_line, ("statement may have no effect"));
+ if (isnoeffect(ip->opcode)) {
+ if (ip->source_line != 0)
+ line = ip->source_line;
+ lintwarn_ln(line, ("statement may have no effect"));
+ }
}
if (ip->opcode == Op_push) { /* run-time warning */
@@ -5454,7 +5947,7 @@ mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1)
/* we can't just combine all bytecodes, since we need to
* process individual expressions for a few builtins in snode() (-:
*/
-
+
/* -- list of lists */
/* [Op_list| ... ]------
* |
@@ -5510,7 +6003,7 @@ count_expressions(INSTRUCTION **list, bool isarg)
(void) list_merge(r, expr);
expr = t2->nexti;
}
-
+
assert(count > 0);
if (! isarg && count > max_args)
max_args = count;
@@ -5597,6 +6090,26 @@ list_merge(INSTRUCTION *l1, INSTRUCTION *l2)
return l1;
}
+/* add_pending_comment --- add a pending comment to a statement */
+
+static inline INSTRUCTION *
+add_pending_comment(INSTRUCTION *stmt)
+{
+ INSTRUCTION *ret = stmt;
+
+ if (prior_comment != NULL) {
+ if (function_comment != prior_comment)
+ ret = list_append(stmt, prior_comment);
+ prior_comment = NULL;
+ } else if (comment != NULL && comment->memory->comment_type == EOL_COMMENT) {
+ if (function_comment != comment)
+ ret = list_append(stmt, comment);
+ comment = NULL;
+ }
+
+ return ret;
+}
+
/* See if name is a special token. */
int
@@ -5756,7 +6269,7 @@ install_builtins(void)
* The scene of the murder was grisly to look upon. When the inspector
* arrived, the sergeant turned to him and said, "Another programmer stabbed
* in the back. He never knew what happened."
- *
+ *
* The inspector replied, "Looks like the MO of isalpha, and his even meaner
* big brother, isalnum. The Locale brothers." The sergeant merely
* shuddered in horror.
@@ -5802,3 +6315,26 @@ is_identchar(int c)
{
return (is_alnum(c) || c == '_');
}
+
+/* set_profile_text --- make a number that can be printed when profiling */
+
+static NODE *
+set_profile_text(NODE *n, const char *str, size_t len)
+{
+ if (do_pretty_print) {
+ // two extra bytes: one for NUL termination, and another in
+ // case we need to add a leading minus sign in add_sign_to_num
+ emalloc(n->stptr, char *, len + 2, "set_profile_text");
+ memcpy(n->stptr, str, len);
+ n->stptr[len] = '\0';
+ n->stlen = len;
+ // Set STRCUR and n->stfmt for use when profiling
+ // (i.e., actually running the program) so that
+ // force_string() on this item will work ok.
+ // Thanks and a tip of the hatlo to valgrind.
+ n->flags |= (NUMCONSTSTR|STRCUR);
+ n->stfmt = STFMT_UNUSED;
+ }
+
+ return n;
+}
diff --git a/awklib/Makefile.am b/awklib/Makefile.am
index 73f91f05..902c1937 100644
--- a/awklib/Makefile.am
+++ b/awklib/Makefile.am
@@ -39,7 +39,6 @@ AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
pkgdatadir = $(datadir)/awk
pkglibexecdir = $(libexecdir)/awk
-bin_SCRIPTS = igawk
pkglibexec_PROGRAMS = pwcat grcat
AUXAWK = passwd.awk group.awk
nodist_grcat_SOURCES = grcat.c
@@ -47,7 +46,7 @@ nodist_pwcat_SOURCES = pwcat.c
CLEANFILES = $(nodist_grcat_SOURCES) $(nodist_pwcat_SOURCES)
-all: $(srcdir)/stamp-eg $(AUXPROGS) igawk $(AUXAWK)
+all: $(srcdir)/stamp-eg $(AUXPROGS) $(AUXAWK)
install-exec-hook: $(AUXAWK)
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
@@ -59,10 +58,9 @@ install-exec-hook: $(AUXAWK)
# pkglibexecdir and pkgdatadir are removed in the top level Makefile's uninstall
uninstall-local:
rm -fr $(DESTDIR)$(pkglibexecdir)/* $(DESTDIR)$(pkgdatadir)/*
- rm -f $(DESTDIR)$(bindir)/igawk
clean-local:
- rm -f $(AUXAWK) igawk *.exe
+ rm -f $(AUXAWK) *.exe
rm -fr eg.old
rm -fr grcat.dSYM pwcat.dSYM
@@ -85,9 +83,6 @@ grcat.c: $(srcdir)/eg/lib/grcat.c
$(srcdir)/eg/lib/pwcat.c $(srcdir)/eg/lib/grcat.c $(srcdir)/eg/prog/igawk.sh \
$(srcdir)/eg/lib/passwdawk.in $(srcdir)/eg/lib/groupawk.in: stamp-eg; @:
-igawk: $(srcdir)/eg/prog/igawk.sh
- cp $(srcdir)/eg/prog/igawk.sh $@ ; chmod 755 $@
-
passwd.awk: $(srcdir)/eg/lib/passwdawk.in
sed 's;/usr/local/libexec/awk;$(pkglibexecdir);' < $(srcdir)/eg/lib/passwdawk.in > passwd.awk
diff --git a/awklib/Makefile.in b/awklib/Makefile.in
index b96dbe1b..16f8132c 100644
--- a/awklib/Makefile.in
+++ b/awklib/Makefile.in
@@ -37,7 +37,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
-
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
@@ -116,14 +115,14 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
- $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libsigsegv.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -131,7 +130,7 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-am__installdirs = "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(bindir)"
+am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
nodist_grcat_OBJECTS = grcat.$(OBJEXT)
grcat_OBJECTS = $(nodist_grcat_OBJECTS)
@@ -139,34 +138,6 @@ grcat_LDADD = $(LDADD)
nodist_pwcat_OBJECTS = pwcat.$(OBJEXT)
pwcat_OBJECTS = $(nodist_pwcat_OBJECTS)
pwcat_LDADD = $(LDADD)
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
- $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
- *) f=$$p;; \
- esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
- srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
- for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
- for p in $$list; do echo "$$p $$p"; done | \
- sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
- $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
- if (++n[$$2] == $(am__install_max)) \
- { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
- END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
- sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
- sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
- test -z "$$files" \
- || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
- || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
- $(am__cd) "$$dir" && rm -f $$files; }; \
- }
-SCRIPTS = $(bin_SCRIPTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -288,6 +259,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POSUB = @POSUB@
+RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -361,7 +333,6 @@ EXTRA_DIST = ChangeLog ChangeLog.0 extract.awk eg $(srcdir)/stamp-eg
# Get config.h from the build directory and custom.h from the source directory.
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
-bin_SCRIPTS = igawk
AUXAWK = passwd.awk group.awk
nodist_grcat_SOURCES = grcat.c
nodist_pwcat_SOURCES = pwcat.c
@@ -449,41 +420,6 @@ grcat$(EXEEXT): $(grcat_OBJECTS) $(grcat_DEPENDENCIES) $(EXTRA_grcat_DEPENDENCIE
pwcat$(EXEEXT): $(pwcat_OBJECTS) $(pwcat_DEPENDENCIES) $(EXTRA_pwcat_DEPENDENCIES)
@rm -f pwcat$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(pwcat_OBJECTS) $(pwcat_LDADD) $(LIBS)
-install-binSCRIPTS: $(bin_SCRIPTS)
- @$(NORMAL_INSTALL)
- @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
- fi; \
- for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
- done | \
- sed -e 'p;s,.*/,,;n' \
- -e 'h;s|.*|.|' \
- -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
- $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
- { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
- if ($$2 == $$4) { files[d] = files[d] " " $$1; \
- if (++n[d] == $(am__install_max)) { \
- print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
- else { print "f", d "/" $$4, $$1 } } \
- END { for (d in files) print "f", d, files[d] }' | \
- while read type dir files; do \
- if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
- test -z "$$files" || { \
- echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
- $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
- } \
- ; done
-
-uninstall-binSCRIPTS:
- @$(NORMAL_UNINSTALL)
- @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
- files=`for p in $$list; do echo "$$p"; done | \
- sed -e 's,.*/,,;$(transform)'`; \
- dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -592,9 +528,9 @@ distdir: $(DISTFILES)
done
check-am: all-am
check: check-am
-all-am: Makefile $(PROGRAMS) $(SCRIPTS)
+all-am: Makefile $(PROGRAMS)
installdirs:
- for dir in "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(bindir)"; do \
+ for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -657,7 +593,7 @@ install-dvi: install-dvi-am
install-dvi-am:
-install-exec-am: install-binSCRIPTS install-pkglibexecPROGRAMS
+install-exec-am: install-pkglibexecPROGRAMS
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-exec-hook
install-html: install-html-am
@@ -697,8 +633,7 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-binSCRIPTS uninstall-local \
- uninstall-pkglibexecPROGRAMS
+uninstall-am: uninstall-local uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-exec-am install-strip
@@ -706,22 +641,21 @@ uninstall-am: uninstall-binSCRIPTS uninstall-local \
clean-local clean-pkglibexecPROGRAMS cscopelist-am ctags \
ctags-am distclean distclean-compile distclean-generic \
distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-binSCRIPTS install-data \
- install-data-am install-dvi install-dvi-am install-exec \
- install-exec-am install-exec-hook install-html install-html-am \
- install-info install-info-am install-man install-pdf \
- install-pdf-am install-pkglibexecPROGRAMS install-ps \
- install-ps-am install-strip installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
- ps ps-am tags tags-am uninstall uninstall-am \
- uninstall-binSCRIPTS uninstall-local \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-exec-hook \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am \
+ install-pkglibexecPROGRAMS install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-local \
uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
-all: $(srcdir)/stamp-eg $(AUXPROGS) igawk $(AUXAWK)
+all: $(srcdir)/stamp-eg $(AUXPROGS) $(AUXAWK)
install-exec-hook: $(AUXAWK)
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
@@ -733,10 +667,9 @@ install-exec-hook: $(AUXAWK)
# pkglibexecdir and pkgdatadir are removed in the top level Makefile's uninstall
uninstall-local:
rm -fr $(DESTDIR)$(pkglibexecdir)/* $(DESTDIR)$(pkgdatadir)/*
- rm -f $(DESTDIR)$(bindir)/igawk
clean-local:
- rm -f $(AUXAWK) igawk *.exe
+ rm -f $(AUXAWK) *.exe
rm -fr eg.old
rm -fr grcat.dSYM pwcat.dSYM
@@ -759,9 +692,6 @@ grcat.c: $(srcdir)/eg/lib/grcat.c
$(srcdir)/eg/lib/pwcat.c $(srcdir)/eg/lib/grcat.c $(srcdir)/eg/prog/igawk.sh \
$(srcdir)/eg/lib/passwdawk.in $(srcdir)/eg/lib/groupawk.in: stamp-eg; @:
-igawk: $(srcdir)/eg/prog/igawk.sh
- cp $(srcdir)/eg/prog/igawk.sh $@ ; chmod 755 $@
-
passwd.awk: $(srcdir)/eg/lib/passwdawk.in
sed 's;/usr/local/libexec/awk;$(pkglibexecdir);' < $(srcdir)/eg/lib/passwdawk.in > passwd.awk
diff --git a/awklib/eg/lib/have_mpfr.awk b/awklib/eg/lib/have_mpfr.awk
new file mode 100644
index 00000000..90bd523b
--- /dev/null
+++ b/awklib/eg/lib/have_mpfr.awk
@@ -0,0 +1,9 @@
+# adequate_math_precision --- return true if we have enough bits
+#
+# Andrew Schorr, aschorr@telemetry-investments.com, Public Domain
+# May 2017
+
+function adequate_math_precision(n)
+{
+ return (1 != (1+(1/(2^(n-1)))))
+}
diff --git a/awklib/eg/lib/intdiv.awk b/awklib/eg/lib/intdiv.awk
new file mode 100644
index 00000000..dbc553b0
--- /dev/null
+++ b/awklib/eg/lib/intdiv.awk
@@ -0,0 +1,20 @@
+# intdiv --- do integer division
+
+#
+# Arnold Robbins, arnold@skeeve.com, Public Domain
+# July, 2014
+#
+# Name changed from div() to intdiv()
+# April, 2015
+
+function intdiv(numerator, denominator, result)
+{
+ split("", result)
+
+ numerator = int(numerator)
+ denominator = int(denominator)
+ result["quotient"] = int(numerator / denominator)
+ result["remainder"] = int(numerator % denominator)
+
+ return 0.0
+}
diff --git a/awklib/eg/prog/pi.awk b/awklib/eg/prog/pi.awk
new file mode 100644
index 00000000..e1b5bc4f
--- /dev/null
+++ b/awklib/eg/prog/pi.awk
@@ -0,0 +1,18 @@
+# pi.awk --- compute the digits of pi
+#
+# Katie Wasserman, katie@wass.net
+# August 2014
+
+BEGIN {
+ digits = 100000
+ two = 2 * 10 ^ digits
+ pi = two
+ for (m = digits * 4; m > 0; --m) {
+ d = m * 2 + 1
+ x = pi * m
+ intdiv(x, d, result)
+ pi = result["quotient"]
+ pi = pi + two
+ }
+ print pi
+}
diff --git a/builtin.c b/builtin.c
index 1eb2e3eb..b642e648 100644
--- a/builtin.c
+++ b/builtin.c
@@ -2,22 +2,22 @@
* builtin.c - Builtin functions and various utility procedures.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -129,14 +129,21 @@ wrerror:
if (errno == 0 || errno == EINVAL)
w32_maybe_set_errno();
#endif
- /* die silently on EPIPE to stdout */
+ /* for stdout, die with a real SIGPIPE, like other awks */
if (fp == stdout && errno == EPIPE)
- gawk_exit(EXIT_FATAL);
+ die_via_sigpipe();
/* otherwise die verbosely */
- fatal(_("%s to \"%s\" failed (%s)"), from,
- rp ? rp->value : _("standard output"),
- errno ? strerror(errno) : _("reason unknown"));
+ if ((rp != NULL) ? is_non_fatal_redirect(rp->value, strlen(rp->value)) : is_non_fatal_std(fp))
+ update_ERRNO_int(errno);
+ else
+ fatal(_("%s to \"%s\" failed (%s)"), from,
+ rp != NULL
+ ? rp->value
+ : fp == stdout
+ ? _("standard output")
+ : _("standard error"),
+ errno ? strerror(errno) : _("reason unknown"));
}
/* do_exp --- exponential function */
@@ -148,7 +155,7 @@ do_exp(int nargs)
double d, res;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("exp: received non-numeric argument"));
d = force_number(tmp)->numbr;
DEREF(tmp);
@@ -190,12 +197,13 @@ do_fflush(int nargs)
FILE *fp;
int status = 0;
const char *file;
+ int len;
/*
* November, 2012.
- * It turns out that circa 2002, when BWK
+ * It turns out that circa 2002, when BWK
* added fflush() and fflush("") to his awk, he made both of
- * them flush everything.
+ * them flush everything.
*
* Now, with our inside agent getting ready to try to get fflush()
* standardized in POSIX, we are going to make our awk consistent
@@ -210,16 +218,17 @@ do_fflush(int nargs)
/* fflush() */
if (nargs == 0) {
- status = flush_io();
+ status = flush_io(); // ERRNO updated
return make_number((AWKNUM) status);
}
tmp = POP_STRING();
file = tmp->stptr;
+ len = tmp->stlen;
/* fflush("") */
if (tmp->stlen == 0) {
- status = flush_io();
+ status = flush_io(); // ERRNO updated
DEREF(tmp);
return make_number((AWKNUM) status);
}
@@ -230,25 +239,32 @@ do_fflush(int nargs)
if (rp != NULL) {
if ((rp->flag & (RED_WRITE|RED_APPEND)) == 0) {
if ((rp->flag & RED_PIPE) != 0)
- warning(_("fflush: cannot flush: pipe `%s' opened for reading, not writing"),
- file);
+ warning(_("fflush: cannot flush: pipe `%.*s' opened for reading, not writing"),
+ len, file);
else
- warning(_("fflush: cannot flush: file `%s' opened for reading, not writing"),
- file);
+ warning(_("fflush: cannot flush: file `%.*s' opened for reading, not writing"),
+ len, file);
DEREF(tmp);
return make_number((AWKNUM) status);
}
fp = rp->output.fp;
- if (fp != NULL)
+ if (fp != NULL) {
status = rp->output.gawk_fflush(fp, rp->output.opaque);
- else if ((rp->flag & RED_TWOWAY) != 0)
- warning(_("fflush: cannot flush: two-way pipe `%s' has closed write end"),
- file);
+
+ if (status != 0) {
+ if (! is_non_fatal_redirect(tmp->stptr, tmp->stlen))
+ fatal(_("fflush: cannot flush file `%.*s': %s"),
+ len, file, strerror(errno));
+ update_ERRNO_int(errno);
+ }
+ } else if ((rp->flag & RED_TWOWAY) != 0)
+ warning(_("fflush: cannot flush: two-way pipe `%.*s' has closed write end"),
+ len, file);
} else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) {
- status = fflush(fp);
+ status = (non_fatal_flush_std_file(fp) == false);
} else {
status = -1;
- warning(_("fflush: `%s' is not an open file, pipe or co-process"), file);
+ warning(_("fflush: `%.*s' is not an open file, pipe or co-process"), len, file);
}
DEREF(tmp);
return make_number((AWKNUM) status);
@@ -354,9 +370,9 @@ do_index(int nargs)
POP_TWO_SCALARS(s1, s2);
if (do_lint) {
- if ((s1->flags & (STRING|STRCUR)) == 0)
+ if ((fixtype(s1)->flags & STRING) == 0)
lintwarn(_("index: received non-string first argument"));
- if ((s2->flags & (STRING|STRCUR)) == 0)
+ if ((fixtype(s2)->flags & STRING) == 0)
lintwarn(_("index: received non-string second argument"));
}
@@ -386,7 +402,7 @@ do_index(int nargs)
* If we don't have valid wide character strings, use
* the real bytes.
*/
- do_single_byte = ((s1->wstlen == 0 && s1->stlen > 0)
+ do_single_byte = ((s1->wstlen == 0 && s1->stlen > 0)
|| (s2->wstlen == 0 && s2->stlen > 0));
}
@@ -469,7 +485,7 @@ do_int(int nargs)
double d;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("int: received non-numeric argument"));
d = force_number(tmp)->numbr;
d = double_to_int(d);
@@ -484,6 +500,12 @@ do_isarray(int nargs)
{
NODE *tmp;
int ret = 1;
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ warned = true;
+ lintwarn(_("`isarray' is deprecated. Use `typeof' instead"));
+ }
tmp = POP();
if (tmp->type != Node_var_array) {
@@ -515,7 +537,7 @@ do_length(int nargs)
/*
* Support for deferred loading of array elements requires that
- * we use the array length interface even though it isn't
+ * we use the array length interface even though it isn't
* necessary for the built-in array types.
*
* 1/2015: The deferred arrays are gone, but this is probably
@@ -528,7 +550,7 @@ do_length(int nargs)
assert(tmp->type == Node_val);
- if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & STRING) == 0)
lintwarn(_("length: received non-string argument"));
tmp = force_string(tmp);
@@ -557,7 +579,7 @@ do_log(int nargs)
double d, arg;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("log: received non-numeric argument"));
arg = force_number(tmp)->numbr;
if (arg < 0.0)
@@ -716,7 +738,7 @@ format_tree(
emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
obufout = obuf;
osiz = INITIAL_OUT_SIZE;
- ofre = osiz - 2;
+ ofre = osiz - 1;
cur_arg = 1;
@@ -956,7 +978,7 @@ check_pos:
case ' ': /* print ' ' or '-' */
/* 'space' flag is ignored */
/* if '+' already present */
- if (signchar != false)
+ if (signchar != false)
goto check_pos;
/* FALL THROUGH */
case '+': /* print '+' or '-' */
@@ -982,18 +1004,18 @@ check_pos:
alt = true;
goto check_pos;
case '\'':
-#if defined(HAVE_LOCALE_H)
+#if defined(HAVE_LOCALE_H)
quote_flag = true;
goto check_pos;
#else
- goto retry;
+ goto retry;
#endif
case 'l':
if (big_flag)
break;
else {
static bool warned = false;
-
+
if (do_lint && ! warned) {
lintwarn(_("`l' is meaningless in awk formats; ignored"));
warned = true;
@@ -1010,7 +1032,7 @@ check_pos:
break;
else {
static bool warned = false;
-
+
if (do_lint && ! warned) {
lintwarn(_("`L' is meaningless in awk formats; ignored"));
warned = true;
@@ -1027,7 +1049,7 @@ check_pos:
break;
else {
static bool warned = false;
-
+
if (do_lint && ! warned) {
lintwarn(_("`h' is meaningless in awk formats; ignored"));
warned = true;
@@ -1043,8 +1065,7 @@ check_pos:
need_format = false;
parse_next_arg();
/* user input that looks numeric is numeric */
- if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
- (void) force_number(arg);
+ fixtype(arg);
if ((arg->flags & NUMBER) != 0) {
uval = get_number_uj(arg);
if (gawk_mb_cur_max > 1) {
@@ -1214,7 +1235,7 @@ out0:
jj = 0; /* keep using current val in loc.grouping[ii] */
else if (loc.grouping[ii+1] == CHAR_MAX)
quote_flag = false;
- else {
+ else {
ii++;
jj = 0;
}
@@ -1329,7 +1350,7 @@ mpf1:
zero_flag = (! lj
&& ((zero_flag && ! have_prec)
|| (fw == 0 && have_prec)));
-
+
(void) mpfr_get_z(mpzval, mf, MPFR_RNDZ); /* convert to GMP integer */
fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
zi = mpzval;
@@ -1394,11 +1415,11 @@ mpf1:
PREPEND(ts[k]);
}
}
- if (loc.grouping[ii+1] == 0)
+ if (loc.grouping[ii+1] == 0)
jj = 0; /* keep using current val in loc.grouping[ii] */
- else if (loc.grouping[ii+1] == CHAR_MAX)
+ else if (loc.grouping[ii+1] == CHAR_MAX)
quote_flag = false;
- else {
+ else {
ii++;
jj = 0;
}
@@ -1578,7 +1599,7 @@ mpf1:
bchunk(s0, s1 - s0);
olen_final = obufout - obuf;
if (ofre > 0)
- erealloc(obuf, char *, olen_final + 2, "format_tree");
+ erealloc(obuf, char *, olen_final + 1, "format_tree");
r = make_str_node(obuf, olen_final, ALREADY_MALLOCED);
obuf = NULL;
out:
@@ -1649,7 +1670,7 @@ do_printf(int nargs, int redirtype)
FILE *fp = NULL;
NODE *tmp;
struct redirect *rp = NULL;
- int errflg; /* not used, sigh */
+ int errflg = 0;
NODE *redir_exp = NULL;
if (nargs == 0) {
@@ -1660,7 +1681,7 @@ do_printf(int nargs, int redirtype)
redir_exp = TOP();
if (redir_exp->type != Node_val)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
DEREF(redir_exp);
decr_sp();
}
@@ -1673,14 +1694,22 @@ do_printf(int nargs, int redirtype)
redir_exp = PEEK(nargs);
if (redir_exp->type != Node_val)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
if (rp != NULL) {
if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) {
+ if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
+ update_ERRNO_int(EBADF);
+ return;
+ }
(void) close_rp(rp, CLOSE_ALL);
fatal(_("printf: attempt to write to closed write end of two-way pipe"));
}
fp = rp->output.fp;
}
+ else if (errflg) {
+ update_ERRNO_int(errflg);
+ return;
+ }
} else if (do_debug) /* only the debugger can change the default output */
fp = output_fp;
else
@@ -1713,7 +1742,7 @@ do_sqrt(int nargs)
double arg;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("sqrt: received non-numeric argument"));
arg = (double) force_number(tmp)->numbr;
DEREF(tmp);
@@ -1854,7 +1883,7 @@ do_substr(int nargs)
* way to do things.
*/
memset(& mbs, 0, sizeof(mbs));
- emalloc(substr, char *, (length * gawk_mb_cur_max) + 2, "do_substr");
+ emalloc(substr, char *, (length * gawk_mb_cur_max) + 1, "do_substr");
wp = t1->wstptr + indx;
for (cp = substr; length > 0; length--) {
result = wcrtomb(cp, *wp, & mbs);
@@ -1885,9 +1914,10 @@ do_strftime(int nargs)
char buf[BUFSIZ];
const char *format;
int formatlen;
- int do_gmt;
+ bool do_gmt;
NODE *val = NULL;
NODE *sub = NULL;
+ char save;
static const time_t time_t_min = TYPE_MINIMUM(time_t);
static const time_t time_t_max = TYPE_MAXIMUM(time_t);
@@ -1903,7 +1933,7 @@ do_strftime(int nargs)
unref(sub);
if (val != NULL) {
- if (do_lint && (val->flags & STRING) == 0)
+ if (do_lint && (fixtype(val)->flags & STRING) == 0)
lintwarn(_("strftime: format value in PROCINFO[\"strftime\"] has numeric type"));
val = force_string(val);
format = val->stptr;
@@ -1917,16 +1947,13 @@ do_strftime(int nargs)
if (nargs == 3) {
t3 = POP_SCALAR();
- if ((t3->flags & (NUMCUR|NUMBER)) != 0)
- do_gmt = (t3->numbr != 0);
- else
- do_gmt = (t3->stlen > 0);
+ do_gmt = boolval(t3);
DEREF(t3);
}
if (nargs >= 2) {
t2 = POP_SCALAR();
- if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(t2)->flags & NUMBER) == 0)
lintwarn(_("strftime: received non-numeric second argument"));
(void) force_number(t2);
clock_val = get_number_d(t2);
@@ -1952,9 +1979,9 @@ do_strftime(int nargs)
}
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & STRING) == 0)
lintwarn(_("strftime: received non-string first argument"));
-
+
t1 = force_string(tmp);
format = t1->stptr;
formatlen = t1->stlen;
@@ -1964,6 +1991,7 @@ do_strftime(int nargs)
DEREF(t1);
return make_string("", 0);
}
+ str_terminate(t1, save);
}
if (do_gmt)
@@ -1971,8 +1999,10 @@ do_strftime(int nargs)
else
tm = localtime(& fclock);
- if (tm == NULL)
- return make_string("", 0);
+ if (tm == NULL) {
+ ret = make_string("", 0);
+ goto done;
+ }
bufp = buf;
bufsize = sizeof(buf);
@@ -1998,8 +2028,11 @@ do_strftime(int nargs)
ret = make_string(bufp, buflen);
if (bufp != buf)
efree(bufp);
- if (t1)
+done:
+ if (t1) {
+ str_restore(t1, save);
DEREF(t1);
+ }
return ret;
}
@@ -2014,21 +2047,57 @@ do_systime(int nargs ATTRIBUTE_UNUSED)
return make_number((AWKNUM) lclock);
}
+/* mktime_tz --- based on Linux timegm man page */
+
+static time_t
+mktime_tz(struct tm *tm, const char *tzreq)
+{
+ time_t ret;
+ char *tz = getenv("TZ");
+
+ if (tz)
+ tz = estrdup(tz, strlen(tz));
+ if (setenv("TZ", tzreq, 1) < 0) {
+ warning(_("setenv(TZ, %s) failed (%s)"), tzreq, strerror(errno));
+ return -1;
+ }
+ tzset();
+ ret = mktime(tm);
+ if (tz) {
+ if (setenv("TZ", tz, 1) < 0)
+ fatal(_("setenv(TZ, %s) restoration failed (%s)"), tz, strerror(errno));
+ free(tz);
+ } else {
+ if (unsetenv("TZ") < 0)
+ fatal(_("unsetenv(TZ) failed (%s)"), strerror(errno));
+ }
+ tzset();
+ return ret;
+}
+
/* do_mktime --- turn a time string into a timestamp */
NODE *
do_mktime(int nargs)
{
- NODE *t1;
+ NODE *t1, *t2;
struct tm then;
long year;
int month, day, hour, minute, second, count;
int dst = -1; /* default is unknown */
time_t then_stamp;
char save;
+ bool do_gmt;
+ if (nargs == 2) {
+ t2 = POP_SCALAR();
+ do_gmt = boolval(t2);
+ DEREF(t2);
+ }
+ else
+ do_gmt = false;
t1 = POP_SCALAR();
- if (do_lint && (t1->flags & (STRING|STRCUR)) == 0)
+ if (do_lint && (fixtype(t1)->flags & STRING) == 0)
lintwarn(_("mktime: received non-string argument"));
t1 = force_string(t1);
@@ -2066,7 +2135,7 @@ do_mktime(int nargs)
then.tm_year = year - 1900;
then.tm_isdst = dst;
- then_stamp = mktime(& then);
+ then_stamp = (do_gmt ? mktime_tz(& then, "UTC+0") : mktime(& then));
return make_number((AWKNUM) then_stamp);
}
@@ -2086,7 +2155,7 @@ do_system(int nargs)
(void) flush_io(); /* so output is synchronous with gawk's */
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & STRING) == 0)
lintwarn(_("system: received non-string argument"));
cmd = force_string(tmp)->stptr;
@@ -2096,9 +2165,7 @@ do_system(int nargs)
cmd[tmp->stlen] = '\0';
os_restore_mode(fileno(stdin));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_DFL);
-#endif
+ set_sigpipe_to_default();
status = system(cmd);
/*
@@ -2114,29 +2181,17 @@ do_system(int nargs)
; /* leave it alone, full 16 bits */
else if (do_traditional)
#ifdef __MINGW32__
- ret = (((unsigned)status) & ~0xC0000000);
+ ret = (((unsigned)status) & ~0xC0000000);
#else
ret = (status / 256.0);
#endif
- else if (WIFEXITED(status))
- ret = WEXITSTATUS(status); /* normal exit */
- else if (WIFSIGNALED(status)) {
- bool coredumped = false;
-#ifdef WCOREDUMP
- coredumped = WCOREDUMP(status);
-#endif
- /* use 256 since exit values are 8 bits */
- ret = WTERMSIG(status) +
- (coredumped ? 512 : 256);
- } else
- ret = 0; /* shouldn't get here */
+ else
+ ret = sanitize_exit_status(status);
}
if ((BINMODE & BINMODE_INPUT) != 0)
os_setbinmode(fileno(stdin), O_BINARY);
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
cmd[tmp->stlen] = save;
}
@@ -2150,7 +2205,7 @@ void
do_print(int nargs, int redirtype)
{
struct redirect *rp = NULL;
- int errflg; /* not used, sigh */
+ int errflg = 0;
FILE *fp = NULL;
int i;
NODE *redir_exp = NULL;
@@ -2162,14 +2217,22 @@ do_print(int nargs, int redirtype)
redir_exp = PEEK(nargs);
if (redir_exp->type != Node_val)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
if (rp != NULL) {
if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) {
+ if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
+ update_ERRNO_int(EBADF);
+ return;
+ }
(void) close_rp(rp, CLOSE_ALL);
fatal(_("print: attempt to write to closed write end of two-way pipe"));
}
fp = rp->output.fp;
}
+ else if (errflg) {
+ update_ERRNO_int(errflg);
+ return;
+ }
} else if (do_debug) /* only the debugger can change the default output */
fp = output_fp;
else
@@ -2182,9 +2245,10 @@ do_print(int nargs, int redirtype)
DEREF(args_array[i]);
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp));
}
-
- if ((tmp->flags & STRCUR) == 0 || (tmp->stfmt != -1 && tmp->stfmt != OFMTidx))
- args_array[i] = format_val(OFMT, OFMTidx, tmp);
+ if ( (tmp->flags & STRCUR) == 0
+ || ( tmp->stfmt != STFMT_UNUSED
+ && tmp->stfmt != OFMTidx))
+ args_array[i] = force_string_ofmt(tmp);
}
if (redir_exp != NULL) {
@@ -2215,21 +2279,25 @@ do_print(int nargs, int redirtype)
/* do_print_rec --- special case printing of $0, for speed */
-void
+void
do_print_rec(int nargs, int redirtype)
{
FILE *fp = NULL;
NODE *f0;
struct redirect *rp = NULL;
- int errflg; /* not used, sigh */
+ int errflg = 0;
NODE *redir_exp = NULL;
assert(nargs == 0);
if (redirtype != 0) {
redir_exp = TOP();
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
if (rp != NULL) {
if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) {
+ if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
+ update_ERRNO_int(EBADF);
+ return;
+ }
(void) close_rp(rp, CLOSE_ALL);
fatal(_("print: attempt to write to closed write end of two-way pipe"));
}
@@ -2240,6 +2308,11 @@ do_print_rec(int nargs, int redirtype)
} else
fp = output_fp;
+ if (errflg) {
+ update_ERRNO_int(errflg);
+ return;
+ }
+
if (fp == NULL)
return;
@@ -2333,7 +2406,7 @@ do_tolower(int nargs)
NODE *t1, *t2;
t1 = POP_SCALAR();
- if (do_lint && (t1->flags & (STRING|STRCUR)) == 0)
+ if (do_lint && (fixtype(t1)->flags & STRING) == 0)
lintwarn(_("tolower: received non-string argument"));
t1 = force_string(t1);
t2 = make_string(t1->stptr, t1->stlen);
@@ -2364,7 +2437,7 @@ do_toupper(int nargs)
NODE *t1, *t2;
t1 = POP_SCALAR();
- if (do_lint && (t1->flags & (STRING|STRCUR)) == 0)
+ if (do_lint && (fixtype(t1)->flags & STRING) == 0)
lintwarn(_("toupper: received non-string argument"));
t1 = force_string(t1);
t2 = make_string(t1->stptr, t1->stlen);
@@ -2397,9 +2470,9 @@ do_atan2(int nargs)
POP_TWO_SCALARS(t1, t2);
if (do_lint) {
- if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(t1)->flags & NUMBER) == 0)
lintwarn(_("atan2: received non-numeric first argument"));
- if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(t2)->flags & NUMBER) == 0)
lintwarn(_("atan2: received non-numeric second argument"));
}
d1 = force_number(t1)->numbr;
@@ -2418,7 +2491,7 @@ do_sin(int nargs)
double d;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("sin: received non-numeric argument"));
d = sin((double) force_number(tmp)->numbr);
DEREF(tmp);
@@ -2434,7 +2507,7 @@ do_cos(int nargs)
double d;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("cos: received non-numeric argument"));
d = cos((double) force_number(tmp)->numbr);
DEREF(tmp);
@@ -2453,6 +2526,8 @@ static char *const state = (char *const) istate;
NODE *
do_rand(int nargs ATTRIBUTE_UNUSED)
{
+ double tmprand;
+#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0)
if (firstrand) {
(void) initstate((unsigned) 1, state, SIZEOF_STATE);
/* don't need to srandom(1), initstate() does it for us. */
@@ -2464,7 +2539,66 @@ do_rand(int nargs ATTRIBUTE_UNUSED)
*
* 0 <= n < 1
*/
- return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+ /*
+ * Date: Wed, 28 Aug 2013 17:52:46 -0700
+ * From: Bob Jewett <jewett@bill.scs.agilent.com>
+ *
+ * Call random() twice to fill in more bits in the value
+ * of the double. Also, there is a bug in random() such
+ * that when the values of successive values are combined
+ * like (rand1*rand2)^2, (rand3*rand4)^2, ... the
+ * resulting time series is not white noise. The
+ * following also seems to fix that bug.
+ *
+ * The add/subtract 0.5 keeps small bits from filling
+ * below 2^-53 in the double, not that anyone should be
+ * looking down there.
+ *
+ * Date: Wed, 25 Sep 2013 10:45:38 -0600 (MDT)
+ * From: "Nelson H. F. Beebe" <beebe@math.utah.edu>
+ * (4) The code is typical of many published fragments for converting
+ * from integer to floating-point, and I discuss the serious pitfalls
+ * in my book, because it leads to platform-dependent behavior at the
+ * end points of the interval [0,1]
+ *
+ * (5) the documentation in the gawk info node says
+ *
+ * `rand()'
+ * Return a random number. The values of `rand()' are uniformly
+ * distributed between zero and one. The value could be zero but is
+ * never one.(1)
+ *
+ * The division by RAND_DIVISOR may not guarantee that 1.0 is never
+ * returned: the programmer forgot the platform-dependent issue of
+ * rounding.
+ *
+ * For points 4 and 5, the safe way is a loop:
+ *
+ * double
+ * rand(void) // return value in [0.0, 1.0)
+ * {
+ * value = internal_rand();
+ *
+ * while (value == 1.0)
+ * value = internal_rand();
+ *
+ * return (value);
+ * }
+ */
+
+ do {
+ long d1, d2;
+ /*
+ * Do the calls in predictable order to avoid
+ * compiler differences in order of evaluation.
+ */
+ d1 = random();
+ d2 = random();
+ tmprand = 0.5 + ( (d1/RAND_DIVISOR + d2) / RAND_DIVISOR );
+ tmprand -= 0.5;
+ } while (tmprand == 1.0);
+
+ return make_number((AWKNUM) tmprand);
}
/* do_srand --- seed the random number generator */
@@ -2487,7 +2621,7 @@ do_srand(int nargs)
srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
else {
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("srand: received non-numeric argument"));
srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr));
DEREF(tmp);
@@ -2525,7 +2659,7 @@ do_match(int nargs)
tre = POP();
rp = re_update(tre);
t1 = POP_STRING();
-
+
rstart = research(rp, t1->stptr, 0, t1->stlen, RE_NEED_START);
if (rstart >= 0) { /* match succeded */
size_t *wc_indices = NULL;
@@ -2538,7 +2672,7 @@ do_match(int nargs)
}
rstart++; /* now it's 1-based indexing */
-
+
/* Build the array only if the caller wants the optional subpatterns */
if (dest != NULL) {
subsepstr = SUBSEP_node->var_value->stptr;
@@ -2554,7 +2688,7 @@ do_match(int nargs)
size_t subpat_len;
NODE **lhs;
NODE *sub;
-
+
start = t1->stptr + s;
subpat_start = s;
subpat_len = len = SUBPATEND(rp, t1->stptr, ii) - s;
@@ -2562,9 +2696,9 @@ do_match(int nargs)
subpat_start = wc_indices[s];
subpat_len = wc_indices[s + len - 1] - subpat_start + 1;
}
-
+
it = make_string(start, len);
- it->flags |= MAYBE_NUM; /* user input */
+ it->flags |= USER_INPUT;
sub = make_number((AWKNUM) (ii));
lhs = assoc_lookup(dest, sub);
@@ -2577,8 +2711,8 @@ do_match(int nargs)
sprintf(buff, "%d", ii);
ilen = strlen(buff);
- amt = ilen + subseplen + strlen("length") + 2;
-
+ amt = ilen + subseplen + strlen("length") + 1;
+
if (oldamt == 0) {
emalloc(buf, char *, amt, "do_match");
} else if (amt > oldamt) {
@@ -2588,9 +2722,9 @@ do_match(int nargs)
memcpy(buf, buff, ilen);
memcpy(buf + ilen, subsepstr, subseplen);
memcpy(buf + ilen + subseplen, "start", 6);
-
+
slen = ilen + subseplen + 5;
-
+
it = make_number((AWKNUM) subpat_start + 1);
sub = make_string(buf, slen);
lhs = assoc_lookup(dest, sub);
@@ -2599,13 +2733,13 @@ do_match(int nargs)
if (dest->astore != NULL)
(*dest->astore)(dest, sub);
unref(sub);
-
+
memcpy(buf, buff, ilen);
memcpy(buf + ilen, subsepstr, subseplen);
memcpy(buf + ilen + subseplen, "length", 7);
-
+
slen = ilen + subseplen + 6;
-
+
it = make_number((AWKNUM) subpat_len);
sub = make_string(buf, slen);
lhs = assoc_lookup(dest, sub);
@@ -2640,9 +2774,9 @@ do_match(int nargs)
* Gsub can be tricksy; particularly when handling the case of null strings.
* The following awk code was useful in debugging problems. It is too bad
* that it does not readily translate directly into the C code, below.
- *
+ *
* #! /usr/local/bin/mawk -f
- *
+ *
* BEGIN {
* true = 1; false = 0
* print "--->", mygsub("abc", "b+", "FOO")
@@ -2652,7 +2786,7 @@ do_match(int nargs)
* print "--->", mygsub("abc", "c+", "X")
* print "--->", mygsub("abc", "x*$", "X")
* }
- *
+ *
* function mygsub(str, regex, replace, origstr, newstr, eosflag, nonzeroflag)
* {
* origstr = str;
@@ -2690,7 +2824,7 @@ do_match(int nargs)
* }
* if (length(str) > 0)
* newstr = newstr str # rest of string
- *
+ *
* return newstr
* }
*/
@@ -2702,7 +2836,7 @@ do_match(int nargs)
*
* The relevant text is to be found on lines 6394-6407 (pages 166, 167) of the
* 2001 standard:
- *
+ *
* sub(ere, repl[, in ])
* Substitute the string repl in place of the first instance of the
* extended regular expression ERE in string in and return the number of
@@ -2751,56 +2885,48 @@ do_sub(int nargs, unsigned int flags)
int ampersands;
int matches = 0;
Regexp *rp;
- NODE *s; /* subst. pattern */
- NODE *t; /* string to make sub. in; $0 if none given */
+ NODE *rep_node; /* replacement text */
+ NODE *target; /* string to make sub. in; $0 if none given */
NODE *tmp;
NODE **lhs = NULL;
long how_many = 1; /* one substitution for sub, also gensub default */
- int global;
+ bool global;
long current;
bool lastmatchnonzero;
char *mb_indices = NULL;
-
+
if ((flags & GENSUB) != 0) {
double d;
- NODE *t1;
+ NODE *glob_flag;
tmp = PEEK(3);
rp = re_update(tmp);
- t = POP_STRING(); /* original string */
-
- t1 = POP_SCALAR(); /* value of global flag */
- if ((t1->flags & (STRCUR|STRING)) != 0) {
- if (t1->stlen > 0 && (t1->stptr[0] == 'g' || t1->stptr[0] == 'G'))
- how_many = -1;
- else {
- (void) force_number(t1);
- d = get_number_d(t1);
- if ((t1->flags & NUMCUR) != 0)
- goto set_how_many;
+ target = POP_STRING(); /* original string */
- warning(_("gensub: third argument `%.*s' treated as 1"),
- (int) t1->stlen, t1->stptr);
- how_many = 1;
- }
- } else {
- (void) force_number(t1);
- d = get_number_d(t1);
-set_how_many:
+ glob_flag = POP_SCALAR(); /* value of global flag */
+ if ( (glob_flag->flags & STRING) != 0
+ && glob_flag->stlen > 0
+ && (glob_flag->stptr[0] == 'g' || glob_flag->stptr[0] == 'G'))
+ how_many = -1;
+ else {
+ (void) force_number(glob_flag);
+ d = get_number_d(glob_flag);
if (d < 1)
how_many = 1;
else if (d < LONG_MAX)
how_many = d;
else
how_many = LONG_MAX;
- if (d <= 0)
- warning(_("gensub: third argument %g treated as 1"), d);
+ if (d <= 0) {
+ (void) force_string(glob_flag);
+ warning(_("gensub: third argument `%.*s' treated as 1"),
+ (int) glob_flag->stlen,
+ glob_flag->stptr);
+ }
}
- DEREF(t1);
-
+ DEREF(glob_flag);
} else {
-
/* take care of regexp early, in case re_update is fatal */
tmp = PEEK(2);
@@ -2812,30 +2938,30 @@ set_how_many:
/* original string */
if ((flags & LITERAL) != 0)
- t = POP_STRING();
+ target = POP_STRING();
else {
lhs = POP_ADDRESS();
- t = force_string(*lhs);
+ target = force_string(*lhs);
}
}
global = (how_many == -1);
- s = POP_STRING(); /* replacement text */
+ rep_node = POP_STRING(); /* replacement text */
decr_sp(); /* regexp, already updated above */
/* do the search early to avoid work on non-match */
- if (research(rp, t->stptr, 0, t->stlen, RE_NEED_START) == -1 ||
- RESTART(rp, t->stptr) > t->stlen)
+ if (research(rp, target->stptr, 0, target->stlen, RE_NEED_START) == -1 ||
+ RESTART(rp, target->stptr) > target->stlen)
goto done;
- t->flags |= STRING;
+ target->flags |= STRING;
- text = t->stptr;
- textlen = t->stlen;
+ text = target->stptr;
+ textlen = target->stlen;
- repl = s->stptr;
- replend = repl + s->stlen;
+ repl = rep_node->stptr;
+ replend = repl + rep_node->stlen;
repllen = replend - repl;
ampersands = 0;
@@ -2853,6 +2979,7 @@ set_how_many:
index_multibyte_buffer(repl, mb_indices, repllen);
}
+ /* compute length of replacement string, number of ampersands */
for (scan = repl; scan < replend; scan++) {
if ((gawk_mb_cur_max == 1 || (repllen > 0 && mb_indices[scan - repl] == 1))
&& (*scan == '&')) {
@@ -2899,24 +3026,32 @@ 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");
+ /* guesstimate how much room to allocate; +1 forces > 0 */
+ buflen = textlen + (ampersands + 1) * repllen + 1;
+ emalloc(buf, char *, buflen + 1, "do_sub");
buf[buflen] = '\0';
- buf[buflen + 1] = '\0';
bp = buf;
for (current = 1;; current++) {
matches++;
- matchstart = t->stptr + RESTART(rp, t->stptr);
- matchend = t->stptr + REEND(rp, t->stptr);
+ matchstart = target->stptr + RESTART(rp, target->stptr);
+ matchend = target->stptr + REEND(rp, target->stptr);
/*
* create the result, copying in parts of the original
- * string
+ * string. note that length of replacement string can
+ * vary since ampersand is actual text of regexp match.
+ */
+
+ /*
+ * add 1 to len to handle "empty" case where
+ * matchend == matchstart and we force a match on a single
+ * char. Use 'matchend - text' instead of 'matchstart - text'
+ * because we may not actually make any substitution depending
+ * on the 'global' and 'how_many' values.
*/
- len = matchstart - text + repllen
- + ampersands * (matchend - matchstart);
+ len = matchend - text + repllen
+ + ampersands * (matchend - matchstart) + 1;
sofar = bp - buf;
while (buflen < (sofar + len + 1)) {
buflen *= 2;
@@ -2963,13 +3098,13 @@ set_how_many:
if (flags & GENSUB) { /* gensub, behave sanely */
if (isdigit((unsigned char) scan[1])) {
int dig = scan[1] - '0';
- if (dig < NUMSUBPATS(rp, t->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) {
+ if (dig < NUMSUBPATS(rp, target->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) {
char *start, *end;
-
- start = t->stptr
- + SUBPATSTART(rp, t->stptr, dig);
- end = t->stptr
- + SUBPATEND(rp, t->stptr, dig);
+
+ start = target->stptr
+ + SUBPATSTART(rp, target->stptr, dig);
+ end = target->stptr
+ + SUBPATEND(rp, target->stptr, dig);
for (cp = start; cp < end; cp++)
*bp++ = *cp;
@@ -3025,19 +3160,29 @@ set_how_many:
textlen = text + textlen - matchend;
text = matchend;
+#if 0
+ if (bp - buf > sofar + len)
+ fprintf(stderr, "debug: len = %zu, but used %ld\n", len, (long)((bp - buf) - (long)sofar));
+#endif
+
if ((current >= how_many && ! global)
|| ((long) textlen <= 0 && matchstart == matchend)
- || research(rp, t->stptr, text - t->stptr, textlen, RE_NEED_START) == -1)
+ || research(rp, target->stptr, text - target->stptr, textlen, RE_NEED_START) == -1)
break;
}
sofar = bp - buf;
- if (buflen - sofar - textlen - 1) {
- buflen = sofar + textlen + 2;
+ if (buflen < (sofar + textlen + 1)) {
+ buflen = sofar + textlen + 1;
erealloc(buf, char *, buflen, "do_sub");
bp = buf + sofar;
}
- for (scan = matchend; scan < text + textlen; scan++)
+ /*
+ * Note that text == matchend, since that assignment is made before
+ * exiting the 'for' loop above. Thus we copy in the rest of the
+ * original string.
+ */
+ for (scan = text; scan < text + textlen; scan++)
*bp++ = *scan;
*bp = '\0';
textlen = bp - buf;
@@ -3046,31 +3191,31 @@ set_how_many:
efree(mb_indices);
done:
- DEREF(s);
+ DEREF(rep_node);
if ((matches == 0 || (flags & LITERAL) != 0) && buf != NULL) {
- efree(buf);
+ efree(buf);
buf = NULL;
}
if (flags & GENSUB) {
if (matches > 0) {
/* return the result string */
- DEREF(t);
+ DEREF(target);
assert(buf != NULL);
- return make_str_node(buf, textlen, ALREADY_MALLOCED);
+ return make_str_node(buf, textlen, ALREADY_MALLOCED);
}
/* return the original string */
- return t;
+ return target;
}
/* For a string literal, must not change the original string. */
if ((flags & LITERAL) != 0)
- DEREF(t);
+ DEREF(target);
else if (matches > 0) {
unref(*lhs);
- *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);
+ *lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);
}
return make_number((AWKNUM) matches);
@@ -3106,7 +3251,10 @@ call_sub(const char *name, int nargs)
* push replace
* push $0
*/
- regex = make_regnode(Node_regex, regex);
+ if ((regex->flags & REGEX) != 0)
+ regex = regex->typed_re;
+ else
+ regex = make_regnode(Node_regex, regex);
PUSH(regex);
PUSH(replace);
lhs = r_get_field(zero, (Func_ptr *) 0, true);
@@ -3130,7 +3278,10 @@ call_sub(const char *name, int nargs)
* nargs++
* }
*/
- regex = make_regnode(Node_regex, regex);
+ if ((regex->flags & REGEX) != 0)
+ regex = regex->typed_re;
+ else
+ regex = make_regnode(Node_regex, regex);
PUSH(regex);
PUSH(replace);
PUSH(glob_flag);
@@ -3167,7 +3318,11 @@ call_match(int nargs)
/* Don't need to pop the string just to push it back ... */
- regex = make_regnode(Node_regex, regex);
+ if ((regex->flags & REGEX) != 0)
+ regex = regex->typed_re;
+ else
+ regex = make_regnode(Node_regex, regex);
+
PUSH(regex);
if (array)
@@ -3195,7 +3350,10 @@ call_split_func(const char *name, int nargs)
if (nargs >= 3) {
regex = POP_STRING();
- regex = make_regnode(Node_regex, regex);
+ if ((regex->flags & REGEX) != 0)
+ regex = regex->typed_re;
+ else
+ regex = make_regnode(Node_regex, regex);
} else {
if (name[0] == 's') {
regex = make_regnode(Node_regex, FS_node->var_value);
@@ -3238,16 +3396,18 @@ do_lshift(int nargs)
POP_TWO_SCALARS(s1, s2);
if (do_lint) {
- if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(s1)->flags & NUMBER) == 0)
lintwarn(_("lshift: received non-numeric first argument"));
- if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(s2)->flags & NUMBER) == 0)
lintwarn(_("lshift: received non-numeric second argument"));
}
+
val = force_number(s1)->numbr;
shift = force_number(s2)->numbr;
+ if (val < 0 || shift < 0)
+ fatal(_("lshift(%f, %f): negative values are not allowed"), val, shift);
+
if (do_lint) {
- if (val < 0 || shift < 0)
- lintwarn(_("lshift(%f, %f): negative values will give strange results"), val, shift);
if (double_to_int(val) != val || double_to_int(shift) != shift)
lintwarn(_("lshift(%f, %f): fractional values will be truncated"), val, shift);
if (shift >= sizeof(uintmax_t) * CHAR_BIT)
@@ -3275,16 +3435,18 @@ do_rshift(int nargs)
POP_TWO_SCALARS(s1, s2);
if (do_lint) {
- if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(s1)->flags & NUMBER) == 0)
lintwarn(_("rshift: received non-numeric first argument"));
- if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(s2)->flags & NUMBER) == 0)
lintwarn(_("rshift: received non-numeric second argument"));
}
+
val = force_number(s1)->numbr;
shift = force_number(s2)->numbr;
+ if (val < 0 || shift < 0)
+ fatal(_("rshift(%f, %f): negative values are not allowed"), val, shift);
+
if (do_lint) {
- if (val < 0 || shift < 0)
- lintwarn(_("rshift(%f, %f): negative values will give strange results"), val, shift);
if (double_to_int(val) != val || double_to_int(shift) != shift)
lintwarn(_("rshift(%f, %f): fractional values will be truncated"), val, shift);
if (shift >= sizeof(uintmax_t) * CHAR_BIT)
@@ -3317,12 +3479,12 @@ do_and(int nargs)
for (i = 1; nargs > 0; nargs--, i++) {
s1 = POP_SCALAR();
- if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(s1)->flags & NUMBER) == 0)
lintwarn(_("and: argument %d is non-numeric"), i);
val = force_number(s1)->numbr;
- if (do_lint && val < 0)
- lintwarn(_("and: argument %d negative value %g will give strange results"), i, val);
+ if (val < 0)
+ fatal(_("and: argument %d negative value %g is not allowed"), i, val);
uval = (uintmax_t) val;
res &= uval;
@@ -3349,12 +3511,12 @@ do_or(int nargs)
for (i = 1; nargs > 0; nargs--, i++) {
s1 = POP_SCALAR();
- if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(s1)->flags & NUMBER) == 0)
lintwarn(_("or: argument %d is non-numeric"), i);
val = force_number(s1)->numbr;
- if (do_lint && val < 0)
- lintwarn(_("or: argument %d negative value %g will give strange results"), i, val);
+ if (val < 0)
+ fatal(_("or: argument %d negative value %g is not allowed"), i, val);
uval = (uintmax_t) val;
res |= uval;
@@ -3381,12 +3543,12 @@ do_xor(int nargs)
res = 0; /* silence compiler warning */
for (i = 1; nargs > 0; nargs--, i++) {
s1 = POP_SCALAR();
- if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(s1)->flags & NUMBER) == 0)
lintwarn(_("xor: argument %d is non-numeric"), i);
val = force_number(s1)->numbr;
- if (do_lint && val < 0)
- lintwarn(_("xor: argument %d negative value %g will give strange results"), i, val);
+ if (val < 0)
+ fatal(_("xor: argument %d negative value %g is not allowed"), i, val);
uval = (uintmax_t) val;
if (i == 1)
@@ -3410,17 +3572,16 @@ do_compl(int nargs)
uintmax_t uval;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("compl: received non-numeric argument"));
d = force_number(tmp)->numbr;
DEREF(tmp);
- if (do_lint) {
- if (d < 0)
- lintwarn(_("compl(%f): negative value will give strange results"), d);
- if (double_to_int(d) != d)
- lintwarn(_("compl(%f): fractional value will be truncated"), d);
- }
+ if (d < 0)
+ fatal(_("compl(%f): negative value is not allowed"), d);
+
+ if (do_lint && double_to_int(d) != d)
+ lintwarn(_("compl(%f): fractional value will be truncated"), d);
uval = (uintmax_t) d;
uval = ~ uval;
@@ -3435,11 +3596,11 @@ do_strtonum(int nargs)
NODE *tmp;
AWKNUM d;
- tmp = POP_SCALAR();
- if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
- d = (AWKNUM) force_number(tmp)->numbr;
- else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
- d = nondec2awknum(tmp->stptr, tmp->stlen);
+ tmp = fixtype(POP_SCALAR());
+ if ((tmp->flags & NUMBER) != 0)
+ d = (AWKNUM) tmp->numbr;
+ else if (get_numbase(tmp->stptr, tmp->stlen, use_lc_numeric) != 10)
+ d = nondec2awknum(tmp->stptr, tmp->stlen, NULL);
else
d = (AWKNUM) force_number(tmp)->numbr;
@@ -3456,20 +3617,23 @@ do_strtonum(int nargs)
*/
AWKNUM
-nondec2awknum(char *str, size_t len)
+nondec2awknum(char *str, size_t len, char **endptr)
{
AWKNUM retval = 0.0;
char save;
short val;
char *start = str;
- if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ if (len >= 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
/*
* User called strtonum("0x") or some such,
* so just quit early.
*/
- if (len <= 2)
+ if (len <= 2) {
+ if (endptr)
+ *endptr = start;
return (AWKNUM) 0.0;
+ }
for (str += 2, len -= 2; len > 0; len--, str++) {
switch (*str) {
@@ -3502,14 +3666,21 @@ nondec2awknum(char *str, size_t len)
val = *str - 'A' + 10;
break;
default:
+ if (endptr)
+ *endptr = str;
goto done;
}
retval = (retval * 16) + val;
}
- } else if (*str == '0') {
+ if (endptr)
+ *endptr = str;
+ } else if (len >= 1 && *str == '0') {
for (; len > 0; len--) {
- if (! isdigit((unsigned char) *str))
+ if (! isdigit((unsigned char) *str)) {
+ if (endptr)
+ *endptr = str;
goto done;
+ }
else if (*str == '8' || *str == '9') {
str = start;
goto decimal;
@@ -3517,11 +3688,13 @@ nondec2awknum(char *str, size_t len)
retval = (retval * 8) + (*str - '0');
str++;
}
+ if (endptr)
+ *endptr = str;
} else {
decimal:
save = str[len];
str[len] = '\0';
- retval = strtod(str, NULL);
+ retval = strtod(str, endptr);
str[len] = save;
}
done:
@@ -3570,6 +3743,8 @@ localecategory_from_argument(NODE *t)
char *category;
int lc_cat = -1;
+ char save = t->stptr[t->stlen];
+ t->stptr[t->stlen] = '\0';
category = t->stptr;
/* binary search the table */
@@ -3588,6 +3763,7 @@ localecategory_from_argument(NODE *t)
break;
}
}
+ t->stptr[t->stlen] = save;
if (lc_cat == -1) /* not there */
fatal(_("dcgettext: `%s' is not a valid locale category"), category);
@@ -3613,9 +3789,11 @@ do_dcgettext(int nargs)
NODE *tmp, *t1, *t2 = NULL;
char *string;
char *the_result;
+ size_t reslen;
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
int lc_cat;
char *domain;
+ char save1, save2;
if (nargs == 3) { /* third argument */
tmp = POP_STRING();
@@ -3627,6 +3805,7 @@ do_dcgettext(int nargs)
if (nargs >= 2) { /* second argument */
t2 = POP_STRING();
domain = t2->stptr;
+ str_terminate(t2, save2);
} else
domain = TEXTDOMAIN;
#else
@@ -3644,14 +3823,20 @@ do_dcgettext(int nargs)
string = t1->stptr;
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
+ str_terminate(t1, save1);
the_result = dcgettext(domain, string, lc_cat);
- if (t2 != NULL)
+ str_restore(t1, save1);
+ if (t2 != NULL) {
+ str_restore(t2, save2);
DEREF(t2);
+ }
+ reslen = strlen(the_result);
#else
the_result = string;
+ reslen = t1->stlen;
#endif
DEREF(t1);
- return make_string(the_result, strlen(the_result));
+ return make_string(the_result, reslen);
}
@@ -3663,10 +3848,13 @@ do_dcngettext(int nargs)
unsigned long number;
AWKNUM d;
char *the_result;
+ size_t reslen;
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
int lc_cat;
char *domain;
+ char save, save1, save2;
+ bool saved_end = false;
if (nargs == 5) { /* fifth argument */
tmp = POP_STRING();
@@ -3679,6 +3867,9 @@ do_dcngettext(int nargs)
if (nargs >= 4) { /* fourth argument */
t3 = POP_STRING();
domain = t3->stptr;
+ save = domain[t3->stlen];
+ domain[t3->stlen] = '\0';
+ saved_end = true;
} else
domain = TEXTDOMAIN;
#else
@@ -3704,15 +3895,29 @@ do_dcngettext(int nargs)
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
+ str_terminate(t1, save1);
+ str_terminate(t2, save2);
the_result = dcngettext(domain, string1, string2, number, lc_cat);
+ reslen = strlen(the_result);
+ str_restore(t1, save1);
+ str_restore(t2, save2);
+ if (saved_end)
+ domain[t3->stlen] = save;
if (t3 != NULL)
DEREF(t3);
#else
- the_result = (number == 1 ? string1 : string2);
+ if (number == 1) {
+ the_result = string1;
+ reslen = t1->stlen;
+ }
+ else {
+ the_result = string2;
+ reslen = t2->stlen;
+ }
#endif
DEREF(t1);
DEREF(t2);
- return make_string(the_result, strlen(the_result));
+ return make_string(the_result, reslen);
}
/* do_bindtextdomain --- set the directory for a text domain */
@@ -3737,26 +3942,170 @@ do_bindtextdomain(int nargs)
/* set defaults */
directory = NULL;
domain = TEXTDOMAIN;
+ char save, save1;
if (nargs == 2) { /* second argument */
t2 = POP_STRING();
domain = (const char *) t2->stptr;
+ save = t2->stptr[t2->stlen];
+ t2->stptr[t2->stlen] = '\0';
}
/* first argument */
t1 = POP_STRING();
- if (t1->stlen > 0)
+ if (t1->stlen > 0) {
directory = (const char *) t1->stptr;
+ str_terminate(t1, save1);
+ }
the_result = bindtextdomain(domain, directory);
+ if (directory)
+ str_restore(t1, save1);
DEREF(t1);
- if (t2 != NULL)
+ if (t2 != NULL) {
+ t2->stptr[t2->stlen] = save;
DEREF(t2);
+ }
return make_string(the_result, strlen(the_result));
}
+/* do_intdiv --- do integer division, return quotient and remainder in dest array */
+
+/*
+ * We define the semantics as:
+ * numerator = int(numerator)
+ * denominator = int(denonmator)
+ * quotient = int(numerator / denomator)
+ * remainder = int(numerator % denomator)
+ */
+
+NODE *
+do_intdiv(int nargs)
+{
+ NODE *numerator, *denominator, *result;
+ double num, denom, quotient, remainder;
+ NODE *sub, **lhs;
+
+ result = POP_PARAM();
+ if (result->type != Node_var_array)
+ fatal(_("intdiv: third argument is not an array"));
+ assoc_clear(result);
+
+ denominator = POP_SCALAR();
+ numerator = POP_SCALAR();
+
+ if (do_lint) {
+ if ((fixtype(numerator)->flags & NUMBER) == 0)
+ lintwarn(_("intdiv: received non-numeric first argument"));
+ if ((fixtype(denominator)->flags & NUMBER) == 0)
+ lintwarn(_("intdiv: received non-numeric second argument"));
+ }
+
+ (void) force_number(numerator);
+ (void) force_number(denominator);
+ num = double_to_int(get_number_d(numerator));
+ denom = double_to_int(get_number_d(denominator));
+
+ if (denom == 0.0)
+ fatal(_("intdiv: division by zero attempted"));
+
+ quotient = double_to_int(num / denom);
+ /*
+ * FIXME: This code is duplicated, factor it out to a
+ * separate function.
+ */
+#ifdef HAVE_FMOD
+ remainder = fmod(num, denom);
+#else /* ! HAVE_FMOD */
+ (void) modf(num / denom, & remainder);
+ remainder = num - remainder * denom;
+#endif /* ! HAVE_FMOD */
+ remainder = double_to_int(remainder);
+
+ sub = make_string("quotient", 8);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = make_number((AWKNUM) quotient);
+
+ sub = make_string("remainder", 9);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = make_number((AWKNUM) remainder);
+
+ DEREF(denominator);
+ DEREF(numerator);
+
+ return make_number((AWKNUM) 0.0);
+}
+
+/* do_typeof --- return a string with the type of the arg */
+
+NODE *
+do_typeof(int nargs)
+{
+ NODE *arg;
+ char *res = NULL;
+ bool deref = true;
+
+ arg = POP();
+ switch (arg->type) {
+ case Node_var_array:
+ /* Node_var_array is never UPREF'ed */
+ res = "array";
+ deref = false;
+ break;
+ case Node_val:
+ switch (fixtype(arg)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) {
+ case NUMBER:
+ res = "number";
+ break;
+ case NUMBER|USER_INPUT:
+ res = "strnum";
+ break;
+ case REGEX:
+ res = "regexp";
+ break;
+ case STRING:
+ res = "string";
+ // fall through
+ case NUMBER|STRING:
+ if (arg == Nnull_string || (arg->flags & NULL_FIELD) != 0) {
+ res = "unassigned";
+ break;
+ }
+ /* fall through */
+ default:
+ if (res == NULL) {
+ warning(_("typeof detected invalid flags combination `%s'; please file a bug report."), flags2str(arg->flags));
+ res = "unknown";
+ }
+ break;
+ }
+ break;
+ case Node_var_new:
+ res = "untyped";
+ deref = false;
+ break;
+ case Node_var:
+ /*
+ * Note: this doesn't happen because the function calling code
+ * in interpret.h pushes Node_var->var_value.
+ */
+ fatal(_("typeof: invalid argument type `%s'"),
+ nodetype2str(arg->type));
+ break;
+ default:
+ fatal(_("typeof: unknown argument type `%s'"),
+ nodetype2str(arg->type));
+ break;
+ }
+
+ if (deref)
+ DEREF(arg);
+ return make_string(res, strlen(res));
+}
/* mbc_byte_count --- return number of bytes for corresponding numchars multibyte characters */
@@ -3799,17 +4148,39 @@ mbc_char_count(const char *ptr, size_t numbytes)
memset(& cur_state, 0, sizeof(cur_state));
- mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
+ mb_len = mbrlen(ptr, numbytes, &cur_state);
if (mb_len <= 0)
return numbytes; /* no valid m.b. char */
- for (; numbytes > 0; numbytes--) {
- mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
+ while (numbytes > 0) {
+ mb_len = mbrlen(ptr, numbytes, &cur_state);
if (mb_len <= 0)
break;
sum++;
ptr += mb_len;
+ numbytes -= mb_len;
}
return sum;
}
+
+/* sanitize_exit_status --- convert a 16 bit Unix exit status into something reasonable */
+
+int sanitize_exit_status(int status)
+{
+ int ret = 0;
+
+ if (WIFEXITED(status))
+ ret = WEXITSTATUS(status); /* normal exit */
+ else if (WIFSIGNALED(status)) {
+ bool coredumped = false;
+#ifdef WCOREDUMP
+ coredumped = WCOREDUMP(status);
+#endif
+ /* use 256 since exit values are 8 bits */
+ ret = WTERMSIG(status) + (coredumped ? 512 : 256);
+ } else
+ ret = 0; /* shouldn't get here */
+
+ return ret;
+}
diff --git a/cint_array.c b/cint_array.c
index 7a92cb0d..851e980e 100644
--- a/cint_array.c
+++ b/cint_array.c
@@ -2,23 +2,23 @@
* cint_array.c - routines for arrays of (mostly) consecutive positive integer indices.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2013, 2016,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -37,7 +37,7 @@ extern NODE **is_integer(NODE *symbol, NODE *subs);
* THRESHOLD --- Maximum capacity waste; THRESHOLD >= 2^(NHAT + 1).
*/
-static int NHAT = 10;
+static int NHAT = 10;
static long THRESHOLD;
/*
@@ -102,7 +102,7 @@ static void leaf_info(NODE *array, NODE *ndump, const char *aname);
static void leaf_print(NODE *array, size_t bi, int indent_level);
#endif
-/* powers of 2 table upto 2^30 */
+/* powers of 2 table upto 2^30 */
static const long power_two_table[] = {
1, 2, 4, 8, 16, 32, 64,
128, 256, 512, 1024, 2048, 4096,
@@ -118,7 +118,7 @@ static const long power_two_table[] = {
/*
* To store 2^n integers, allocate top-level array of size n, elements
* of which are 1-Dimensional (leaf-array) of geometrically increasing
- * size (power of 2).
+ * size (power of 2).
*
* [0] --> [ 0 ]
* [1] --> [ 1 ]
@@ -128,7 +128,7 @@ static const long power_two_table[] = {
* |k| --> [ 2^(k - 1)| ... | 2^k - 1 ]
* ...
*
- * For a given integer n (> 0), the leaf-array is at 1 + floor(log2(n)).
+ * For a given integer n (> 0), the leaf-array is at 1 + floor(log2(n)).
*
* The idea for the geometrically increasing array sizes is from:
* Fast Functional Lists, Hash-Lists, Deques and Variable Length Arrays.
@@ -228,8 +228,7 @@ cint_lookup(NODE *symbol, NODE *subs)
assert(symbol->table_size == 0);
/* nodes[0] .. nodes[NHAT- 1] not used */
- emalloc(symbol->nodes, NODE **, INT32_BIT * sizeof(NODE *), "cint_lookup");
- memset(symbol->nodes, '\0', INT32_BIT * sizeof(NODE *));
+ ezalloc(symbol->nodes, NODE **, INT32_BIT * sizeof(NODE *), "cint_lookup");
}
symbol->table_size++; /* one more element in array */
@@ -387,14 +386,13 @@ cint_copy(NODE *symbol, NODE *newsymb)
assert(symbol->nodes != NULL);
/* allocate new table */
- emalloc(new, NODE **, INT32_BIT * sizeof(NODE *), "cint_copy");
- memset(new, '\0', INT32_BIT * sizeof(NODE *));
+ ezalloc(new, NODE **, INT32_BIT * sizeof(NODE *), "cint_copy");
old = symbol->nodes;
for (i = NHAT; i < INT32_BIT; i++) {
if (old[i] == NULL)
continue;
- new[i] = make_node(Node_array_tree);
+ new[i] = make_node(Node_array_tree);
tree_copy(newsymb, old[i], new[i]);
}
@@ -494,7 +492,7 @@ cint_dump(NODE *symbol, NODE *ndump)
xsize = xn->table_size;
}
cint_size = symbol->table_size - xsize;
-
+
if ((symbol->flags & XARRAY) == 0)
fprintf(output_fp, "%s `%s'\n",
(symbol->parent_array == NULL) ? "array" : "sub-array",
@@ -525,7 +523,7 @@ cint_dump(NODE *symbol, NODE *ndump)
/* Node_array_tree + HAT */
kb += (sizeof(NODE) + tree_kilobytes(tn)) / 1024.0;
}
- kb += (INT32_BIT * sizeof(NODE *)) / 1024.0; /* symbol->nodes */
+ kb += (INT32_BIT * sizeof(NODE *)) / 1024.0; /* symbol->nodes */
kb += (symbol->array_capacity * sizeof(NODE *)) / 1024.0; /* value nodes in Node_array_leaf(s) */
if (xn != NULL) {
if (xn->array_funcs == int_array_func)
@@ -600,12 +598,12 @@ cint_hash(long k)
* By Sean Eron Anderson
* seander@cs.stanford.edu
* Individually, the code snippets here are in the public domain
- * (unless otherwise noted) — feel free to use them however you please.
- * The aggregate collection and descriptions are © 1997-2005
+ * (unless otherwise noted) --- feel free to use them however you please.
+ * The aggregate collection and descriptions are (C) 1997-2005
* Sean Eron Anderson. The code and descriptions are distributed in the
* hope that they will be useful, but WITHOUT ANY WARRANTY and without
* even the implied warranty of merchantability or fitness for a particular
- * purpose.
+ * purpose.
*
*/
@@ -678,15 +676,15 @@ cint_print(NODE *symbol)
/*
* A half HAT is defined here as a HAT with a top-level array of size n^2/2
* and holds the first n^2/2 elements.
- *
+ *
* 1. 2^8 elements can be stored in a full HAT of size 2^4.
- * 2. 2^9 elements can be stored in a half HAT of size 2^5.
+ * 2. 2^9 elements can be stored in a half HAT of size 2^5.
* 3. When the number of elements is some power of 2, it
* can be stored in a full or a half HAT.
* 4. When the number of elements is some power of 2, it
* can be stored in a HAT (full or half) with HATs as leaf elements
* (full or half), and so on (e.g. 2^8 elements in a HAT of size 2^4 (top-level
- * array dimension) with each leaf array being a HAT of size 2^2).
+ * array dimension) with each leaf array being a HAT of size 2^2).
*
* IMPLEMENTATION DETAILS:
* 1. A HAT of 2^12 elements needs 2^6 house-keeping NODEs
@@ -737,7 +735,7 @@ tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base)
*/
n = (m + 1) / 2;
-
+
if (tree->table_size == 0) {
size_t actual_size;
NODE **table;
@@ -754,8 +752,7 @@ tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base)
actual_size /= 2;
tree->flags |= HALFHAT;
}
- emalloc(table, NODE **, actual_size * sizeof(NODE *), "tree_lookup");
- memset(table, '\0', actual_size * sizeof(NODE *));
+ ezalloc(table, NODE **, actual_size * sizeof(NODE *), "tree_lookup");
tree->nodes = table;
} else
size = tree->array_size;
@@ -920,7 +917,7 @@ tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind)
static void
tree_copy(NODE *newsymb, NODE *tree, NODE *newtree)
-{
+{
NODE **old, **new;
size_t j, hsize;
@@ -928,8 +925,7 @@ tree_copy(NODE *newsymb, NODE *tree, NODE *newtree)
if ((tree->flags & HALFHAT) != 0)
hsize /= 2;
- emalloc(new, NODE **, hsize * sizeof(NODE *), "tree_copy");
- memset(new, '\0', hsize * sizeof(NODE *));
+ ezalloc(new, NODE **, hsize * sizeof(NODE *), "tree_copy");
newtree->nodes = new;
newtree->array_base = tree->array_base;
newtree->array_size = tree->array_size;
@@ -1047,8 +1043,7 @@ leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base)
array->table_size = 0; /* sanity */
array->array_size = size;
array->array_base = base;
- emalloc(array->nodes, NODE **, size * sizeof(NODE *), "leaf_lookup");
- memset(array->nodes, '\0', size * sizeof(NODE *));
+ ezalloc(array->nodes, NODE **, size * sizeof(NODE *), "leaf_lookup");
symbol->array_capacity += size;
}
@@ -1061,13 +1056,13 @@ leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base)
}
-/* leaf_exists --- check if the array contains an integer subscript */
+/* leaf_exists --- check if the array contains an integer subscript */
static inline NODE **
leaf_exists(NODE *array, long k)
{
NODE **lhs;
- lhs = array->nodes + (k - array->array_base);
+ lhs = array->nodes + (k - array->array_base);
return (*lhs != NULL) ? lhs : NULL;
}
@@ -1086,7 +1081,7 @@ leaf_clear(NODE *array)
continue;
if (r->type == Node_var_array) {
assoc_clear(r); /* recursively clear all sub-arrays */
- efree(r->vname);
+ efree(r->vname);
freenode(r);
} else
unref(r);
@@ -1104,7 +1099,7 @@ leaf_remove(NODE *symbol, NODE *array, long k)
{
NODE **lhs;
- lhs = array->nodes + (k - array->array_base);
+ lhs = array->nodes + (k - array->array_base);
if (*lhs == NULL)
return false;
*lhs = NULL;
@@ -1127,8 +1122,7 @@ leaf_copy(NODE *newsymb, NODE *array, NODE *newarray)
long size, i;
size = array->array_size;
- emalloc(new, NODE **, size * sizeof(NODE *), "leaf_copy");
- memset(new, '\0', size * sizeof(NODE *));
+ ezalloc(new, NODE **, size * sizeof(NODE *), "leaf_copy");
newarray->nodes = new;
newarray->array_size = size;
newarray->array_base = array->array_base;
@@ -1171,7 +1165,7 @@ leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind)
/* index */
num = array->array_base + ci;
if ((assoc_kind & AISTR) != 0) {
- sprintf(buf, "%ld", num);
+ sprintf(buf, "%ld", num);
subs = make_string(buf, strlen(buf));
subs->numbr = num;
subs->flags |= (NUMCUR|NUMINT);
diff --git a/cmake/ChangeLog b/cmake/ChangeLog
new file mode 100644
index 00000000..d5e37043
--- /dev/null
+++ b/cmake/ChangeLog
@@ -0,0 +1,12 @@
+2016-12-27 Juergen Kahrs <Juergen.Kahrs@googlemail.com>
+
+ * configure.cmake: Include po directory.
+
+2014-08-12 Juergen Kahrs <jkahrs@users.sourceforge.net>
+
+ (Date is approximate).
+
+ * Toolchain_clang.cmake, Toolchain_generic.cmake,
+ Toolchain_mingw32.cmake, Toolchain_s390.cmake,
+ auk.ico, basictest, configure, configure.cmake,
+ docmaker, package.cmake: New files.
diff --git a/cmake/Toolchain_clang.cmake b/cmake/Toolchain_clang.cmake
new file mode 100644
index 00000000..89353570
--- /dev/null
+++ b/cmake/Toolchain_clang.cmake
@@ -0,0 +1,19 @@
+# http://www.cmake.org/Wiki/CmakeMingw
+# http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Generic)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER /usr/bin/clang)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH /usr/lib64/clang/3.1)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
diff --git a/cmake/Toolchain_generic.cmake b/cmake/Toolchain_generic.cmake
new file mode 100644
index 00000000..91ddc6e7
--- /dev/null
+++ b/cmake/Toolchain_generic.cmake
@@ -0,0 +1,21 @@
+# http://www.cmake.org/Wiki/CmakeMingw
+# http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Generic)
+
+# which compilers to use for C and C++
+# Settings for Ubuntu 12.04.1 LTS
+SET(CMAKE_C_COMPILER /usr/bin/gcc)
+
+# here is the target environment located
+# Settings for Ubuntu 12.04.1 LTS
+SET(CMAKE_FIND_ROOT_PATH /usr/)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
diff --git a/cmake/Toolchain_mingw32.cmake b/cmake/Toolchain_mingw32.cmake
new file mode 100644
index 00000000..bb885f2f
--- /dev/null
+++ b/cmake/Toolchain_mingw32.cmake
@@ -0,0 +1,23 @@
+# http://www.cmake.org/Wiki/CmakeMingw
+# http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Windows)
+
+# which compilers to use for C and C++
+# Settings for Ubuntu 12.04.1 LTS
+SET(CMAKE_C_COMPILER /usr/bin/i686-w64-mingw32-gcc)
+SET(CMAKE_CXX_COMPILER /usr/bin/i686-w64-mingw32-g++)
+SET(CMAKE_RC_COMPILER /usr/bin/i686-w64-mingw32-windres)
+
+# here is the target environment located
+# Settings for Ubuntu 12.04.1 LTS
+SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
diff --git a/cmake/Toolchain_s390.cmake b/cmake/Toolchain_s390.cmake
new file mode 100644
index 00000000..e1cdcfff
--- /dev/null
+++ b/cmake/Toolchain_s390.cmake
@@ -0,0 +1,20 @@
+# http://www.cmake.org/Wiki/CmakeMingw
+# http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file
+# http://wiki.debian.org/EmdebianToolchain#Get_the_binaries
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Generic)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER /usr/bin/s390-linux-gnu-gcc-4.4)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH /usr/s390-linux-gnu/)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
diff --git a/cmake/auk.ico b/cmake/auk.ico
new file mode 100644
index 00000000..795ef1d9
--- /dev/null
+++ b/cmake/auk.ico
Binary files differ
diff --git a/cmake/basictest b/cmake/basictest
new file mode 100755
index 00000000..210ed224
--- /dev/null
+++ b/cmake/basictest
@@ -0,0 +1,553 @@
+#!/bin/sh
+
+# Use this for debugging the test cases.
+# The resulting textual output will not destroy the test cases.
+set -x
+# After test case execution, the output can be found in
+# build/Testing/Temporary/LastTest.log
+
+export PATH=$PATH:/c/MinGW/msys/1.0/bin
+export GAWKEXE=$1
+export TESTCASE=$2
+TOPSRCDIR=$(dirname ${0})/..
+SRCDIR=${TOPSRCDIR}/test
+export AWKPATH=${SRCDIR}
+export AWKLIBPATH=$(dirname ${GAWKEXE})/extension/
+export LANG=C
+# Is this shell running in a native MinGW shell (MSYS) ?
+if test -n "$COMSPEC"; then
+ # Ignore all differences in white space.
+ COMPARE="diff -w"
+ PATH_SEPARATOR="\\"
+else
+ # This is a shell running in Unix environment.
+ COMPARE="cmp"
+ PATH_SEPARATOR="/"
+fi
+
+# This is the central function for executing a standard test case.
+# Many of the more specialized test cases rely on this function.
+function simple_test_case() {
+ local options=$1 # options passed to the gawk executable
+ local parameters=$2 # parameters passed to the test case script
+ cd ${SRCDIR}
+ if test -r ${TESTCASE}.in
+ # Any existing .in file will be redirected to standard input.
+ # The output redirection must be bound to the test script, otherwise
+ # the "set -x" logging would mix with the test case output.
+ then
+ ${pregawk} $GAWKEXE ${options} -f ${TESTCASE}.awk ${parameters} < ${TESTCASE}.in ${postgawk} > _${TESTCASE} 2>&1
+ else
+ ${pregawk} $GAWKEXE ${options} -f ${TESTCASE}.awk ${parameters} ${postgawk} > _${TESTCASE} 2>&1
+ fi || echo EXIT CODE: $? >> _${TESTCASE}
+ # Compare the expected (correct) output with the actual output.
+ ${COMPARE} ${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+ # If the comparison succeeds then remove the actual output.
+ # Else leave the actual output file untouched for later analysis.
+}
+
+# Each test case that cannot be handle in the "standard way" shall
+# be implemented as a function here.
+
+function lintold() { simple_test_case "--lint-old" "" ; }
+function defref() { simple_test_case "--lint" "" ; }
+function fmtspcl() { simple_test_case "--lint" "" ; }
+function lintwarn() { simple_test_case "--lint" "" ; }
+function noeffect() { simple_test_case "--lint" "" ; }
+function nofmtch() { simple_test_case "--lint" "" ; }
+function shadow() { simple_test_case "--lint" "" ; }
+function uninit2() { simple_test_case "--lint" "" ; }
+function uninit3() { simple_test_case "--lint" "" ; }
+function uninit4() { simple_test_case "--lint" "" ; }
+function uninit5() { simple_test_case "--lint" "" ; }
+function uninitialized() { simple_test_case "--lint" "" ; }
+
+function regtest() {
+ echo 'Some of the output from regtest is very system specific, do not'
+ echo 'be distressed if your output differs from that distributed.'
+ echo 'Manual inspection is called for.'
+ AWK=$GAWKEXE ${SRCDIR}/regtest.sh
+}
+
+function compare() { simple_test_case "" "0 1" ; }
+
+function inftest() {
+ echo This test is very machine specific...
+ $GAWKEXE -f ${SRCDIR}/inftest.awk | sed "s/inf/Inf/g" >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function getline2() { simple_test_case "" "getline2.awk getline2.awk" ; }
+
+function awkpath() {
+ AWKPATH="${SRCDIR}$(PATH_SEPARATOR)/lib" $GAWKEXE -f awkpath.awk >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function argtest() { simple_test_case "" "-x -y abc" ; }
+
+function badargs() {
+ $GAWKEXE -f 2>&1 | grep -v patchlevel >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function nonl() { simple_test_case "--lint" "/dev/null" ; }
+
+function poundbang() {
+# The original poundbang test case looks a bit non-deterministic.
+# This is a shortened version.
+ sed "s;/tmp/gawk;$GAWKEXE;" < ${SRCDIR}/poundbang.awk > ./_pbd.awk
+ chmod +x ./_pbd.awk
+ ./_pbd.awk ${SRCDIR}/poundbang.awk > _`basename ${TESTCASE}` ;
+ ${COMPARE} ${SRCDIR}/poundbang.awk _`basename ${TESTCASE}` && rm -f _`basename ${TESTCASE}` _pbd.awk
+}
+
+function messages() {
+ $GAWKEXE -f ${SRCDIR}/messages.awk >_out2 2>_out3
+ ${COMPARE} ${SRCDIR}/out1.ok _out1 && ${COMPARE} ${SRCDIR}/out2.ok _out2 && ${COMPARE} ${SRCDIR}/out3.ok _out3 && rm -f _out1 _out2 _out3
+}
+
+function argarray() {
+ case ${SRCDIR} in
+ .) : ;;
+ *) cp ${SRCDIR}/argarray.in . ;;
+ esac
+ TEST=test echo just a test | $GAWKEXE -f ${SRCDIR}/argarray.awk ./argarray.in - >_${TESTCASE}
+ case ${SRCDIR} in
+ .) : ;;
+ *) rm -f ./argarray.in ;;
+ esac
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+
+function localenl() {
+ ${SRCDIR}/${TESTCASE}.sh >_${TESTCASE} 2>/dev/null
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function mbprintf1() {
+ GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE
+ LANG=en_US.UTF-8
+ $GAWKEXE -f ${SRCDIR}/${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.in >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >> _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function mbfw1() {
+ GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE
+ LANG=en_US.UTF-8
+ $GAWKEXE -f ${SRCDIR}/${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.in >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >> _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function printfbad2() {
+ $GAWKEXE --lint -f ${SRCDIR}/${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.in 2>&1 | sed "s;$SRCDIR/;;g" >_${TESTCASE} || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function beginfile1() {
+ AWKPATH=${SRCDIR} $GAWKEXE -f ${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.awk . ./no/such/file Makefile >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function beginfile2() {
+ # This differs from the original, the pwd part is new.
+ # The re-direction is now bound to the .sh file.
+ # This way the output of "set -x" is not written to the script's output file.
+ ( cd ${SRCDIR} && LC_ALL=C AWK="$GAWKEXE" ${SRCDIR}/${TESTCASE}.sh ${SRCDIR}/${TESTCASE}.in > `pwd`/_${TESTCASE} 2>&1 )
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok ${SRCDIR}/_${TESTCASE} && rm -f ${SRCDIR}/_${TESTCASE}
+}
+
+function dumpvars() {
+ AWKPATH=${SRCDIR} $GAWKEXE --dump-variables 1 < ${SRCDIR}/${TESTCASE}.in >/dev/null 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ mv awkvars.out _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function manyfiles() {
+ rm -rf junk
+ mkdir junk
+ $GAWKEXE 'BEGIN { for (i = 1; i <= 1030; i++) print i, i}' >_${TESTCASE}
+ $GAWKEXE -f ${SRCDIR}/manyfiles.awk _${TESTCASE} _${TESTCASE}
+ wc -l junk/* | $GAWKEXE '$1 != 2' | wc -l | sed "s/ *//g" > _${TESTCASE}
+ rm -rf junk
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function exitval1() {
+ $GAWKEXE -f ${SRCDIR}/exitval1.awk >_${TESTCASE} 2>&1; echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function fsspcoln() {
+ $GAWKEXE -f ${SRCDIR}/${TESTCASE}.awk 'FS=[ :]+' ${SRCDIR}/${TESTCASE}.in >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rsstart2() {
+ $GAWKEXE -f ${SRCDIR}/${TESTCASE}.awk ${SRCDIR}/rsstart1.in >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rsstart3() {
+ head ${SRCDIR}/rsstart1.in | $GAWKEXE -f ${SRCDIR}/rsstart2.awk >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function strftime() {
+ echo This test could fail on slow machines or on a minute boundary,
+ echo so if it does, double check the actual results:
+ GAWKLOCALE=C; export GAWKLOCALE
+ TZ=GMT0; export TZ
+ (LC_ALL=C date) | $GAWKEXE -v OUTPUT=_${TESTCASE} -f ${SRCDIR}/strftime.awk
+ ${COMPARE} strftime.ok _${TESTCASE} && rm -f _${TESTCASE} strftime.ok || exit 0
+}
+
+function inplace1() {
+ cp ${SRCDIR}/inplace.1.in _${TESTCASE}.1
+ cp ${SRCDIR}/inplace.2.in _${TESTCASE}.2
+ AWKPATH=${SRCDIR}/../awklib/eg/lib $GAWKEXE -i inplace 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _${TESTCASE}.1 - _${TESTCASE}.2 < ${SRCDIR}/inplace.in >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.1.ok _${TESTCASE}.1 && rm -f _${TESTCASE}.1
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.2.ok _${TESTCASE}.2 && rm -f _${TESTCASE}.2
+}
+
+function inplace2() {
+ cp ${SRCDIR}/inplace.1.in _${TESTCASE}.1
+ cp ${SRCDIR}/inplace.2.in _${TESTCASE}.2
+ AWKPATH=${SRCDIR}/../awklib/eg/lib $GAWKEXE -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _${TESTCASE}.1 - _${TESTCASE}.2 < ${SRCDIR}/inplace.in >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.1.ok _${TESTCASE}.1 && rm -f _${TESTCASE}.1
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.1.bak.ok _${TESTCASE}.1.bak && rm -f _${TESTCASE}.1.bak
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.2.ok _${TESTCASE}.2 && rm -f _${TESTCASE}.2
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.2.bak.ok _${TESTCASE}.2.bak && rm -f _${TESTCASE}.2.bak
+}
+
+function inplace3() {
+ cp ${SRCDIR}/inplace.1.in _${TESTCASE}.1
+ cp ${SRCDIR}/inplace.2.in _${TESTCASE}.2
+ AWKPATH=${SRCDIR}/../awklib/eg/lib $GAWKEXE -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "before"} {gsub(/foo/, "bar"); print} END {print "after"}' _${TESTCASE}.1 - _${TESTCASE}.2 < ${SRCDIR}/inplace.in >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ AWKPATH=${SRCDIR}/../awklib/eg/lib $GAWKEXE -i inplace -v INPLACE_SUFFIX=.bak 'BEGIN {print "Before"} {gsub(/bar/, "foo"); print} END {print "After"}' _${TESTCASE}.1 - _${TESTCASE}.2 < ${SRCDIR}/inplace.in >>_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.1.ok _${TESTCASE}.1 && rm -f _${TESTCASE}.1
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.1.bak.ok _${TESTCASE}.1.bak && rm -f _${TESTCASE}.1.bak
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.2.ok _${TESTCASE}.2 && rm -f _${TESTCASE}.2
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.2.bak.ok _${TESTCASE}.2.bak && rm -f _${TESTCASE}.2.bak
+}
+
+function testext() {
+ $GAWKEXE ' /^(@load|BEGIN)/,/^}/' ${SRCDIR}/../extension/testext.c > testext.awk
+ $GAWKEXE -f ${TESTCASE}.awk > ${SRCDIR}/_${TESTCASE} 2>&1 || echo EXIT CODE: $? >> ${SRCDIR}/_${TESTCASE}
+ rm -f testext.awk
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok ${SRCDIR}/_${TESTCASE} && rm -f ${SRCDIR}/_${TESTCASE}
+}
+
+function readdir() {
+ if [ "`uname`" = Linux ] && [ "`stat -f . 2>/dev/null | awk 'NR == 2 { print $NF }'`" = nfs ]; then
+ echo This test may fail on GNU/Linux systems when run on an NFS filesystem.;
+ echo If it does, try rerunning on an ext'[234]' filesystem. ;
+ fi
+ $GAWKEXE -f ${TESTCASE}.awk ${SRCDIR}/.. > ${SRCDIR}/_${TESTCASE} 2>&1
+ ls -afli ${TOPSRCDIR} | sed 1d | $GAWKEXE -f ${SRCDIR}/readdir0.awk -v extout=${SRCDIR}/_${TESTCASE} > ${SRCDIR}/${TESTCASE}.ok
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok ${SRCDIR}/_${TESTCASE} && rm -f ${SRCDIR}/_${TESTCASE} ${SRCDIR}/${TESTCASE}.ok
+}
+
+function ordchr2() {
+ $GAWKEXE -l ordchr 'BEGIN {print chr(ord("z"))}' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function include2() {
+ AWKPATH=${SRCDIR} $GAWKEXE -i inclib 'BEGIN {print sandwich("a", "b", "c")}' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -i inclib -i inclib.awk 'BEGIN {print sandwich("a", "b", "c")}' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe2() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -f inclib -f inclib.awk >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe3() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -f hello -f hello.awk >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe4() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -f hello -i hello.awk >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe5() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -i hello -f hello.awk >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe6() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -i inchello -f hello.awk >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function incdupe7() {
+ AWKPATH=${SRCDIR} $GAWKEXE --lint -f hello -i inchello >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+# TODO: The compare operation passes even when there are diffs.
+function readfile() {
+ $GAWKEXE -l readfile 'BEGIN {printf "%s", readfile("Makefile")}' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} Makefile _${TESTCASE} && rm -f _${TESTCASE} || cp -p Makefile ${TESTCASE}.ok
+}
+
+function fts() {
+ if [ "`uname`" = IRIX ]; then \
+ echo This test may fail on IRIX systems when run on an NFS filesystem.; \
+ echo If it does, try rerunning on an xfs filesystem. ; \
+ fi
+ simple_test_case "" ""
+}
+
+function charasbytes() {
+ [ -z "$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ AWKPATH=${SRCDIR} $GAWKEXE -b -v BINMODE=2 -f ${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.in | \
+ od -c -t x1 | sed -e 's/ */ /g' -e 's/ *$//' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function symtab6() {
+ $GAWKEXE -d__${TESTCASE} -f ${SRCDIR}/${TESTCASE}.awk
+ grep -v '^ENVIRON' __${TESTCASE} | grep -v '^PROCINFO' > _${TESTCASE} ; rm __${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function symtab8() {
+ $GAWKEXE -d__${TESTCASE} -f ${SRCDIR}/${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.in >_${TESTCASE}
+ grep -v '^ENVIRON' __${TESTCASE} | grep -v '^PROCINFO' | grep -v '^FILENAME' >> _${TESTCASE} ; rm __${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function colonwarn() {
+ for i in 1 2 3 ; \
+ do $GAWKEXE -f ${SRCDIR}/${TESTCASE}.awk $i < ${SRCDIR}/${TESTCASE}.in ; \
+ done > _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function litoct() {
+ echo ab | $GAWKEXE --traditional -f ${SRCDIR}/litoct.awk >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function devfd() {
+ $GAWKEXE 1 /dev/fd/4 /dev/fd/5 4<${SRCDIR}/devfd.in4 5<${SRCDIR}/devfd.in5 >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >> _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function fflush() {
+ ${SRCDIR}/fflush.sh >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function mmap8k() {
+ $GAWKEXE '{ print }' ${SRCDIR}/mmap8k.in >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/mmap8k.in _${TESTCASE} && rm -f _${TESTCASE} || cp ${SRCDIR}/${TESTCASE}.in ${TESTCASE}.ok
+}
+
+function pid() {
+ AWKPATH=${SRCDIR} AWK=$GAWKEXE ${SHELL} ${SRCDIR}/pid.sh $$ > _${TESTCASE} ; :
+ ${COMPARE} ${SRCDIR}/pid.ok _`basename ${TESTCASE}` && rm -f _${TESTCASE}
+}
+
+function strftlng() {
+ TZ=UTC; export TZ; $GAWKEXE -f ${SRCDIR}/strftlng.awk >_${TESTCASE}
+ if ${COMPARE} ${SRCDIR}/strftlng.ok _${TESTCASE} >/dev/null 2>&1 ; then : ; else \
+ TZ=UTC0; export TZ; $GAWKEXE -f ${SRCDIR}/strftlng.awk >_${TESTCASE} ; \
+ fi
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function nors() {
+ echo A B C D E | tr -d '\12\15' | $GAWKEXE '{ print $NF }' - ${SRCDIR}/nors.in > _${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function fmtspcl() {
+ $GAWKEXE -v "sd=${SRCDIR}" 'BEGIN {pnan = sprintf("%g",sqrt(-1)); nnan = sprintf("%g",-sqrt(-1)); pinf = sprintf("%g",-log(0)); ninf = sprintf("%g",log(0))} {sub(/positive_nan/,pnan); sub(/negative_nan/,nnan); sub(/positive_infinity/,pinf); sub(/negative_infinity/,ninf); sub(/fmtspcl/,(sd"/fmtspcl")); print}' < ${SRCDIR}/fmtspcl.tok > ${TESTCASE}.ok 2>/dev/null
+ $GAWKEXE $AWKFLAGS -f ${SRCDIR}/fmtspcl.awk --lint >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ if test -z "$AWKFLAGS" ; then
+ ${COMPARE} ${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+ else
+ ${COMPARE} ${SRCDIR}/${TESTCASE}-mpfr.ok _${TESTCASE} && rm -f _${TESTCASE}
+ fi
+}
+
+function pipeio2() { simple_test_case "-v SRCDIR=${SRCDIR}" "" ; }
+
+function arynocls() {
+ AWKPATH=${SRCDIR} $GAWKEXE -v INPUT=${SRCDIR}/arynocls.in -f arynocls.awk >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function inetechu() {
+ echo This test is for establishing UDP connections
+ $GAWKEXE 'BEGIN {print "" |& "/inet/udp/0/127.0.0.1/9"}'
+}
+
+function inetecht() {
+ echo This test is for establishing TCP connections
+ $GAWKEXE 'BEGIN {print "" |& "/inet/tcp/0/127.0.0.1/9"}'
+}
+
+function inetdayu() {
+ echo This test is for bidirectional UDP transmission
+ $GAWKEXE 'BEGIN { print "" |& "/inet/udp/0/127.0.0.1/13"; \
+ "/inet/udp/0/127.0.0.1/13" |& getline; print $0}'
+}
+
+function inetdayt() {
+ echo This test is for bidirectional TCP transmission
+ $GAWKEXE 'BEGIN { print "" |& "/inet/tcp/0/127.0.0.1/13"; \
+ "/inet/tcp/0/127.0.0.1/13" |& getline; print $0}'
+}
+
+function redfilnm() { simple_test_case "" "srcdir=${SRCDIR}" ; }
+
+function leaddig() { simple_test_case "-v x=2E" "" ; }
+function longwrds() { simple_test_case "-vSORT=sort" "" ; }
+
+function gsubtst3() {
+ $GAWKEXE --re-interval -f ${SRCDIR}/${TESTCASE}.awk ${SRCDIR}/${TESTCASE}.in >_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function space() {
+ $GAWKEXE -f ' ' ${SRCDIR}/space.awk >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rsnulbig() {
+ # Suppose that block size for pipe is at most 128kB:
+ $GAWKEXE 'BEGIN { for (i = 1; i <= 128*64+1; i++) print "abcdefgh123456\n" }' 2>&1 | \
+ $GAWKEXE 'BEGIN { RS = ""; ORS = "\n\n" }; { print }' 2>&1 | \
+ $GAWKEXE '/^[^a]/; END{ print NR }' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rsnulbig2() {
+ $GAWKEXE 'BEGIN { ORS = ""; n = "\n"; for (i = 1; i <= 10; i++) n = (n n); \
+ for (i = 1; i <= 128; i++) print n; print "abc\n" }' 2>&1 | \
+ $GAWKEXE 'BEGIN { RS = ""; ORS = "\n\n" };{ print }' 2>&1 | \
+ $GAWKEXE '/^[^a]/; END { print NR }' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function printf0() { simple_test_case "--posix" "" ; }
+
+function profile1() {
+ $GAWKEXE --pretty-print=ap-${TESTCASE}.out -f ${SRCDIR}/xref.awk ${SRCDIR}/dtdgport.awk > _${TESTCASE}.out1
+ $GAWKEXE -f ap-${TESTCASE}.out ${SRCDIR}/dtdgport.awk > _${TESTCASE}.out2 ; rm ap-${TESTCASE}.out
+ ${COMPARE} _${TESTCASE}.out1 _${TESTCASE}.out2 && rm _${TESTCASE}.out[12] || { echo EXIT CODE: $$? >>_${TESTCASE} ; \
+ cp $(srcdir)/dtdgport.awk > ${TESTCASE}.ok ; }
+}
+
+function profile2() {
+ $GAWKEXE --profile=ap-${TESTCASE}.out -v sortcmd=sort -f ${SRCDIR}/xref.awk ${SRCDIR}/dtdgport.awk > /dev/null
+ sed 1,2d < ap-${TESTCASE}.out > _${TESTCASE}; rm ap-${TESTCASE}.out
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function profile3() {
+ $GAWKEXE --profile=ap-${TESTCASE}.out -f ${SRCDIR}/${TESTCASE}.awk > /dev/null
+ sed 1,2d < ap-${TESTCASE}.out > _${TESTCASE}; rm ap-${TESTCASE}.out
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function profile4() {
+ GAWK_NO_PP_RUN=1 $GAWKEXE --profile=ap-${TESTCASE}.out -f ${SRCDIR}/${TESTCASE}.awk > /dev/null
+ sed 1,2d < ap-${TESTCASE}.out > _${TESTCASE}; rm ap-${TESTCASE}.out
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function profile5() {
+ GAWK_NO_PP_RUN=1 $GAWKEXE --profile=ap-${TESTCASE}.out -f ${SRCDIR}/${TESTCASE}.awk > /dev/null
+ sed 1,2d < ap-${TESTCASE}.out > _${TESTCASE}; rm ap-${TESTCASE}.out
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function posix2008sub() {
+ $GAWKEXE --posix -f ${SRCDIR}/${TESTCASE}.awk > _${TESTCASE} 2>&1
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function next() {
+ LC_ALL=${GAWKLOCALE:-C} LANG=${GAWKLOCALE:-C} AWK="$GAWKEXE" ${SRCDIR}/${TESTCASE}.sh > _${TESTCASE} 2>&1
+ LC_ALL=C ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function exit() {
+ AWK="$GAWKEXE" ${SRCDIR}/${TESTCASE}.sh > _${TESTCASE} 2>&1
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function mpfrexprange() { simple_test_case "-M -vPREC=53 " "" ; }
+function mpfrrnd() { simple_test_case "-M -vPREC=53 " "" ; }
+function mpfrnr() { simple_test_case "-M -vPREC=113" "" ; }
+function mpfrbigint() { simple_test_case "-M " "" ; }
+
+function jarebug() {
+ ${SRCDIR}/${TESTCASE}.sh "$GAWKEXE" "${SRCDIR}/${TESTCASE}.awk" "${SRCDIR}/${TESTCASE}.in" "_${TESTCASE}"
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rtlen() {
+ ${SRCDIR}/${TESTCASE}.sh >_${TESTCASE} || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rtlen01() {
+ ${SRCDIR}/${TESTCASE}.sh >_${TESTCASE} || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function rtlenmb() {
+ GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE
+ ${SRCDIR}/rtlen.sh >_${TESTCASE} || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function nondec2() { simple_test_case "--non-decimal-data -v a=0x1" "" ; }
+
+function nofile() {
+ $GAWKEXE '{}' no/such/file >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function binmode1() {
+ $GAWKEXE -v BINMODE=3 'BEGIN { print BINMODE }' >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function devfd1() {
+ $GAWKEXE -f ${SRCDIR}/${TESTCASE}.awk 4< ${SRCDIR}/devfd.in1 5< ${SRCDIR}/devfd.in2 >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+function devfd2() {
+ # The program text is the '1' which will print each record. How compact can you get?
+ $GAWKEXE 1 /dev/fd/4 /dev/fd/5 4< ${SRCDIR}/devfd.in1 5< ${SRCDIR}/devfd.in2 >_${TESTCASE} 2>&1 || echo EXIT CODE: $? >>_${TESTCASE}
+ ${COMPARE} ${SRCDIR}/${TESTCASE}.ok _${TESTCASE} && rm -f _${TESTCASE}
+}
+
+# Is this test case implemented as a function ?
+if [ "$( type -t $TESTCASE )" = "function" ]
+then
+ $TESTCASE
+else
+ # If no function exists, then treat the test case in standard way.
+ simple_test_case "" ""
+fi
+
diff --git a/cmake/configure b/cmake/configure
new file mode 100755
index 00000000..d375a81c
--- /dev/null
+++ b/cmake/configure
@@ -0,0 +1,58 @@
+#!/bin/sh
+# On 2013-05-14 Arnold wrote in an e-mail:
+
+# <QUOTE)
+# I think that using CMake would be more palatable if there is also a simple
+# configure wrapper that can be used by people who build distributions. This would
+# mean things like
+#
+# configure CC=XXXX # XXXX in { gcc, clang, tcc } or native platform cc
+# configure --prefix=/path/to/install
+#
+# And the few other current configure options like --with-whiny-user-strftime,
+# --disable-nls, etc. I don't know if we need all the standard configure options,
+# but I do want the ones I've added in configure.ac.
+# </QUOTE)
+
+
+# Anyone using this script still needs an out-of-source build directory.
+if [ -f CMakeLists.txt ] ; then
+ echo "Your current working directory contains a file CMakeLists.txt, indicating"
+ echo "that this is a source directory. Create a new directory elsewhere, change into"
+ echo "this empty directory and try again."
+ echo " mkdir build"
+ echo " cd build"
+ echo " ../$0"
+ exit 1
+fi
+
+# TODO: Evaluate all the options and translate the options into CMake variables.
+CC=$( which cc )
+PREFIX=""
+SRCDIR=".."
+WHINY=""
+
+for p in $@
+do
+ if [ ${p:0:3} = "CC=" ]; then CC=${p:3}; fi
+ if [ ${p:0:9} = "--prefix=" ]; then PREFIX=-DCMAKE_INSTALL_PREFIX=${p:9}; fi
+ if [ ${p:0:9} = "--srcdir=" ]; then SRCDIR=${p:9}; fi
+ if [ ${p:0:26} = "--with-whiny-user-strftime" ]; then WHINY=-DUSE_INCLUDED_STRFTIME=1; fi
+done
+CC=$( which $CC )
+
+rm -f Toolchain.cmake
+(
+ echo "set(CMAKE_C_COMPILER $CC)"
+ echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)"
+ echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)"
+ echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)"
+) > Toolchain.cmake
+
+if ! [ -f ${SRCDIR}/CMakeLists.txt ] ; then
+ echo "The source directory (${SRCDIR}) does not contain a file CMakeLists.txt."
+ exit 1
+fi
+
+cmake ${PREFIX} ${WHINY} -DCMAKE_TOOLCHAIN_FILE=Toolchain.cmake ${SRCDIR}
+
diff --git a/cmake/configure.cmake b/cmake/configure.cmake
new file mode 100644
index 00000000..6e18c7c9
--- /dev/null
+++ b/cmake/configure.cmake
@@ -0,0 +1,309 @@
+#
+# cmake/configure --- CMake input file for gawk
+#
+# Copyright (C) 2013-2014
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with CMake to produce Makefile
+
+option (USE_CONFIG_H "Generate a file config.h for inclusion into C source code" ON)
+if (USE_CONFIG_H)
+ file( WRITE config.h "/* all settings defined by CMake. */\n\n" )
+ ADD_DEFINITIONS (-D HAVE_CONFIG_H)
+ # Configure a header file to pass some of the CMake settings
+ # to the source code
+ # http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:configure_file
+ # CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h IMMEDIATE )
+else()
+ file( WRITE config.h "/* empty file, all settings defined by CMake. */" )
+endif()
+
+include(CheckIncludeFiles)
+include(CheckIncludeFile)
+include(CheckSymbolExists)
+include(CheckFunctionExists)
+include(CheckLibraryExists)
+include(CheckTypeSize)
+include(CheckStructHasMember)
+INCLUDE(CheckCSourceCompiles)
+include(CheckPrototypeDefinition)
+
+MACRO(DefineConfigH feature)
+# message(STATUS feature=${feature}=${${feature}})
+ if (${feature})
+ if (${USE_CONFIG_H} STREQUAL ON)
+ FILE( APPEND config.h "#define ${feature} ${${feature}}\n")
+ else()
+ #ADD_DEFINITIONS (-D ${feature})
+ ADD_DEFINITIONS (-D${feature}=${${feature}})
+ endif ()
+ endif ()
+ENDMACRO(DefineConfigH)
+
+MACRO(DefineConfigHValue feature value)
+ set(${feature} ${value})
+ DefineConfigH(${feature})
+ENDMACRO(DefineConfigHValue)
+
+MACRO(DefineFunctionIfAvailable func feature)
+ check_function_exists("${func}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineFunctionIfAvailable)
+
+MACRO(DefineHFileIfAvailable hfile feature)
+ check_include_file("${hfile}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineHFileIfAvailable)
+
+MACRO(DefineTypeIfAvailable type feature)
+ check_type_size("${type}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineTypeIfAvailable)
+
+MACRO(DefineSymbolIfAvailable symbol hfile feature)
+ check_symbol_exists("${symbol}" "${hfile}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineSymbolIfAvailable)
+
+MACRO(DefineStructHasMemberIfAvailable struct member hfile feature)
+ check_struct_has_member("${struct}" "${member}" "${hfile}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineStructHasMemberIfAvailable)
+
+MACRO(DefineLibraryIfAvailable lib func location feature)
+ check_library_exists("${lib}" "${func}" "${location}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineLibraryIfAvailable)
+
+MACRO(DefineIfSourceCompiles source feature)
+ check_c_source_compiles( "${source}" "${feature}")
+ DefineConfigH(${feature})
+ENDMACRO(DefineIfSourceCompiles)
+
+FILE( READ ${CMAKE_SOURCE_DIR}/configure.ac CONFIG_AUTOMAKE )
+STRING( REGEX MATCH "AC_INIT\\(\\[GNU Awk\\], ([0-9]+\\.[0-9]+\\.[0-9]+)" GAWK_AUTOMAKE_LINE_VERSION "${CONFIG_AUTOMAKE}")
+STRING( REGEX REPLACE ".*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" GAWK_MAJOR_VERSION "${GAWK_AUTOMAKE_LINE_VERSION}")
+STRING( REGEX REPLACE ".*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" GAWK_MINOR_VERSION "${GAWK_AUTOMAKE_LINE_VERSION}")
+STRING( REGEX REPLACE ".*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GAWK_BUGFIX_VERSION "${GAWK_AUTOMAKE_LINE_VERSION}")
+
+# The definition of the symbol GAWK cannot be passed in config.h
+# because the extensions will fail to build.
+add_definitions(-DGAWK)
+add_definitions(-DSTDC_HEADERS)
+# Tell the C compiler to accept C99.
+if (CMAKE_VERSION VERSION_LESS "3.1")
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ set (CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}")
+ endif ()
+else ()
+ set (CMAKE_C_STANDARD 99)
+endif ()
+DefineConfigHValue(_GL_ATTRIBUTE_PURE "__attribute__ ((__pure__))")
+DefineConfigHValue(GAWK_VERSION "${GAWK_MAJOR_VERSION}.${GAWK_MINOR_VERSION}.${GAWK_BUGFIX_VERSION}")
+DefineConfigHValue(VERSION \\"${GAWK_VERSION}\\")
+DefineConfigHValue(PACKAGE \\"gawk\\")
+DefineConfigHValue(PACKAGE_STRING \\"GNU Awk ${GAWK_VERSION}\\")
+DefineConfigHValue(PACKAGE_TARNAME \\"gawk\\")
+DefineConfigHValue(PACKAGE_URL \\"http://www.gnu.org/software/gawk/\\")
+DefineConfigHValue(PACKAGE_VERSION \\"${GAWK_VERSION}\\")
+DefineConfigHValue(DEFPATH \\"${CMAKE_BINARY_DIR}/awk\\")
+DefineConfigHValue(DEFLIBPATH \\"${CMAKE_BINARY_DIR}/lib\\")
+if (CMAKE_DL_LIBS)
+ message(STATUS "Found CMAKE_DL_LIBS:${CMAKE_DL_LIBS}")
+else()
+ message(STATUS "Found no CMAKE_DL_LIBS")
+endif()
+if (CMAKE_SHARED_LIBRARY_SUFFIX)
+ DefineConfigHValue(DYNAMIC 1)
+ STRING( REGEX REPLACE "^(\\.)([a-zA-Z0-9])" "\\2" SHLIBEXT "${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ DefineConfigHValue(SHLIBEXT \\"${SHLIBEXT}\\")
+ message(STATUS "Found SHLIBEXT: ${SHLIBEXT}")
+else()
+ message(STATUS "Found no SHLIBEXT")
+endif()
+DefineTypeIfAvailable("unsigned int" SIZEOF_UNSIGNED_INT)
+DefineTypeIfAvailable("unsigned long" SIZEOF_UNSIGNED_LONG)
+#/* Define to 1 if *printf supports %F format */
+add_definitions(-D PRINTF_HAS_F_FORMAT)
+#/* Define as the return type of signal handlers (`int' or `void'). */
+add_definitions(-D RETSIGTYPE=void)
+#add_definitions(-D PIPES_SIMULATED)
+check_prototype_definition(getpgrp "pid_t getpgrp(void)" "NULL" "unistd.h" GETPGRP_VOID)
+DefineConfigH(GETPGRP_VOID)
+#add_definitions(-D YYPARSE_PARAM)
+
+DefineFunctionIfAvailable(snprintf HAVE_SNPRINTF)
+DefineFunctionIfAvailable(vprintf HAVE_VPRINTF)
+DefineHFileIfAvailable(sys/types.h HAVE_SYS_TYPES_H)
+DefineHFileIfAvailable(sys/stat.h HAVE_SYS_STAT_H)
+DefineHFileIfAvailable(string.h HAVE_STRING_H)
+DefineHFileIfAvailable(memory.h HAVE_MEMORY_H)
+DefineHFileIfAvailable(strings.h HAVE_STRINGS_H)
+DefineHFileIfAvailable(stdint.h HAVE_STDINT_H)
+DefineHFileIfAvailable(inttypes.h HAVE_INTTYPES_H)
+DefineHFileIfAvailable(stdlib.h HAVE_STDLIB_H)
+DefineHFileIfAvailable(unistd.h HAVE_UNISTD_H)
+FIND_PATH(INTL_INCLUDE_DIR libintl.h PATHS /usr/include /usr/local/include)
+FIND_LIBRARY(INTL_LIBRARIES intl c PATHS /usr/lib/ /usr/local/lib)
+DefineSymbolIfAvailable("CODESET" "langinfo.h" HAVE_LANGINFO_CODESET)
+DefineSymbolIfAvailable("LC_MESSAGES" "locale.h" HAVE_LC_MESSAGES)
+DefineTypeIfAvailable("_Bool" HAVE__BOOL)
+if (${HAVE_GETTEXT} AND ${HAVE_DCGETTEXT} AND ${HAVE_LANGINFO_CODESET} AND ${HAVE_LC_MESSAGES})
+ add_definitions(-D LOCALEDIR=\\"/usr/share/locale\\")
+ add_definitions(-D ENABLE_NLS)
+ ADD_SUBDIRECTORY( ${CMAKE_SOURCE_DIR}/po )
+endif()
+DefineHFileIfAvailable(stdbool.h HAVE_STDBOOL_H)
+DefineHFileIfAvailable(sys/wait.h HAVE_SYS_WAIT_H)
+DefineHFileIfAvailable(arpa/inet.h HAVE_ARPA_INET_H)
+DefineHFileIfAvailable(fcntl.h HAVE_FCNTL_H)
+DefineHFileIfAvailable(limits.h HAVE_LIMITS_H)
+DefineHFileIfAvailable(locale.h HAVE_LOCALE_H)
+DefineHFileIfAvailable(libintl.h HAVE_LIBINTL_H)
+DefineHFileIfAvailable(mcheck.h HAVE_MCHECK_H)
+DefineHFileIfAvailable(netdb.h HAVE_NETDB_H)
+DefineHFileIfAvailable(netinet/in.h HAVE_NETINET_IN_H)
+DefineHFileIfAvailable(stdarg.h HAVE_STDARG_H)
+DefineHFileIfAvailable(stddef.h HAVE_STDDEF_H)
+DefineHFileIfAvailable(sys/ioctl.h HAVE_SYS_IOCTL_H)
+DefineHFileIfAvailable(sys/param.h HAVE_SYS_PARAM_H)
+DefineHFileIfAvailable(sys/socket.h HAVE_SYS_SOCKET_H)
+DefineHFileIfAvailable(sys/termios.h HAVE_TERMIOS_H)
+DefineHFileIfAvailable(stropts.h HAVE_STROPTS_H)
+DefineHFileIfAvailable(wchar.h HAVE_WCHAR_H)
+DefineHFileIfAvailable(wctype.h HAVE_WCTYPE_H)
+DefineTypeIfAvailable("long long int" HAVE_LONG_LONG_INT)
+DefineTypeIfAvailable("unsigned long long int" HAVE_UNSIGNED_LONG_LONG_INT)
+DefineTypeIfAvailable(intmax_t INTMAX_T)
+DefineTypeIfAvailable(uintmax_t UINTMAX_T)
+DefineTypeIfAvailable("time_t" TIME_T_IN_SYS_TYPES_H)
+SET(CMAKE_EXTRA_INCLUDE_FILES wctype.h)
+DefineTypeIfAvailable("wctype_t" HAVE_WCTYPE_T)
+DefineTypeIfAvailable("wint_t" HAVE_WINT_T)
+SET(CMAKE_EXTRA_INCLUDE_FILES)
+
+DefineStructHasMemberIfAvailable("struct sockaddr_storage" ss_family sys/socket.h HAVE_SOCKADDR_STORAGE)
+DefineStructHasMemberIfAvailable("struct stat" st_blksize sys/stat.h HAVE_STRUCT_STAT_ST_BLKSIZE)
+DefineStructHasMemberIfAvailable("struct stat" st_blksize sys/stat.h HAVE_ST_BLKSIZE)
+DefineStructHasMemberIfAvailable("struct tm" tm_zone time.h HAVE_TM_ZONE)
+DefineStructHasMemberIfAvailable("struct tm" tm_zone time.h HAVE_STRUCT_TM_TM_ZONE)
+
+DefineHFileIfAvailable(sys/time.h HAVE_SYS_TIME_H)
+DefineFunctionIfAvailable(alarm HAVE_ALARM)
+DefineFunctionIfAvailable(tzname HAVE_DECL_TZNAME)
+DefineFunctionIfAvailable(mktime HAVE_MKTIME)
+DefineFunctionIfAvailable(getaddrinfo HAVE_GETADDRINFO)
+DefineFunctionIfAvailable(atexit HAVE_ATEXIT)
+DefineFunctionIfAvailable(btowc HAVE_BTOWC)
+DefineFunctionIfAvailable(fmod HAVE_FMOD)
+DefineFunctionIfAvailable(isinf HAVE_ISINF)
+DefineFunctionIfAvailable(ismod HAVE_ISMOD)
+DefineFunctionIfAvailable(getgrent HAVE_GETGRENT)
+DefineSymbolIfAvailable("getgroups" "unistd.h" HAVE_GETGROUPS)
+if (${HAVE_GETGROUPS})
+ check_prototype_definition(getgroups "int getgroups(int size, gid_t list[])" "NULL" "unistd.h" GETGROUPS_T)
+ if (${GETGROUPS_T})
+ DefineConfigHValue(GETGROUPS_T gid_t)
+ else()
+ DefineConfigHValue(GETGROUPS_T int)
+ endif()
+endif()
+
+DefineTypeIfAvailable("pid_t" PID_T)
+DefineTypeIfAvailable("intmax_t" HAVE_INTMAX_T)
+DefineFunctionIfAvailable(grantpt HAVE_GRANTPT)
+DefineFunctionIfAvailable(isascii HAVE_ISASCII)
+DefineFunctionIfAvailable(iswctype HAVE_ISWCTYPE)
+DefineFunctionIfAvailable(iswlower HAVE_ISWLOWER)
+DefineFunctionIfAvailable(iswupper HAVE_ISWUPPER)
+DefineFunctionIfAvailable(mbrlen HAVE_MBRLEN)
+DefineFunctionIfAvailable(memcmp HAVE_MEMCMP)
+DefineFunctionIfAvailable(memcpy HAVE_MEMCPY)
+DefineFunctionIfAvailable(memmove HAVE_MEMMOVE)
+DefineFunctionIfAvailable(memset HAVE_MEMSET)
+DefineFunctionIfAvailable(mkstemp HAVE_MKSTEMP)
+DefineFunctionIfAvailable(posix_openpt HAVE_POSIX_OPENPT)
+DefineFunctionIfAvailable(setenv HAVE_SETENV)
+DefineFunctionIfAvailable(setlocale HAVE_SETLOCALE)
+DefineFunctionIfAvailable(setsid HAVE_SETSID)
+DefineFunctionIfAvailable(strchr HAVE_STRCHR)
+DefineFunctionIfAvailable(strerror HAVE_STRERROR)
+DefineFunctionIfAvailable(strftime HAVE_STRFTIME)
+DefineFunctionIfAvailable(strncasecmp HAVE_STRNCASECMP)
+DefineFunctionIfAvailable(strcoll HAVE_STRCOLL)
+DefineFunctionIfAvailable(strtod HAVE_STRTOD)
+DefineFunctionIfAvailable(strtoul HAVE_STRTOUL)
+DefineFunctionIfAvailable(system HAVE_SYSTEM)
+DefineFunctionIfAvailable(tmpfile HAVE_TMPFILE)
+DefineFunctionIfAvailable(towlower HAVE_TOWLOWER)
+DefineFunctionIfAvailable(towupper HAVE_TOWUPPER)
+DefineFunctionIfAvailable(tzset HAVE_TZSET)
+DefineFunctionIfAvailable(usleep HAVE_USLEEP)
+DefineFunctionIfAvailable(wcrtomb HAVE_WCRTOMB)
+DefineFunctionIfAvailable(wcscoll HAVE_WCSCOLL)
+DefineFunctionIfAvailable(wctype HAVE_WCTYPE)
+DefineFunctionIfAvailable(mbrtowc HAVE_MBRTOWC)
+
+add_definitions(-D HAVE_STRINGIZE)
+add_definitions(-D _Noreturn=)
+
+find_package(BISON QUIET)
+# If there is a bison installed on this platform,
+if (${BISON_FOUND} STREQUAL "TRUE")
+ # then let bison generate awkgram.c.
+ BISON_TARGET(awkgram awkgram.y ${CMAKE_SOURCE_DIR}/awkgram.c)
+else()
+ # otherwise use the existing awkgram.c.
+ set(BISON_awkgram_OUTPUTS ${CMAKE_SOURCE_DIR}/awkgram.c)
+endif()
+
+find_package(Gettext REQUIRED)
+if (GETTEXT_FOUND STREQUAL "TRUE")
+ include_directories(${GETTEXT_INCLUDE_DIR})
+ DefineFunctionIfAvailable(gettext HAVE_GETTEXT)
+ DefineFunctionIfAvailable(dcgettext HAVE_DCGETTEXT)
+else ()
+ message( FATAL_ERROR "Gettext not found" )
+endif()
+
+find_package(LATEX)
+include(GNUInstallDirs)
+include(GetPrerequisites)
+
+# For some unknown reason the defines for the extensions
+# are written into config.h only if they are implemented
+# here and not in extension/CMakeLists.txt.
+DefineLibraryIfAvailable(m sin "" HAVE_LIBM)
+DefineLibraryIfAvailable(mpfr mpfr_add_si "" HAVE_MPFR)
+DefineLibraryIfAvailable(c socket "" HAVE_SOCKETS)
+DefineLibraryIfAvailable(readline readline "" HAVE_LIBREADLINE)
+DefineFunctionIfAvailable(fnmatch HAVE_FNMATCH)
+DefineHFileIfAvailable(fnmatch.h HAVE_FNMATCH_H)
+DefineHFileIfAvailable(dirent.h HAVE_DIRENT_H)
+DefineFunctionIfAvailable(dirfd HAVE_DIRFD)
+DefineFunctionIfAvailable(getdtablesize HAVE_GETDTABLESIZE)
+DefineFunctionIfAvailable(select HAVE_SELECT)
+DefineFunctionIfAvailable(gettimeofday HAVE_GETTIMEOFDAY)
+DefineHFileIfAvailable(sys/select.h HAVE_SYS_SELECT_H)
+DefineFunctionIfAvailable(nanosleep HAVE_NANOSLEEP)
+DefineHFileIfAvailable(time.h HAVE_TIME_H)
+DefineFunctionIfAvailable(GetSystemTimeAsFileTime HAVE_GETSYSTEMTIMEASFILETIME)
+
diff --git a/cmake/docmaker b/cmake/docmaker
new file mode 100755
index 00000000..4af7cee1
--- /dev/null
+++ b/cmake/docmaker
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+# The first parameter is the target, the file to be built.
+# All remaining parameters are dependencies (file names).
+if [ $# -lt 1 ] ; then
+ echo " $0: Incorrect number ($#) of parameters passed: $*"
+ exit 1
+fi
+OUTFILE=$1
+shift 1
+INFILES="$@"
+
+MAKEINFO="makeinfo --no-split --force"
+TROFF="groff -t -Tps -U"
+SEDME="sed -e \"s/^level0 restore/level0 restore flashme 100 72 moveto (Copyright `date '+%m-%d-%y %T'`, FSF, Inc. (all)) show/\" -e \"s/^\/level0 save def/\/level0 save def 30 -48 translate/\""
+SEDME2="sed '/%%Page: 10 10/,/0 Cg EP/d'"
+
+function BuildTarget()
+{
+ local OUTFILE=$1
+ local INFILE=""
+ local COMMAND=""
+
+ FILEBASE=${OUTFILE%.*}
+ case $OUTFILE in
+ *\.in | *\.1 | macros | cardfonts | colors | ad.block | setter.outline | \
+ gawkinet.texi | rflashlight.eps | api-figure1.fig | api-figure2.fig | api-figure3.fig | \
+ general-program.fig | process-flow.fig | statist.eps)
+ INFILE=$OUTFILE
+ ;;
+ *\.texi)
+ if [ $FILEBASE = gawk ] ; then
+ INFILE=gawktexi.in
+ else
+ INFILE=$OUTFILE.in
+ fi
+ COMMAND="awk -f sidebar.awk < $INFILE > $OUTFILE"
+ ;;
+ *\.dvi)
+ INFILE=$FILEBASE.texi
+ COMMAND="texi2dvi -q --clean $INFILE"
+ ;;
+ *\.info)
+ INFILE=$FILEBASE.texi
+ COMMAND="${MAKEINFO} $INFILE"
+ ;;
+ *\.ps)
+ if [ $FILEBASE = awkcard ] ; then
+ INFILE=awkcard.in
+ COMMAND="${TROFF} $* | ${SEDME} | cat setter.outline - | ${SEDME2} > awkcard.ps"
+ elif [ $FILEBASE = gawk.1 -o $FILEBASE = igawk.1 ] ; then
+ INFILE=$FILEBASE
+ COMMAND="groff -z -man $INFILE > $OUTFILE"
+ else
+ INFILE=$FILEBASE.dvi
+ COMMAND="dvips -q -o $OUTFILE $INFILE"
+ fi
+ ;;
+ *\.pdf)
+ INFILE=$FILEBASE.ps
+ COMMAND="ps2pdf -q $INFILE $OUTFILE"
+ ;;
+ *\.tr)
+ INFILE=$FILEBASE.in
+ COMMAND="sed 's:SRCDIR:.:' < $INFILE > $OUTFILE"
+ ;;
+ *\.nc)
+ INFILE=$FILEBASE.in
+ COMMAND="sed 's:SRCDIR:.:' < $INFILE > $OUTFILE"
+ COMMAND="${TROFF} $* | ${SEDME} | cat setter.outline - | ${SEDME2} > $FILEBASE.ps && touch $OUTFILE"
+ ;;
+ *)
+ echo " unknwon target $OUTFILE"
+ exit 1
+ esac
+
+ if [ ! -r "$INFILE" ] ; then
+ echo " $0: Cannot read input file $INFILE"
+ exit 1
+ fi
+
+ if [ -f "$OUTFILE" ] ; then
+ if [ "$INFILE" -ot "$OUTFILE" ] ; then
+ #printf " Target %15s is up-to-date\n" $OUTFILE
+ COMMAND=""
+ fi
+ fi
+ #echo " Generating $OUTFILE from $INFILE"
+ echo $COMMAND | sh -x
+ #echo "COMMAND=$COMMAND"
+}
+
+# Build all dependencies first, then build the target.
+for dep in $INFILES
+do
+ #echo $OUTFILE depends on $dep
+ BuildTarget $dep
+done
+BuildTarget $OUTFILE
+
diff --git a/cmake/package.cmake b/cmake/package.cmake
new file mode 100644
index 00000000..f1127797
--- /dev/null
+++ b/cmake/package.cmake
@@ -0,0 +1,71 @@
+#
+# cmake/package --- CMake input file for gawk
+#
+# Copyright (C) 2013-2014
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with CMake to produce Makefile
+
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "This is GNU Awk ${GAWK_VERSION}")
+set(CPACK_PACKAGE_VENDOR "GNU Project - Free Software Foundation (FSF)")
+SET(CPACK_PACKAGE_NAME "gawk")
+SET(CPACK_PACKAGE_VERSION "${GAWK_VERSION}")
+SET(CPACK_PACKAGE_VERSION_MAJOR "${GAWK_MAJOR_VERSION}")
+SET(CPACK_PACKAGE_VERSION_MINOR "${GAWK_MINOR_VERSION}")
+SET(CPACK_PACKAGE_VERSION_PATCH "${GAWK_BUGFIX_VERSION}")
+SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
+SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README")
+set(CPACK_PACKAGE_CONTACT "bug-gawk@gnu.org")
+
+IF (WIN32)
+ SET(CPACK_GENERATOR "NSIS")
+ set(CPACK_NSIS_INSTALL_ROOT "C:")
+ set(CPACK_NSIS_MENU_LINKS "http://www.gnu.org/software/gawk" "GNU Awk")
+ set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/cmake/auk.ico")
+ set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/cmake/auk.ico")
+ set(CPACK_NSIS_MODIFY_PATH true)
+ set(CPACK_NSIS_CONTACT "bug-gawk@gnu.org")
+ set(CPACK_NSIS_DISPLAY_NAME "GNU Awk")
+ include(CPack)
+ELSE()
+ set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}_${CMAKE_SYSTEM_PROCESSOR}")
+ set(CPACK_PACKAGING_INSTALL_PREFIX /usr)
+ if (CPACK_GENERATOR STREQUAL "TGZ")
+ include(CPack)
+ elseif (CPACK_GENERATOR STREQUAL "RPM")
+ include(CPack)
+ elseif (CPACK_GENERATOR STREQUAL "DEB")
+ set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR} <${CPACK_PACKAGE_CONTACT}>")
+ set(CPACK_DEBIAN_PACKAGE_SECTION "interpreters")
+ set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
+ set(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
+ set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://www.gnu.org/software/gawk")
+ set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+ set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libgcc1 (>= 1:3.4.2-12)")
+ include(CPack)
+ else()
+ # No package format selected. Don't create the "package" target.
+ endif()
+ if (CPACK_GENERATOR)
+ message(STATUS "CPACK_GENERATOR set to ${CPACK_GENERATOR}")
+ endif()
+ENDIF()
+
diff --git a/cmd.h b/cmd.h
index f663586c..c87d9640 100644
--- a/cmd.h
+++ b/cmd.h
@@ -2,22 +2,22 @@
* cmd.h - definitions for command parser
*/
-/*
+/*
* Copyright (C) 2004, 2010, 2011, 2013, 2014 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -106,7 +106,7 @@ enum argtype {
D_range
};
-/* non-number arguments to commands */
+/* non-number arguments to commands */
enum nametypeval {
A_NONE = 0,
@@ -135,7 +135,7 @@ typedef struct cmd_argument {
NODE *nodeval;
} value;
-#define a_int value.lval /* type = D_int or D_range */
+#define a_int value.lval /* type = D_int or D_range */
#define a_argument value.lval /* type = D_argument */
#define a_string value.sval /* type = D_string, D_array, D_subscript or D_variable */
#define a_node value.nodeval /* type = D_node, D_field or D_func */
diff --git a/command.c b/command.c
index 95f28f31..1d804c75 100644
--- a/command.c
+++ b/command.c
@@ -89,7 +89,7 @@ static bool want_nodeval = false;
static int cmd_idx = -1; /* index of current command in cmd table */
static int repeat_idx = -1; /* index of last repeatable command in command table */
-static CMDARG *arg_list = NULL; /* list of arguments */
+static CMDARG *arg_list = NULL; /* list of arguments */
static long errcount = 0;
static char *lexptr_begin = NULL;
static bool in_commands = false;
@@ -97,7 +97,7 @@ static int num_dim;
static bool in_eval = false;
static const char start_EVAL[] = "function @eval(){";
-static const char end_EVAL[] = "}";
+static const char end_EVAL[] = "}";
static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
static NODE *concat_args(CMDARG *a, int count);
@@ -1553,7 +1553,7 @@ yyreduce:
bool terminate = false;
CMDARG *args;
int ctype = 0;
-
+
ctype = cmdtab[cmd_idx].type;
/* a blank line repeats previous command
@@ -1794,7 +1794,7 @@ yyreduce:
if (type) {
in_commands = true;
if (input_from_tty) {
- dbg_prompt = commands_prompt;
+ dbg_prompt = commands_prompt;
fprintf(out_fp, _("Type commands for when %s %d is hit, one per line.\n"),
(type == D_break) ? "breakpoint" : "watchpoint", num);
fprintf(out_fp, _("End with the command \"end\"\n"));
@@ -1811,7 +1811,7 @@ yyreduce:
yyerror(_("`end' valid only in command `commands' or `eval'"));
else {
if (input_from_tty)
- dbg_prompt = dgawk_prompt;
+ dbg_prompt = dgawk_prompt;
in_commands = false;
}
}
@@ -2108,7 +2108,7 @@ yyreduce:
CMDARG *a;
NODE *subs;
int count = 0;
-
+
for (a = (yyvsp[-1]); a != NULL; a = a->next)
count++;
subs = concat_args((yyvsp[-1]), count);
@@ -2165,7 +2165,7 @@ yyreduce:
case 145:
#line 678 "command.y" /* yacc.c:1646 */
- {
+ {
NODE *n = (yyvsp[0])->a_node;
if ((n->flags & NUMBER) == 0)
yyerror(_("non-numeric value found, numeric expected"));
@@ -2176,7 +2176,7 @@ yyreduce:
case 146:
#line 685 "command.y" /* yacc.c:1646 */
- {
+ {
NODE *n = (yyvsp[0])->a_node;
if ((n->flags & NUMBER) == 0)
yyerror(_("non-numeric value found, numeric expected"));
@@ -2498,12 +2498,12 @@ yyreturn:
-/* append_statement --- append 'stmt' to the list of eval awk statements */
+/* append_statement --- append 'stmt' to the list of eval awk statements */
static CMDARG *
-append_statement(CMDARG *stmt_list, char *stmt)
+append_statement(CMDARG *stmt_list, char *stmt)
{
- CMDARG *a, *arg;
+ CMDARG *a, *arg;
char *s;
int len, slen, ssize;
@@ -2515,7 +2515,7 @@ append_statement(CMDARG *stmt_list, char *stmt)
len += strlen(a->a_string) + 1; /* 1 for ',' */
len += EVALSIZE;
- emalloc(s, char *, (len + 2) * sizeof(char), "append_statement");
+ emalloc(s, char *, (len + 1) * sizeof(char), "append_statement");
arg = mk_cmdarg(D_string);
arg->a_string = s;
arg->a_count = len; /* kludge */
@@ -2535,14 +2535,14 @@ append_statement(CMDARG *stmt_list, char *stmt)
s[slen] = '\0';
return arg;
}
-
+
len = strlen(stmt) + 1; /* 1 for newline */
s = stmt_list->a_string;
slen = strlen(s);
ssize = stmt_list->a_count;
if (len > ssize - slen) {
ssize = slen + len + EVALSIZE;
- erealloc(s, char *, (ssize + 2) * sizeof(char), "append_statement");
+ erealloc(s, char *, (ssize + 1) * sizeof(char), "append_statement");
stmt_list->a_string = s;
stmt_list->a_count = ssize;
}
@@ -2554,7 +2554,7 @@ append_statement(CMDARG *stmt_list, char *stmt)
}
if (stmt == end_EVAL)
- erealloc(stmt_list->a_string, char *, slen + 2, "append_statement");
+ erealloc(stmt_list->a_string, char *, slen + 1, "append_statement");
return stmt_list;
#undef EVALSIZE
@@ -2699,7 +2699,7 @@ get_command_name(int ctype)
return cmdtab[i].name;
}
return NULL;
-}
+}
/* mk_cmdarg --- make an argument for command */
@@ -2707,14 +2707,13 @@ static CMDARG *
mk_cmdarg(enum argtype type)
{
CMDARG *arg;
- emalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
- memset(arg, 0, sizeof(CMDARG));
+ ezalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
arg->type = type;
return arg;
}
/* append_cmdarg --- append ARG to the list of arguments for the current command */
-
+
static void
append_cmdarg(CMDARG *arg)
{
@@ -2785,7 +2784,7 @@ yylex(void)
static char *lexend;
int c;
char *tokstart;
- size_t toklen;
+ size_t toklen;
yylval = (CMDARG *) NULL;
@@ -2799,7 +2798,7 @@ yylex(void)
again:
lexptr_begin = read_a_line(dbg_prompt);
if (lexptr_begin == NULL) { /* EOF or error */
- if (get_eof_status() == EXIT_FATAL)
+ if (get_eof_status() == EXIT_FATAL)
exit(EXIT_FATAL);
if (get_eof_status() == EXIT_FAILURE) {
static int seen_eof = 0;
@@ -2831,7 +2830,7 @@ again:
&& input_from_tty
)
history_expand_line(&lexptr_begin);
-
+
lexptr = lexptr_begin;
lexend = lexptr + strlen(lexptr);
if (*lexptr == '\0' /* blank line */
@@ -2850,14 +2849,14 @@ again:
}
repeat_idx = -1;
}
-
+
c = *lexptr;
while (c == ' ' || c == '\t')
c = *++lexptr;
if (! input_from_tty && c == '#')
- return '\n';
+ return '\n';
tokstart = lexptr;
if (lexptr >= lexend)
@@ -2914,7 +2913,7 @@ again:
}
c = *lexptr;
-
+
if (cmdtab[cmd_idx].type == D_option) {
if (c == '=')
return *lexptr++;
@@ -2927,7 +2926,7 @@ again:
bool esc_seen = false;
toklen = lexend - lexptr;
- emalloc(str, char *, toklen + 2, "yylex");
+ emalloc(str, char *, toklen + 1, "yylex");
p = str;
while ((c = *++lexptr) != '"') {
@@ -3016,8 +3015,8 @@ err:
r = mpg_integer();
mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
unref(tmp);
- }
- } else
+ }
+ } else
#endif
r = make_number(strtod(tokstart, & lexptr));
@@ -3126,7 +3125,7 @@ concat_args(CMDARG *arg, int count)
n = force_string(arg->a_node);
return dupnode(n);
}
-
+
emalloc(tmp, NODE **, count * sizeof(NODE *), "concat_args");
subseplen = SUBSEP_node->var_value->stlen;
subsep = SUBSEP_node->var_value->stptr;
@@ -3139,7 +3138,7 @@ concat_args(CMDARG *arg, int count)
arg = arg->next;
}
- emalloc(str, char *, len + 2, "concat_args");
+ emalloc(str, char *, len + 1, "concat_args");
n = tmp[0];
memcpy(str, n->stptr, n->stlen);
p = str + n->stlen;
@@ -3161,7 +3160,7 @@ concat_args(CMDARG *arg, int count)
}
/* find_command --- find the index in 'cmdtab' using exact,
- * abbreviation or unique partial match
+ * abbreviation or unique partial match
*/
static int
@@ -3253,10 +3252,10 @@ do_help(CMDARG *arg, int cmd)
#ifdef HAVE_LIBREADLINE
-/* next_word --- find the next word in a line to complete
+/* next_word --- find the next word in a line to complete
* (word seperation characters are space and tab).
*/
-
+
static char *
next_word(char *p, int len, char **endp)
{
@@ -3338,10 +3337,10 @@ command_completion(const char *text, int start, int end)
if (this_cmd == D_print || this_cmd == D_printf)
return rl_completion_matches(text, variable_generator);
return NULL;
-}
+}
/* command_generator --- generator function for command completion */
-
+
static char *
command_generator(const char *text, int state)
{
@@ -3414,7 +3413,7 @@ argument_generator(const char *text, int state)
if (strncmp(name, text, textlen) == 0)
return estrdup(name, strlen(name));
}
- }
+ }
return NULL;
}
diff --git a/command.y b/command.y
index d0507034..65d21853 100644
--- a/command.y
+++ b/command.y
@@ -2,23 +2,23 @@
* command.y - yacc/bison parser for debugger commands.
*/
-/*
+/*
* Copyright (C) 2004, 2010, 2011, 2014, 2016
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
@@ -42,7 +42,7 @@ static bool want_nodeval = false;
static int cmd_idx = -1; /* index of current command in cmd table */
static int repeat_idx = -1; /* index of last repeatable command in command table */
-static CMDARG *arg_list = NULL; /* list of arguments */
+static CMDARG *arg_list = NULL; /* list of arguments */
static long errcount = 0;
static char *lexptr_begin = NULL;
static bool in_commands = false;
@@ -50,7 +50,7 @@ static int num_dim;
static bool in_eval = false;
static const char start_EVAL[] = "function @eval(){";
-static const char end_EVAL[] = "}";
+static const char end_EVAL[] = "}";
static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
static NODE *concat_args(CMDARG *a, int count);
@@ -132,7 +132,7 @@ line
bool terminate = false;
CMDARG *args;
int ctype = 0;
-
+
ctype = cmdtab[cmd_idx].type;
/* a blank line repeats previous command
@@ -308,7 +308,7 @@ command
| D_LIST list_args
| D_UNTIL location
| D_CLEAR location
- | break_cmd break_args
+ | break_cmd break_args
| D_SET { want_nodeval = true; } variable '=' node
| D_OPTION option_args
| D_RETURN { want_nodeval = true; } opt_node
@@ -345,7 +345,7 @@ command
if (type) {
in_commands = true;
if (input_from_tty) {
- dbg_prompt = commands_prompt;
+ dbg_prompt = commands_prompt;
fprintf(out_fp, _("Type commands for when %s %d is hit, one per line.\n"),
(type == D_break) ? "breakpoint" : "watchpoint", num);
fprintf(out_fp, _("End with the command \"end\"\n"));
@@ -358,7 +358,7 @@ command
yyerror(_("`end' valid only in command `commands' or `eval'"));
else {
if (input_from_tty)
- dbg_prompt = dgawk_prompt;
+ dbg_prompt = dgawk_prompt;
in_commands = false;
}
}
@@ -493,9 +493,9 @@ location
break_args
: /* empty */
- { $$ = NULL; }
+ { $$ = NULL; }
| plus_integer { want_nodeval = true; } condition_exp
- | func_name
+ | func_name
| D_STRING ':' plus_integer { want_nodeval = true; } condition_exp
| D_STRING ':' func_name
;
@@ -631,7 +631,7 @@ subscript
CMDARG *a;
NODE *subs;
int count = 0;
-
+
for (a = $2; a != NULL; a = a->next)
count++;
subs = concat_args($2, count);
@@ -641,7 +641,7 @@ subscript
$2->a_node = subs;
$$ = $2;
}
- | '[' exp_list error
+ | '[' exp_list error
;
subscript_list
@@ -675,14 +675,14 @@ node
: D_NODE
{ $$ = $1; }
| '+' D_NODE
- {
+ {
NODE *n = $2->a_node;
if ((n->flags & NUMBER) == 0)
yyerror(_("non-numeric value found, numeric expected"));
$$ = $2;
}
| '-' D_NODE
- {
+ {
NODE *n = $2->a_node;
if ((n->flags & NUMBER) == 0)
yyerror(_("non-numeric value found, numeric expected"));
@@ -705,7 +705,7 @@ opt_integer
| integer
{ $$ = $1; }
;
-
+
plus_integer
: D_INT
{
@@ -720,7 +720,7 @@ plus_integer
$$ = $2;
}
;
-
+
integer
: D_INT
{ $$ = $1; }
@@ -748,12 +748,12 @@ nls
%%
-/* append_statement --- append 'stmt' to the list of eval awk statements */
+/* append_statement --- append 'stmt' to the list of eval awk statements */
static CMDARG *
-append_statement(CMDARG *stmt_list, char *stmt)
+append_statement(CMDARG *stmt_list, char *stmt)
{
- CMDARG *a, *arg;
+ CMDARG *a, *arg;
char *s;
int len, slen, ssize;
@@ -765,7 +765,7 @@ append_statement(CMDARG *stmt_list, char *stmt)
len += strlen(a->a_string) + 1; /* 1 for ',' */
len += EVALSIZE;
- emalloc(s, char *, (len + 2) * sizeof(char), "append_statement");
+ emalloc(s, char *, (len + 1) * sizeof(char), "append_statement");
arg = mk_cmdarg(D_string);
arg->a_string = s;
arg->a_count = len; /* kludge */
@@ -785,14 +785,14 @@ append_statement(CMDARG *stmt_list, char *stmt)
s[slen] = '\0';
return arg;
}
-
+
len = strlen(stmt) + 1; /* 1 for newline */
s = stmt_list->a_string;
slen = strlen(s);
ssize = stmt_list->a_count;
if (len > ssize - slen) {
ssize = slen + len + EVALSIZE;
- erealloc(s, char *, (ssize + 2) * sizeof(char), "append_statement");
+ erealloc(s, char *, (ssize + 1) * sizeof(char), "append_statement");
stmt_list->a_string = s;
stmt_list->a_count = ssize;
}
@@ -804,7 +804,7 @@ append_statement(CMDARG *stmt_list, char *stmt)
}
if (stmt == end_EVAL)
- erealloc(stmt_list->a_string, char *, slen + 2, "append_statement");
+ erealloc(stmt_list->a_string, char *, slen + 1, "append_statement");
return stmt_list;
#undef EVALSIZE
@@ -949,7 +949,7 @@ get_command_name(int ctype)
return cmdtab[i].name;
}
return NULL;
-}
+}
/* mk_cmdarg --- make an argument for command */
@@ -957,14 +957,13 @@ static CMDARG *
mk_cmdarg(enum argtype type)
{
CMDARG *arg;
- emalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
- memset(arg, 0, sizeof(CMDARG));
+ ezalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
arg->type = type;
return arg;
}
/* append_cmdarg --- append ARG to the list of arguments for the current command */
-
+
static void
append_cmdarg(CMDARG *arg)
{
@@ -1035,7 +1034,7 @@ yylex(void)
static char *lexend;
int c;
char *tokstart;
- size_t toklen;
+ size_t toklen;
yylval = (CMDARG *) NULL;
@@ -1049,7 +1048,7 @@ yylex(void)
again:
lexptr_begin = read_a_line(dbg_prompt);
if (lexptr_begin == NULL) { /* EOF or error */
- if (get_eof_status() == EXIT_FATAL)
+ if (get_eof_status() == EXIT_FATAL)
exit(EXIT_FATAL);
if (get_eof_status() == EXIT_FAILURE) {
static int seen_eof = 0;
@@ -1081,7 +1080,7 @@ again:
&& input_from_tty
)
history_expand_line(&lexptr_begin);
-
+
lexptr = lexptr_begin;
lexend = lexptr + strlen(lexptr);
if (*lexptr == '\0' /* blank line */
@@ -1100,14 +1099,14 @@ again:
}
repeat_idx = -1;
}
-
+
c = *lexptr;
while (c == ' ' || c == '\t')
c = *++lexptr;
if (! input_from_tty && c == '#')
- return '\n';
+ return '\n';
tokstart = lexptr;
if (lexptr >= lexend)
@@ -1164,7 +1163,7 @@ again:
}
c = *lexptr;
-
+
if (cmdtab[cmd_idx].type == D_option) {
if (c == '=')
return *lexptr++;
@@ -1177,7 +1176,7 @@ again:
bool esc_seen = false;
toklen = lexend - lexptr;
- emalloc(str, char *, toklen + 2, "yylex");
+ emalloc(str, char *, toklen + 1, "yylex");
p = str;
while ((c = *++lexptr) != '"') {
@@ -1266,8 +1265,8 @@ err:
r = mpg_integer();
mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
unref(tmp);
- }
- } else
+ }
+ } else
#endif
r = make_number(strtod(tokstart, & lexptr));
@@ -1376,7 +1375,7 @@ concat_args(CMDARG *arg, int count)
n = force_string(arg->a_node);
return dupnode(n);
}
-
+
emalloc(tmp, NODE **, count * sizeof(NODE *), "concat_args");
subseplen = SUBSEP_node->var_value->stlen;
subsep = SUBSEP_node->var_value->stptr;
@@ -1389,7 +1388,7 @@ concat_args(CMDARG *arg, int count)
arg = arg->next;
}
- emalloc(str, char *, len + 2, "concat_args");
+ emalloc(str, char *, len + 1, "concat_args");
n = tmp[0];
memcpy(str, n->stptr, n->stlen);
p = str + n->stlen;
@@ -1411,7 +1410,7 @@ concat_args(CMDARG *arg, int count)
}
/* find_command --- find the index in 'cmdtab' using exact,
- * abbreviation or unique partial match
+ * abbreviation or unique partial match
*/
static int
@@ -1503,10 +1502,10 @@ do_help(CMDARG *arg, int cmd)
#ifdef HAVE_LIBREADLINE
-/* next_word --- find the next word in a line to complete
+/* next_word --- find the next word in a line to complete
* (word seperation characters are space and tab).
*/
-
+
static char *
next_word(char *p, int len, char **endp)
{
@@ -1588,10 +1587,10 @@ command_completion(const char *text, int start, int end)
if (this_cmd == D_print || this_cmd == D_printf)
return rl_completion_matches(text, variable_generator);
return NULL;
-}
+}
/* command_generator --- generator function for command completion */
-
+
static char *
command_generator(const char *text, int state)
{
@@ -1664,7 +1663,7 @@ argument_generator(const char *text, int state)
if (strncmp(name, text, textlen) == 0)
return estrdup(name, strlen(name));
}
- }
+ }
return NULL;
}
diff --git a/compile b/compile
index a85b723c..2ab71e4e 100755
--- a/compile
+++ b/compile
@@ -1,9 +1,9 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
-scriptversion=2012-10-14.11; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
@@ -255,7 +255,8 @@ EOF
echo "compile $scriptversion"
exit $?
;;
- cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
@@ -342,6 +343,6 @@ exit $ret
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/config.guess b/config.guess
index c4bd827a..2193702b 100755
--- a/config.guess
+++ b/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2016-05-15'
+timestamp='2017-05-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright 1992-2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -837,10 +837,11 @@ EOF
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
esac
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -1000,6 +1001,9 @@ EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
+ mips64el:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
openrisc*:Linux:*:*)
echo or1k-unknown-linux-${LIBC}
exit ;;
@@ -1032,6 +1036,9 @@ EOF
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
@@ -1297,14 +1304,21 @@ EOF
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
# Avoid executing cc on OS X 10.9, as it ships with a stub
@@ -1328,15 +1342,18 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
- NEO-?:NONSTOP_KERNEL:*:*)
+ NEO-*:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
- NSR-?:NONSTOP_KERNEL:*:*)
+ NSR-*:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk${UNAME_RELEASE}
+ exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
exit ;;
diff --git a/config.rpath b/config.rpath
index 98183ff2..af3c4155 100755
--- a/config.rpath
+++ b/config.rpath
@@ -2,7 +2,7 @@
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
-# Copyright 1996-2016 Free Software Foundation, Inc.
+# Copyright 1996-2017 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
diff --git a/config.sub b/config.sub
index 9feb73bf..40ea5dfe 100755
--- a/config.sub
+++ b/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2016-06-20'
+timestamp='2017-04-02'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright 1992-2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +117,7 @@ case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
- kopensolaris*-gnu* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -263,7 +263,7 @@ case $basic_machine in
| fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
- | i370 | i860 | i960 | ia64 \
+ | i370 | i860 | i960 | ia16 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
@@ -301,6 +301,7 @@ case $basic_machine in
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
@@ -314,6 +315,7 @@ case $basic_machine in
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \
+ | wasm32 \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
@@ -387,7 +389,7 @@ case $basic_machine in
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
- | i*86-* | i860-* | i960-* | ia64-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
@@ -428,6 +430,7 @@ case $basic_machine in
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
| pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
@@ -444,6 +447,7 @@ case $basic_machine in
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| visium-* \
+ | wasm32-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
@@ -946,6 +950,9 @@ case $basic_machine in
nsr-tandem)
basic_machine=nsr-tandem
;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
@@ -1030,7 +1037,7 @@ case $basic_machine in
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
+ ppcle | powerpclittle)
basic_machine=powerpcle-unknown
;;
ppcle-* | powerpclittle-*)
@@ -1040,7 +1047,7 @@ case $basic_machine in
;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ ppc64le | powerpc64little)
basic_machine=powerpc64le-unknown
;;
ppc64le-* | powerpc64little-*)
@@ -1241,6 +1248,9 @@ case $basic_machine in
basic_machine=a29k-wrs
os=-vxworks
;;
+ wasm32)
+ basic_machine=wasm32-unknown
+ ;;
w65*)
basic_machine=w65-wdc
os=-none
@@ -1395,7 +1405,7 @@ case $os in
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* | -cegcc* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
@@ -1407,7 +1417,7 @@ case $os in
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
- | -onefs* | -tirtos* | -phoenix*)
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1636,6 +1646,9 @@ case $basic_machine in
sparc-* | *-sun)
os=-sunos4.1.1
;;
+ pru-*)
+ os=-elf
+ ;;
*-be)
os=-beos
;;
diff --git a/configh.in b/configh.in
index d3624c2b..41f63d4f 100644
--- a/configh.in
+++ b/configh.in
@@ -48,6 +48,9 @@
/* Define to 1 if you have the `fmod' function. */
#undef HAVE_FMOD
+/* Define to 1 if you have the `fwrite_unlocked' function. */
+#undef HAVE_FWRITE_UNLOCKED
+
/* have getaddrinfo */
#undef HAVE_GETADDRINFO
@@ -168,6 +171,9 @@
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
@@ -302,6 +308,9 @@
/* Define to 1 if you have the `usleep' function. */
#undef HAVE_USLEEP
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
/* Define to 1 if you have the <wchar.h> header file. */
#undef HAVE_WCHAR_H
@@ -332,9 +341,6 @@
/* enable severe portability problems */
#undef I_DONT_KNOW_WHAT_IM_DOING
-/* libc is broken for regex handling */
-#undef LIBC_IS_BORKED
-
/* disable lint checks */
#undef NO_LINT
@@ -362,9 +368,6 @@
/* Define to 1 if *printf supports %F format */
#undef PRINTF_HAS_F_FORMAT
-/* Define as the return type of signal handlers (`int' or `void'). */
-#undef RETSIGTYPE
-
/* The size of `unsigned int', as computed by sizeof. */
#undef SIZEOF_UNSIGNED_INT
diff --git a/configure b/configure
index 074ae48f..c1b5eca4 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for GNU Awk 4.1.4.
+# Generated by GNU Autoconf 2.69 for GNU Awk 4.1.61.
#
# Report bugs to <bug-gawk@gnu.org>.
#
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='GNU Awk'
PACKAGE_TARNAME='gawk'
-PACKAGE_VERSION='4.1.4'
-PACKAGE_STRING='GNU Awk 4.1.4'
+PACKAGE_VERSION='4.1.61'
+PACKAGE_STRING='GNU Awk 4.1.61'
PACKAGE_BUGREPORT='bug-gawk@gnu.org'
PACKAGE_URL='http://www.gnu.org/software/gawk/'
@@ -662,6 +662,7 @@ USE_NLS
SED
pkgextensiondir
acl_shlibext
+RANLIB
LN_S
YFLAGS
YACC
@@ -765,6 +766,7 @@ enable_silent_rules
with_whiny_user_strftime
enable_lint
enable_severe_portability_problems
+enable_mpfr
enable_dependency_tracking
enable_largefile
enable_nls
@@ -1328,7 +1330,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures GNU Awk 4.1.4 to adapt to many kinds of systems.
+\`configure' configures GNU Awk 4.1.61 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1398,7 +1400,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of GNU Awk 4.1.4:";;
+ short | recursive ) echo "Configuration of GNU Awk 4.1.61:";;
esac
cat <<\_ACEOF
@@ -1408,8 +1410,10 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-silent-rules less verbose build output (undo: "make V=1")
--disable-silent-rules verbose build output (undo: "make V=0")
- --disable-lint Disable gawk lint checking
- --enable-severe-portability-problems Enable really nasty portability problems
+ --disable-lint do not compile in gawk lint checking
+ --enable-severe-portability-problems
+ allow really nasty portability problems
+ --disable-mpfr do not check for MPFR
--enable-dependency-tracking
do not reject slow dependency extractors
--disable-dependency-tracking
@@ -1422,7 +1426,9 @@ Optional Features:
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-whiny-user-strftime Force use of included version of strftime for deficient systems
+ --with-whiny-user-strftime
+ force use of included version of strftime for
+ deficient systems
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
--with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib
--without-libiconv-prefix don't search for libiconv in includedir and libdir
@@ -1517,7 +1523,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-GNU Awk configure 4.1.4
+GNU Awk configure 4.1.61
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2226,7 +2232,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by GNU Awk $as_me 4.1.4, which was
+It was created by GNU Awk $as_me 4.1.61, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3109,7 +3115,7 @@ fi
# Define the identity of the package.
PACKAGE='gawk'
- VERSION='4.1.4'
+ VERSION='4.1.61'
cat >>confdefs.h <<_ACEOF
@@ -3240,6 +3246,17 @@ $as_echo "#define I_DONT_KNOW_WHAT_IM_DOING 1" >>confdefs.h
fi
+SKIP_MPFR=no
+# Check whether --enable-mpfr was given.
+if test "${enable_mpfr+set}" = set; then :
+ enableval=$enable_mpfr; if test "$enableval" = no
+ then
+ SKIP_MPFR=yes
+ fi
+
+fi
+
+
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
@@ -4931,524 +4948,167 @@ else
$as_echo "no, using $LN_S" >&6; }
fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- fi
-fi
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl.exe
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl.exe
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
-fi
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
-# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
- { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- sed '10a\
-... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
- cat conftest.er1 >&5
- fi
- rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+typedef const char *ccp;
-int
-main ()
+static inline int
+test_restrict (ccp restrict text)
{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
return 0;
}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_compiler_gnu=yes
-else
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_save_c_werror_flag=$ac_c_werror_flag
- ac_c_werror_flag=yes
- ac_cv_prog_cc_g=no
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int
-main ()
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
- ;
- return 0;
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-else
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
int
main ()
{
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+ // Check bool.
+ _Bool success = false;
-else
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
-int
-main ()
-{
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
;
return 0;
}
_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
+ ac_cv_prog_cc_c99=$ac_arg
fi
rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
fi
# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
+case "x$ac_cv_prog_cc_c99" in
x)
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;;
@@ -5456,205 +5116,13 @@ $as_echo "none needed" >&6; } ;;
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;;
*)
- CC="$CC $ac_cv_prog_cc_c89"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
-if ${am_cv_prog_cc_c_o+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
- # Make sure it works both with $CC and with simple cc.
- # Following AC_PROG_CC_C_O, we do the test twice because some
- # compilers refuse to overwrite an existing .o file with -o,
- # though they will create one.
- am_cv_prog_cc_c_o=yes
- for am_i in 1 2; do
- if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
- ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } \
- && test -f conftest2.$ac_objext; then
- : OK
- else
- am_cv_prog_cc_c_o=no
- break
- fi
- done
- rm -f core conftest*
- unset am_i
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-$as_echo "$am_cv_prog_cc_c_o" >&6; }
-if test "$am_cv_prog_cc_c_o" != yes; then
- # Losing compiler, so override with the script.
- # FIXME: It is wrong to rewrite CC.
- # But if we don't then we get into trouble of one sort or another.
- # A longer-term fix would be to have automake use am__CC in this case,
- # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
- CC="$am_aux_dir/compile $CC"
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-depcc="$CC" am_compiler_list=
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-$as_echo_n "checking dependency style of $depcc... " >&6; }
-if ${am_cv_CC_dependencies_compiler_type+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
- # We make a subdir and do the tests there. Otherwise we can end up
- # making bogus files that we don't know about and never remove. For
- # instance it was reported that on HP-UX the gcc test will end up
- # making a dummy file named 'D' -- because '-MD' means "put the output
- # in D".
- rm -rf conftest.dir
- mkdir conftest.dir
- # Copy depcomp to subdir because otherwise we won't find it if we're
- # using a relative directory.
- cp "$am_depcomp" conftest.dir
- cd conftest.dir
- # We will build objects and dependencies in a subdirectory because
- # it helps to detect inapplicable dependency modes. For instance
- # both Tru64's cc and ICC support -MD to output dependencies as a
- # side effect of compilation, but ICC will put the dependencies in
- # the current directory while Tru64 will put them in the object
- # directory.
- mkdir sub
-
- am_cv_CC_dependencies_compiler_type=none
- if test "$am_compiler_list" = ""; then
- am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
- fi
- am__universal=false
- case " $depcc " in #(
- *\ -arch\ *\ -arch\ *) am__universal=true ;;
- esac
-
- for depmode in $am_compiler_list; do
- # Setup a source with many dependencies, because some compilers
- # like to wrap large dependency lists on column 80 (with \), and
- # we should not choose a depcomp mode which is confused by this.
- #
- # We need to recreate these files for each test, as the compiler may
- # overwrite some of them when testing with obscure command lines.
- # This happens at least with the AIX C compiler.
- : > sub/conftest.c
- for i in 1 2 3 4 5 6; do
- echo '#include "conftst'$i'.h"' >> sub/conftest.c
- # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
- # Solaris 10 /bin/sh.
- echo '/* dummy */' > sub/conftst$i.h
- done
- echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
-
- # We check with '-c' and '-o' for the sake of the "dashmstdout"
- # mode. It turns out that the SunPro C++ compiler does not properly
- # handle '-M -o', and we need to detect this. Also, some Intel
- # versions had trouble with output in subdirs.
- am__obj=sub/conftest.${OBJEXT-o}
- am__minus_obj="-o $am__obj"
- case $depmode in
- gcc)
- # This depmode causes a compiler race in universal mode.
- test "$am__universal" = false || continue
- ;;
- nosideeffect)
- # After this tag, mechanisms are not by side-effect, so they'll
- # only be used when explicitly requested.
- if test "x$enable_dependency_tracking" = xyes; then
- continue
- else
- break
- fi
- ;;
- msvc7 | msvc7msys | msvisualcpp | msvcmsys)
- # This compiler won't grok '-c -o', but also, the minuso test has
- # not run yet. These depmodes are late enough in the game, and
- # so weak that their functioning should not be impacted.
- am__obj=conftest.${OBJEXT-o}
- am__minus_obj=
- ;;
- none) break ;;
- esac
- if depmode=$depmode \
- source=sub/conftest.c object=$am__obj \
- depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
- $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
- >/dev/null 2>conftest.err &&
- grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
- grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
- grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
- ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
- # icc doesn't choke on unknown options, it will just issue warnings
- # or remarks (even with -Werror). So we grep stderr for any message
- # that says an option was ignored or not supported.
- # When given -MP, icc 7.0 and 7.1 complain thusly:
- # icc: Command line warning: ignoring option '-M'; no argument required
- # The diagnosis changed in icc 8.0:
- # icc: Command line remark: option '-MP' not supported
- if (grep 'ignoring option' conftest.err ||
- grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
- am_cv_CC_dependencies_compiler_type=$depmode
- break
- fi
- fi
- done
-
- cd ..
- rm -rf conftest.dir
-else
- am_cv_CC_dependencies_compiler_type=none
-fi
+if test "x$ac_cv_prog_cc_c99" != xno; then :
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
-$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
-CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
-
- if
- test "x$enable_dependency_tracking" != xno \
- && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
- am__fastdepCC_TRUE=
- am__fastdepCC_FALSE='#'
-else
- am__fastdepCC_TRUE='#'
- am__fastdepCC_FALSE=
-fi
ac_ext=c
@@ -5794,6 +5262,98 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
@@ -5955,14 +5515,12 @@ $as_echo "$as_me: WARNING: unrecognized compiler environment" >&2;}
esac
fi # ac_cv_zos_uss = yes
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strerror in -lcposix" >&5
-$as_echo_n "checking for strerror in -lcposix... " >&6; }
-if ${ac_cv_lib_cposix_strerror+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5
+$as_echo_n "checking for library containing strerror... " >&6; }
+if ${ac_cv_search_strerror+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcposix $LIBS"
+ ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5981,22 +5539,37 @@ return strerror ();
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_cposix_strerror=yes
-else
- ac_cv_lib_cposix_strerror=no
+for ac_lib in '' cposix; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_strerror=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cposix_strerror" >&5
-$as_echo "$ac_cv_lib_cposix_strerror" >&6; }
-if test "x$ac_cv_lib_cposix_strerror" = xyes; then :
- LIBS="$LIBS -lcposix"
+ conftest$ac_exeext
+ if ${ac_cv_search_strerror+:} false; then :
+ break
fi
+done
+if ${ac_cv_search_strerror+:} false; then :
+else
+ ac_cv_search_strerror=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5
+$as_echo "$ac_cv_search_strerror" >&6; }
+ac_res=$ac_cv_search_strerror
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+fi
# Check whether --enable-largefile was given.
if test "${enable_largefile+set}" = set; then :
@@ -6199,51 +5772,6 @@ rm -rf conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AIX compilation hacks" >&5
-$as_echo_n "checking for AIX compilation hacks... " >&6; }
-if ${gawk_cv_aix_hack+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
-if test -d /lpp
-then
- CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED=1 -DGAWK_AIX=1"
- gawk_cv_aix_hack=yes
-else
- gawk_cv_aix_hack=no
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${gawk_cv_aix_hack}" >&5
-$as_echo "${gawk_cv_aix_hack}" >&6; }
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux/Alpha compilation hacks" >&5
-$as_echo_n "checking for Linux/Alpha compilation hacks... " >&6; }
-if ${gawk_cv_linux_alpha_hack+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
-if test "Linux" = "`uname`" && test "alpha" = "`uname -m`"
-then
- # this isn't necessarily always true,
- # the vendor's compiler is also often found
- if test "$GCC" = yes
- then
- CFLAGS="$CFLAGS -mieee"
- gawk_cv_linux_alpha_hack=yes
- else
- gawk_cv_linux_alpha_hack=no
- fi
-else
- gawk_cv_linux_alpha_hack=no
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${gawk_cv_linux_alpha_hack}" >&5
-$as_echo "${gawk_cv_linux_alpha_hack}" >&6; }
-
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we are using EBCDIC" >&5
$as_echo_n "checking if we are using EBCDIC... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -6266,19 +5794,6 @@ rm -f conftest*
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_ebcdic" >&5
$as_echo "$use_ebcdic" >&6; }
-if test "$ISC" = 1 # will be set by test for ISC
-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'
@@ -8843,39 +8358,6 @@ _ACEOF
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
-$as_echo_n "checking return type of signal handlers... " >&6; }
-if ${ac_cv_type_signal+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-#include <signal.h>
-
-int
-main ()
-{
-return *(signal (0, 0)) (0) == 1;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_signal=int
-else
- ac_cv_type_signal=void
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
-$as_echo "$ac_cv_type_signal" >&6; }
-
-cat >>confdefs.h <<_ACEOF
-#define RETSIGTYPE $ac_cv_type_signal
-_ACEOF
-
-
ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
if test "x$ac_cv_type_size_t" = xyes; then :
@@ -9337,8 +8819,10 @@ else
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
rsync_cv_socklen_t_equiv=
- for arg2 in "struct sockaddr" void; do
- for t in int size_t unsigned long "unsigned long"; do
+ for arg2 in "struct sockaddr" void
+ do
+ for t in int size_t unsigned long "unsigned long"
+ do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9368,7 +8852,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
done
- if test "x$rsync_cv_socklen_t_equiv" = x; then
+ if test "x$rsync_cv_socklen_t_equiv" = x
+ then
rsync_cv_socklen_t_equiv=int
fi
@@ -10438,11 +9923,13 @@ esac
# Need the check for mkstemp and tmpfile for missing_d/snprintf.c.
for ac_func in __etoa_l atexit btowc fmod getgrent getgroups grantpt \
+ fwrite_unlocked \
isascii iswctype iswlower iswupper mbrlen \
memcmp memcpy memcpy_ulong memmove memset \
- memset_ulong mkstemp posix_openpt setenv setlocale setsid snprintf strchr \
+ memset_ulong mkstemp posix_openpt setenv setlocale setsid sigprocmask \
+ snprintf strchr \
strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \
- system tmpfile towlower towupper tzset usleep wcrtomb \
+ system tmpfile towlower towupper tzset usleep waitpid wcrtomb \
wcscoll wctype
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -10498,7 +9985,8 @@ if test "${enable_extensions+set}" = set; then :
enableval=$enable_extensions;
fi
-if test "x$enable_extensions" != "xno"; then
+if test "x$enable_extensions" != "xno"
+then
extensions_supported=no
case $host_os in
@@ -10578,7 +10066,8 @@ fi
$as_echo "#define DYNAMIC 1" >>confdefs.h
# Add -export-dynamic for old extensions. Only works for GCC
- if test "$GCC" = yes; then
+ if test "$GCC" = yes
+ then
case $host_os in
linux*|freebsd*)
LDFLAGS="$LDFLAGS -Wl,-export-dynamic"
@@ -10593,7 +10082,8 @@ fi
;;
esac
- if test "x$enable_extensions$extensions_supported" = "xyesno"; then
+ if test "x$enable_extensions$extensions_supported" = "xyesno"
+ then
as_fn_error $? "extension support requested, but unavailable" "$LINENO" 5
fi
enable_extensions=$extensions_supported
@@ -10682,7 +10172,8 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-if test "$has_f_format" = yes; then
+if test "$has_f_format" = yes
+then
$as_echo "#define PRINTF_HAS_F_FORMAT 1" >>confdefs.h
@@ -11040,7 +10531,12 @@ fi
fi
-
+case `uname -m` in
+*'Power Macintosh'*)
+ : ;;
+*)
+ case $SKIP_MPFR in
+ no)
# Check whether --with-mpfr was given.
if test "${with_mpfr+set}" = set; then :
@@ -11114,6 +10610,10 @@ $as_echo "#define HAVE_MPFR 1" >>confdefs.h
unset _found_mpfr
fi
+ ;;
+ esac
+ ;;
+esac
ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then :
@@ -11497,9 +10997,10 @@ dylib) GAWKLIBEXT=so ;; # MacOS uses .dylib for shared libraries, but libtool us
esac
-ac_config_files="$ac_config_files Makefile awklib/Makefile doc/Makefile po/Makefile.in test/Makefile"
+ac_config_files="$ac_config_files Makefile support/Makefile awklib/Makefile doc/Makefile extras/Makefile po/Makefile.in test/Makefile"
-if test "x$enable_extensions" = "xyes"; then
+if test "x$enable_extensions" = "xyes"
+then
subdirs="$subdirs extension"
@@ -11638,10 +11139,6 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
-if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
- as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
if test -z "${TEST_CROSS_COMPILE_TRUE}" && test -z "${TEST_CROSS_COMPILE_FALSE}"; then
as_fn_error $? "conditional \"TEST_CROSS_COMPILE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -12047,7 +11544,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by GNU Awk $as_me 4.1.4, which was
+This file was extended by GNU Awk $as_me 4.1.61, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12115,7 +11612,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-GNU Awk config.status 4.1.4
+GNU Awk config.status 4.1.61
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -12255,8 +11752,10 @@ do
"po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;;
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:configh.in" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "support/Makefile") CONFIG_FILES="$CONFIG_FILES support/Makefile" ;;
"awklib/Makefile") CONFIG_FILES="$CONFIG_FILES awklib/Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "extras/Makefile") CONFIG_FILES="$CONFIG_FILES extras/Makefile" ;;
"po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index 6f31e812..011532f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
dnl
dnl configure.ac --- autoconf input file for gawk
dnl
-dnl Copyright (C) 1995-2016 the Free Software Foundation, Inc.
+dnl Copyright (C) 1995-2017 the Free Software Foundation, Inc.
dnl
dnl This file is part of GAWK, the GNU implementation of the
dnl AWK Programming Language.
@@ -23,7 +23,7 @@ dnl
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([GNU Awk], 4.1.4, bug-gawk@gnu.org, gawk)
+AC_INIT([GNU Awk],[4.1.61],[bug-gawk@gnu.org],[gawk])
# This is a hack. Different versions of install on different systems
# are just too different. Chuck it and use install-sh.
@@ -39,32 +39,44 @@ then
export INSTALL
fi
-AC_PREREQ(2.69)
+AC_PREREQ([2.69])
AM_INIT_AUTOMAKE([1.15 dist-xz dist-lzip])
AC_CONFIG_MACRO_DIR([m4])
dnl Additional argument stuff
-AC_ARG_WITH(whiny-user-strftime, [ --with-whiny-user-strftime Force use of included version of strftime for deficient systems],
+AC_ARG_WITH(whiny-user-strftime,
+ [AS_HELP_STRING([--with-whiny-user-strftime], [force use of included version of strftime for deficient systems])],
if test "$withval" = yes
then
AC_DEFINE(USE_INCLUDED_STRFTIME, 1,
[force use of our version of strftime])
fi
)
-AC_ARG_ENABLE([lint], [ --disable-lint Disable gawk lint checking],
+AC_ARG_ENABLE([lint],
+ [AS_HELP_STRING([--disable-lint],[do not compile in gawk lint checking])],
if test "$enableval" = no
then
AC_DEFINE(NO_LINT, 1, [disable lint checks])
fi
)
-AC_ARG_ENABLE([severe-portability-problems], [ --enable-severe-portability-problems Enable really nasty portability problems],
+AC_ARG_ENABLE([severe-portability-problems],
+ [AS_HELP_STRING([--enable-severe-portability-problems],[allow really nasty portability problems])],
if test "$enableval" = yes
then
AC_DEFINE(I_DONT_KNOW_WHAT_IM_DOING, 1, [enable severe portability problems])
fi
)
+SKIP_MPFR=no
+AC_ARG_ENABLE([mpfr],
+ [AS_HELP_STRING([--disable-mpfr],[do not check for MPFR])],
+ if test "$enableval" = no
+ then
+ SKIP_MPFR=yes
+ fi
+)
+
AC_CANONICAL_HOST
AC_USE_SYSTEM_EXTENSIONS
@@ -72,8 +84,9 @@ dnl checks for programs
AC_PROG_EGREP
AC_PROG_YACC
AC_PROG_LN_S
-AC_PROG_CC
+AC_PROG_CC_C99
AC_PROG_CPP
+AC_PROG_RANLIB
AC_OBJEXT
AC_EXEEXT
@@ -110,10 +123,8 @@ AC_SUBST([pkgextensiondir], ['${pkglibdir}'])
dnl checks for systems
AC_ZOS_USS
-AC_ISC_POSIX
+AC_SEARCH_LIBS([strerror],[cposix])
AC_SYS_LARGEFILE
-GAWK_AC_AIX_TWEAK
-GAWK_AC_LINUX_ALPHA
AC_MSG_CHECKING([if we are using EBCDIC])
AC_EGREP_CPP([gnu_gawk_in_ebcdic],
@@ -125,19 +136,6 @@ gnu_gawk_in_ebcdic
[use_ebcdic=no])
AC_MSG_RESULT([$use_ebcdic])
-if test "$ISC" = 1 # will be set by test for ISC
-then
-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])
@@ -170,8 +168,7 @@ AM_CONDITIONAL([TEST_CROSS_COMPILE], [test "x$build_alias" != "x$host_alias"])
dnl checks for typedefs
AC_TYPE_PID_T
-AC_TYPE_SIGNAL
-AC_SIZE_T
+AC_TYPE_SIZE_T
AC_TYPE_GETGROUPS
AC_TYPE_LONG_LONG_INT
AC_TYPE_UNSIGNED_LONG_LONG_INT
@@ -181,30 +178,26 @@ AC_CHECK_TYPE(ssize_t, int)
AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
dnl see if time_t is defined in <sys/types.h>
-AC_TRY_COMPILE([#include <sys/types.h>],[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>]], [[
time_t foo;
foo = 0;
-],
- AC_DEFINE(TIME_T_IN_SYS_TYPES_H, 1,
- [some systems define this type here]))
+]])],[AC_DEFINE(TIME_T_IN_SYS_TYPES_H, 1,
+ some systems define this type here)],[])
dnl check for wctype_t in <wctype.h>
-AC_TRY_COMPILE([#include <wctype.h>],[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <wctype.h>]], [[
wctype_t foo;
foo = 0;
-],
- AC_DEFINE(HAVE_WCTYPE_T, 1, [systems should define this type here]))
+]])],[AC_DEFINE(HAVE_WCTYPE_T, 1, systems should define this type here)],[])
dnl check for wint_t in <wctype.h>
-AC_TRY_COMPILE([#include <wctype.h>],[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <wctype.h>]], [[
wint_t foo;
foo = 0;
-],
- AC_DEFINE(HAVE_WINT_T, 1, [systems should define this type here]))
+]])],[AC_DEFINE(HAVE_WINT_T, 1, systems should define this type here)],[])
dnl check for sockaddr_storage
-AC_TRY_COMPILE([#include <sys/types.h>
-#include <sys/socket.h>],[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <sys/socket.h>]], [[
struct sockaddr_storage foo;
-],
- AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [newer systems define this type here]))
+]])],[AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, newer systems define this type here)],[])
dnl Borrwed from rsync, thanks to to Jim Meyering.
@@ -225,24 +218,27 @@ AC_DEFUN([TYPE_SOCKLEN_T],
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
rsync_cv_socklen_t_equiv=
- for arg2 in "struct sockaddr" void; do
- for t in int size_t unsigned long "unsigned long"; do
- AC_TRY_COMPILE([
+ for arg2 in "struct sockaddr" void
+ do
+ for t in int size_t unsigned long "unsigned long"
+ do
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
- ],[
+ ]], [[
$t len;
getpeername(0,0,&len);
- ],[
+ ]])],[
rsync_cv_socklen_t_equiv="$t"
break
- ])
+ ],[])
done
done
- if test "x$rsync_cv_socklen_t_equiv" = x; then
+ if test "x$rsync_cv_socklen_t_equiv" = x
+ then
dnl Some systems get this. Default to int. -- ADR
dnl AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
rsync_cv_socklen_t_equiv=int
@@ -284,11 +280,13 @@ esac
# Need the check for mkstemp and tmpfile for missing_d/snprintf.c.
AC_CHECK_FUNCS(__etoa_l atexit btowc fmod getgrent getgroups grantpt \
+ fwrite_unlocked \
isascii iswctype iswlower iswupper mbrlen \
memcmp memcpy memcpy_ulong memmove memset \
- memset_ulong mkstemp posix_openpt setenv setlocale setsid snprintf strchr \
+ memset_ulong mkstemp posix_openpt setenv setlocale setsid sigprocmask \
+ snprintf strchr \
strerror strftime strcasecmp strncasecmp strcoll strtod strtoul \
- system tmpfile towlower towupper tzset usleep wcrtomb \
+ system tmpfile towlower towupper tzset usleep waitpid wcrtomb \
wcscoll wctype)
dnl this check is for both mbrtowc and the mbstate_t type, which is good
AC_FUNC_MBRTOWC
@@ -297,7 +295,8 @@ dnl check for dynamic linking
dnl This is known to be very primitive
AC_ARG_ENABLE([extensions],
[AS_HELP_STRING([--disable-extensions], [disable dynamic extensions (default is detect)])])
-if test "x$enable_extensions" != "xno"; then
+if test "x$enable_extensions" != "xno"
+then
extensions_supported=no
dnl On MirBSD (and probably other systems), don't even try.
@@ -318,7 +317,8 @@ if test "x$enable_extensions" != "xno"; then
extensions_supported=yes
AC_DEFINE([DYNAMIC], 1, [dynamic loading is possible])
# Add -export-dynamic for old extensions. Only works for GCC
- if test "$GCC" = yes; then
+ if test "$GCC" = yes
+ then
case $host_os in
linux*|freebsd*)
LDFLAGS="$LDFLAGS -Wl,-export-dynamic"
@@ -330,7 +330,8 @@ if test "x$enable_extensions" != "xno"; then
;;
esac
- if test "x$enable_extensions$extensions_supported" = "xyesno"; then
+ if test "x$enable_extensions$extensions_supported" = "xyesno"
+ then
AC_MSG_ERROR([extension support requested, but unavailable])
fi
enable_extensions=$extensions_supported
@@ -371,7 +372,8 @@ int main()
has_f_format=no,
has_f_format=no dnl Cross-compiling, assuming the worst.
)
-if test "$has_f_format" = yes; then
+if test "$has_f_format" = yes
+then
AC_DEFINE(PRINTF_HAS_F_FORMAT, 1, [Define to 1 if *printf supports %F format])
fi
AC_MSG_RESULT($has_f_format)
@@ -383,7 +385,16 @@ dnl check for readline support
GAWK_CHECK_READLINE
dnl check for mpfr support
-GNUPG_CHECK_MPFR
+case `uname -m` in
+*'Power Macintosh'*)
+ : ;;
+*)
+ case $SKIP_MPFR in
+ no) GNUPG_CHECK_MPFR
+ ;;
+ esac
+ ;;
+esac
dnl checks for structure members
AC_CHECK_MEMBERS([struct stat.st_blksize])
@@ -418,11 +429,14 @@ esac
AC_SUBST(GAWKLIBEXT)
AC_CONFIG_FILES(Makefile
+ support/Makefile
awklib/Makefile
doc/Makefile
+ extras/Makefile
po/Makefile.in
test/Makefile)
-if test "x$enable_extensions" = "xyes"; then
+if test "x$enable_extensions" = "xyes"
+then
AC_CONFIG_SUBDIRS(extension)
fi
AC_OUTPUT
diff --git a/custom.h b/custom.h
index 5660a66f..90fd1f63 100644
--- a/custom.h
+++ b/custom.h
@@ -10,23 +10,23 @@
* the information, to arnold@skeeve.com.
*/
-/*
+/*
* Copyright (C) 1995-2004, 2008, 2009, 2011, 2016
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -60,6 +60,10 @@
#define _TZSET 1
#endif
+#if defined(_AIX)
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
/* Junk for dfa.[ch] */
/* The __pure__ attribute was added in gcc 2.96. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
diff --git a/debug.c b/debug.c
index c7271785..1e04e233 100644
--- a/debug.c
+++ b/debug.c
@@ -1,23 +1,23 @@
/*
- * debug.c - gawk debugger
+ * debug.c - gawk debugger
*/
-/*
+/*
* Copyright (C) 2004, 2010-2013, 2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -77,7 +77,7 @@ struct commands_item {
CMDARG *arg;
};
-/* breakpoint structure */
+/* breakpoint structure */
typedef struct break_point {
struct break_point *next;
struct break_point *prev;
@@ -99,7 +99,7 @@ typedef struct break_point {
#define BP_TEMP 4
#define BP_IGNORE 8
-} BREAKPOINT;
+} BREAKPOINT;
static BREAKPOINT breakpoints = { &breakpoints, &breakpoints, 0 };
@@ -126,12 +126,12 @@ struct list_item {
NODE *symbol; /* variable or function param */
NODE **subs; /* subscripts */
- int num_subs; /* subscript(dimension) count */
+ int num_subs; /* subscript(dimension) count */
char *sname; /* symbol or param name */
long fcall_count;
- struct commands_item commands;
+ struct commands_item commands;
int silent;
struct condition cndn;
@@ -149,8 +149,8 @@ struct list_item {
#define PARAM 1
#define SUBSCRIPT 2
#define FIELD_NUM 4
-#define OLD_IS_ARRAY 8 /* old item is array */
-#define CUR_IS_ARRAY 16 /* current item is array */
+#define OLD_IS_ARRAY 8 /* old item is array */
+#define CUR_IS_ARRAY 16 /* current item is array */
};
#define IS_PARAM(d) (((d)->flags & PARAM) != 0)
@@ -175,7 +175,7 @@ static struct {
INSTRUCTION *pc; /* 'until' and 'return' commands */
int repeat_count; /* 'step', 'next', 'stepi', 'nexti' commands */
bool print_frame; /* print frame info, 'finish' and 'until' */
- bool print_ret; /* print returned value, 'finish' */
+ bool print_ret; /* print returned value, 'finish' */
int break_point; /* non-zero (breakpoint number) if stopped at break point */
int watch_point; /* non-zero (watchpoint number) if stopped at watch point */
@@ -183,7 +183,7 @@ static struct {
* awk interpreter and return control
* to debugger command interpreter.
*/
-
+
enum argtype command; /* command type */
} stop;
@@ -200,8 +200,8 @@ static const char *const env_variable[] = {
"DGAWK_HISTORY",
"DGAWK_OPTION",
};
-static void serialize(int );
-static void unserialize(int );
+static void serialize_list(int type);
+static void unserialize_list(int type);
static const char *commands_string = NULL;
static int commands_string_len = 0;
static char line_sep;
@@ -216,7 +216,7 @@ struct dbg_option {
int *num_val;
char **str_val;
void (*assign)(const char *);
- const char *help_txt;
+ const char *help_txt;
};
#define DEFAULT_HISTFILE "./.gawk_history"
@@ -273,7 +273,7 @@ jmp_buf pager_quit_tag;
int pager_quit_tag_valid = 0;
static int screen_width = INT_MAX; /* no of columns */
static int screen_height = INT_MAX; /* no of rows */
-static int pager_lines_printed = 0; /* no of lines printed so far */
+static int pager_lines_printed = 0; /* no of lines printed so far */
static void restart(bool run) ATTRIBUTE_NORETURN;
static void close_all(void);
@@ -574,7 +574,7 @@ print_lines(char *src, int start_line, int nlines)
for (i = start_line; i < start_line + nlines; i++) {
int supposed_len, len;
char *p;
-
+
sprintf(linebuf, "%-8d", i);
/* mark the line about to be executed with =>; nlines > 1
@@ -582,7 +582,7 @@ print_lines(char *src, int start_line, int nlines)
*/
if (nlines > 1) {
BREAKPOINT *b;
- bool has_bpt = false;
+ bool has_bpt = false;
for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
if (src == b->src && i == b->bpi->source_line) {
has_bpt = true;
@@ -595,7 +595,7 @@ print_lines(char *src, int start_line, int nlines)
else
sprintf(linebuf, "%-4d =>", i);
} else if (has_bpt)
- sprintf(linebuf, "%-4d:b ", i);
+ sprintf(linebuf, "%-4d:b ", i);
}
p = linebuf + strlen(linebuf);
@@ -647,7 +647,7 @@ do_list(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
long count = list_size;
INSTRUCTION *rp;
char *src = cur_srcfile->src;
-
+
line_first = last_printed_line + 1; /* default or no arg */
if (arg == NULL) /* list or list + */
goto list;
@@ -679,10 +679,10 @@ range:
count = arg->a_int - line_first + 1;
break;
- case D_string:
+ case D_string:
src = arg->a_string;
if (arg->next != NULL) {
- arg = arg->next;
+ arg = arg->next;
if (arg->type == D_int) /* list file:n */
goto line;
else if (arg->type == D_range) /* list file:m-n */
@@ -713,7 +713,7 @@ list:
if (line_last != -1) {
last_printed_line = line_last;
last_print_count = line_last - line_first + 1;
- }
+ }
return false;
}
@@ -780,7 +780,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
continue;
start++;
*end = '\0';
- gprintf(out_fp, "%s", start); /* FIXME: translate ? */
+ gprintf(out_fp, "%s", start); /* FIXME: translate ? */
*end = '}';
}
}
@@ -898,9 +898,9 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
for (i = 0; i < d->num_subs; i++) {
NODE *sub;
sub = d->subs[i];
- gprintf(out_fp, "[\"%s\"]", sub->stptr);
+ gprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
}
- gprintf(out_fp, "\n");
+ gprintf(out_fp, "\n");
} else if (IS_FIELD(d))
gprintf(out_fp, "%d:\t$%ld\n", d->number, get_number_si(symbol));
else
@@ -920,7 +920,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
continue;
start++;
*end = '\0';
- gprintf(out_fp, "%s", start); /* FIXME: translate ? */
+ gprintf(out_fp, "%s", start); /* FIXME: translate ? */
*end = '}';
}
}
@@ -998,7 +998,7 @@ find_param(const char *name, long num, char **pname)
func = f->func_node;
pcount = func->param_cnt;
for (i = 0; i < pcount; i++) {
- fparam = func->fparms[i].param;
+ fparam = func->fparms[i].param;
if (strcmp(name, fparam) == 0) {
r = f->stack[i];
if (r->type == Node_array_ref)
@@ -1090,7 +1090,7 @@ print_array(volatile NODE *arr, char *arr_name)
if (r->type == Node_var_array)
ret = print_array(r, r->vname);
else {
- gprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
+ gprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr);
valinfo((NODE *) r, gprintf, out_fp);
}
}
@@ -1116,17 +1116,17 @@ print_subscript(NODE *arr, char *arr_name, CMDARG *a, int count)
subs = a->a_node;
r = in_array(arr, subs);
if (r == NULL)
- fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"), subs->stptr, arr_name);
+ fprintf(out_fp, _("[\"%.*s\"] not in array `%s'\n"), (int) subs->stlen, subs->stptr, arr_name);
else if (r->type == Node_var_array) {
if (count > 1)
print_subscript(r, r->vname, a->next, count - 1);
else {
/* print # of elements in array */
fprintf(out_fp, "%s = ", r->vname);
- print_symbol(r, false);
+ print_symbol(r, false);
}
} else {
- fprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
+ fprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr);
valinfo(r, fprintf, out_fp);
}
}
@@ -1163,17 +1163,17 @@ do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
if ((r = find_array(name)) != NULL) {
int count = a->a_count;
for (; count > 0; count--) {
- NODE *value, *subs;
+ NODE *value, *subs;
a = a->next;
subs = a->a_node;
value = in_array(r, subs);
if (value == NULL) {
- fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"),
- subs->stptr, name);
+ fprintf(out_fp, _("[\"%.*s\"] not in array `%s'\n"),
+ (int) subs->stlen, subs->stptr, name);
break;
} else if (value->type != Node_var_array) {
- fprintf(out_fp, _("`%s[\"%s\"]' is not an array\n"),
- name, subs->stptr);
+ fprintf(out_fp, _("`%s[\"%.*s\"]' is not an array\n"),
+ name, (int) subs->stlen, subs->stptr);
break;
} else {
r = value;
@@ -1195,9 +1195,9 @@ do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
/* notably D_node, subscript for invalid array name; skip */
break;
}
- }
+ }
return false;
-}
+}
/* do_set_var --- set command */
@@ -1255,15 +1255,15 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
if (count == 1) {
if (value != NULL && value->type == Node_var_array)
- d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
- name, subs->stptr);
+ d_error(_("attempt to use array `%s[\".*%s\"]' in a scalar context"),
+ name, (int) subs->stlen, subs->stptr);
else {
arg = arg->next;
val = arg->a_node;
lhs = assoc_lookup(r, subs);
unref(*lhs);
*lhs = dupnode(val);
- fprintf(out_fp, "%s[\"%s\"] = ", name, subs->stptr);
+ fprintf(out_fp, "%s[\"%.*s\"] = ", name, (int) subs->stlen, subs->stptr);
valinfo(*lhs, fprintf, out_fp);
}
} else {
@@ -1277,8 +1277,8 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
*lhs = array;
r = array;
} else if (value->type != Node_var_array) {
- d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
- name, subs->stptr);
+ d_error(_("attempt to use scalar `%s[\".*%s\"]' as array"),
+ name, (int) subs->stlen, subs->stptr);
break;
} else {
r = value;
@@ -1358,7 +1358,7 @@ delete_item(struct list_item *d)
free_context(d->cndn.ctxt, false);
if (d->cndn.expr != NULL)
efree(d->cndn.expr);
-
+
d->next->prev = d->prev;
d->prev->next = d->next;
efree(d);
@@ -1371,8 +1371,7 @@ add_item(struct list_item *list, int type, NODE *symbol, char *pname)
{
struct list_item *d;
- emalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
- memset(d, 0, sizeof(struct list_item));
+ ezalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
d->commands.next = d->commands.prev = &d->commands;
d->number = ++list->number;
@@ -1525,19 +1524,19 @@ display(struct list_item *d)
sub = d->subs[i];
r = in_array(symbol, sub);
if (r == NULL) {
- fprintf(out_fp, _("%d: [\"%s\"] not in array `%s'\n"),
- d->number, sub->stptr, d->sname);
+ fprintf(out_fp, _("%d: [\"%.*s\"] not in array `%s'\n"),
+ d->number, (int) sub->stlen, sub->stptr, d->sname);
break;
}
if (r->type == Node_var_array) {
symbol = r;
if (i == count - 1) /* it's a sub-array */
goto print_sym; /* print # of elements in sub-array */
- } else {
+ } else {
if (i != count - 1)
return; /* FIXME msg and delete item ? */
- fprintf(out_fp, "%d: %s[\"%s\"] = ", d->number,
- d->sname, sub->stptr);
+ fprintf(out_fp, "%d: %s[\"%.*s\"] = ", d->number,
+ d->sname, (int) sub->stlen, sub->stptr);
valinfo(r, fprintf, out_fp);
}
}
@@ -1574,15 +1573,15 @@ do_display(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
}
/* do_undisplay --- undisplay command */
-
+
int
do_undisplay(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
{
do_delete_item(&display_list, arg);
- return false;
+ return false;
}
-/* condition_triggered --- test if a condition expression is true */
+/* condition_triggered --- test if a condition expression is true */
static int
condition_triggered(struct condition *cndn)
@@ -1631,21 +1630,21 @@ find_subscript(struct list_item *item, NODE **ptr)
}
/* cmp_val --- compare values of watched item, returns true if different; */
-
+
static int
-cmp_val(struct list_item *w, NODE *old, NODE *new)
+cmp_val(struct list_item *w, NODE *old, NODE *new)
{
/*
* case old new result
* ------------------------------
- * 1: NULL ARRAY true
+ * 1: NULL ARRAY true
* 2: NULL SCALAR true
* 3: NULL NULL false
* 4: SCALAR SCALAR cmp_node
* 5: SCALAR ARRAY true
* 6: SCALAR NULL true
* 7: ARRAY SCALAR true
- * 8: ARRAY ARRAY compare size
+ * 8: ARRAY ARRAY compare size
* 9: ARRAY NULL true
*/
@@ -1670,7 +1669,7 @@ cmp_val(struct list_item *w, NODE *old, NODE *new)
if (new->type == Node_var_array) /* 5 */
return true;
- return cmp_nodes(old, new); /* 4 */
+ return cmp_nodes(old, new, true); /* 4 */
}
/* watchpoint_triggered --- check if we should stop at this watchpoint;
@@ -1790,6 +1789,8 @@ initialize_watch_item(struct list_item *w)
} else if (symbol->type == Node_var_array) {
w->flags |= CUR_IS_ARRAY;
w->cur_size = assoc_length(symbol);
+ } else if (symbol->type == Node_val && (symbol->flags & REGEX) != 0) {
+ w->cur_value = dupnode(symbol);
} /* else
can't happen */
}
@@ -1822,7 +1823,7 @@ do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
fprintf(out_fp, "%s", w->sname);
for (i = 0; i < w->num_subs; i++) {
sub = w->subs[i];
- fprintf(out_fp, "[\"%s\"]", sub->stptr);
+ fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
}
fprintf(out_fp, "\n");
} else if (IS_FIELD(w))
@@ -1834,7 +1835,7 @@ do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
}
/* do_unwatch --- unwatch command */
-
+
int
do_unwatch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
{
@@ -1881,9 +1882,9 @@ print_function(INSTRUCTION *pc, void *x)
{
NODE *func;
int i, pcount;
- struct pf_data *data = (struct pf_data *) x;
+ struct pf_data *data = (struct pf_data *) x;
int defn = data->defn;
- Func_print print_func = data->print_func;
+ Func_print print_func = data->print_func;
FILE *fp = data->fp;
func = pc->func_body;
@@ -1892,7 +1893,7 @@ print_function(INSTRUCTION *pc, void *x)
print_func(fp, "%s(", func->vname);
for (i = 0; i < pcount; i++) {
print_func(fp, "%s", func->fparms[i].param);
- if (i < pcount - 1)
+ if (i < pcount - 1)
print_func(fp, ", ");
}
print_func(fp, ")");
@@ -1936,7 +1937,7 @@ print_numbered_frame(long num)
} else {
fprintf(out_fp, _("#%ld\tin "), num);
print_frame(f->func_node, f->vname,
- ((INSTRUCTION *) find_frame(num - 1)->reti)->source_line);
+ ((INSTRUCTION *) find_frame(num - 1)->reti)->source_line);
}
fprintf(out_fp, "\n");
}
@@ -1965,7 +1966,7 @@ do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
if (cur < 0)
cur = 0;
}
- }
+ }
for (; cur <= last; cur++) {
print_numbered_frame(cur);
@@ -1973,12 +1974,12 @@ do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
if (cur <= fcall_count)
fprintf(out_fp, _("More stack frames follow ...\n"));
return false;
-}
+}
/* print_cur_frame_and_sourceline --- print current frame, and
* current source line.
*/
-
+
static void
print_cur_frame_and_sourceline()
{
@@ -2092,7 +2093,7 @@ find_rule(char *src, long lineno)
/* mk_breakpoint --- create a breakpoint instruction and the corresponding
* breakpoint structure.
*/
-
+
static INSTRUCTION *
mk_breakpoint(char *src, int srcline)
{
@@ -2113,7 +2114,7 @@ mk_breakpoint(char *src, int srcline)
b->src = src;
bp->break_pt = b;
b->bpi = bp;
-
+
/* prepend to list */
b->next = breakpoints.next;
b->prev = &breakpoints;
@@ -2136,7 +2137,7 @@ delete_breakpoint(BREAKPOINT *b)
* deleteing the instruction is not that simple,
* since could have reference to it somewhere else (e.g. cur_pc).
*/
-
+
pc->opcode = Op_no_op;
pc->source_line = 0;
pc->break_pt = NULL;
@@ -2147,7 +2148,7 @@ delete_breakpoint(BREAKPOINT *b)
delete_commands_item(c->next);
}
- free_context(b->cndn.ctxt, false);
+ free_context(b->cndn.ctxt, false);
if (b->cndn.expr != NULL)
efree(b->cndn.expr);
@@ -2165,7 +2166,7 @@ find_breakpoint(long num)
BREAKPOINT *b;
if (num <= 0)
- return NULL;
+ return NULL;
for (b = breakpoints.next; b != &breakpoints; b = b->next) {
if (b->number == num)
@@ -2175,7 +2176,7 @@ find_breakpoint(long num)
}
/* add_breakpoint --- add a breakpoint instruction between PREVP and IP */
-
+
static BREAKPOINT *
add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent)
{
@@ -2255,7 +2256,7 @@ set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent)
* a monotonically increasing sequence. Check if the line # is between
* the first and last statements of the case block before continuing
* the search.
- */
+ */
for (i2 = ip->stmt_start, i1 = i2->nexti; i2 != ip->stmt_end;
i2 = i1, i1 = i1->nexti) {
if (i1->source_line >= lineno)
@@ -2293,7 +2294,7 @@ set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip)
}
return NULL;
}
-
+
/* set_breakpoint --- set a breakpoint */
static int
@@ -2309,7 +2310,7 @@ set_breakpoint(CMDARG *arg, bool temporary)
if (arg == NULL) {
/*
* (From GDB Documentation):
-*
+*
* When called without any arguments, break sets a breakpoint at the next instruction
* to be executed in the selected stack frame (see section Examining the Stack).
* In any selected frame but the innermost, this makes your program stop as soon
@@ -2322,7 +2323,7 @@ set_breakpoint(CMDARG *arg, bool temporary)
* one instruction has been executed. If it did not do this,
* you would be unable to proceed past a breakpoint without first disabling the
* breakpoint. This rule applies whether or not the breakpoint already existed
-* when your program stopped.
+* when your program stopped.
*/
CHECK_PROG_RUNNING();
if (cur_frame == 0) {
@@ -2427,7 +2428,7 @@ breakpoint_triggered(BREAKPOINT *b)
if ((b->flags & BP_ENABLE_ONCE) != 0) {
b->flags &= ~BP_ENABLE_ONCE;
b->flags &= ~BP_ENABLE;
- }
+ }
return b->number;
}
@@ -2437,7 +2438,7 @@ int
do_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
{
return set_breakpoint(arg, false);
-}
+}
/* do_tmp_breakpoint --- tbreak command */
@@ -2611,7 +2612,7 @@ do_delete_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
delete_all = prompt_yes_no(
_("Delete all breakpoints? (y or n) "),
_("y")[0], true, out_fp);
-
+
if (delete_all) {
while (breakpoints.next != &breakpoints)
delete_breakpoint(breakpoints.next);
@@ -2736,7 +2737,7 @@ initialize_readline()
/* our completion function. */
rl_attempted_completion_function = command_completion;
- read_a_line = readline;
+ read_a_line = readline;
}
#else
#define initialize_readline() /* nothing */
@@ -2769,9 +2770,9 @@ debug_prog(INSTRUCTION *pc)
if (! read_a_line)
read_a_line = g_readline;
- push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
+ push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
- setbuf(out_fp, (char *) NULL);
+ setbuf(out_fp, (char *) NULL);
for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles;
cur_srcfile = cur_srcfile->prev) {
if (cur_srcfile->stype == SRC_FILE
@@ -2794,13 +2795,13 @@ debug_prog(INSTRUCTION *pc)
/* We are restarting; restore state (breakpoints, history etc.)
* passed as environment variables and optionally execute the run command.
*/
- unserialize(BREAK);
- unserialize(WATCH);
- unserialize(DISPLAY);
- unserialize(HISTORY);
- unserialize(OPTION);
+ unserialize_list(BREAK);
+ unserialize_list(WATCH);
+ unserialize_list(DISPLAY);
+ unserialize_list(HISTORY);
+ unserialize_list(OPTION);
unsetenv("DGAWK_RESTART");
- fprintf(out_fp, "Restarting ...\n");
+ fprintf(out_fp, "Restarting ...\n");
if (strcasecmp(run, "true") == 0)
(void) do_run(NULL, 0);
@@ -2867,7 +2868,7 @@ check_breakpoint(INSTRUCTION **pi)
pc = *pi;
if (stop.command == D_return)
- return false;
+ return false;
if (pc->opcode == Op_breakpoint) {
int bnum;
*pi = pc->nexti; /* skip past the breakpoint instruction;
@@ -2889,11 +2890,11 @@ static void
restart(bool run)
{
/* save state in the environment after serialization */
- serialize(BREAK);
- serialize(WATCH);
- serialize(DISPLAY);
- serialize(HISTORY);
- serialize(OPTION);
+ serialize_list(BREAK);
+ serialize_list(WATCH);
+ serialize_list(DISPLAY);
+ serialize_list(HISTORY);
+ serialize_list(OPTION);
/* tell the new process to restore state from the environment */
setenv("DGAWK_RESTART", (run ? "true" : "false"), 1);
@@ -3239,7 +3240,7 @@ check_return(INSTRUCTION **pi)
func = find_frame(cur_frame)->func_node;
assert(func != NULL);
- *pi = (func->code_ptr + 1)->lasti;
+ *pi = (func->code_ptr + 1)->lasti;
/* assert((*pi)->opcode == Op_K_return); */
}
@@ -3306,7 +3307,7 @@ do_until(CMDARG *arg, int cmd)
int lineno;
INSTRUCTION *rp, *ip;
NODE *func;
-
+
CHECK_PROG_RUNNING();
stop.pc = NULL;
stop.sourceline = 0;
@@ -3411,9 +3412,9 @@ print_watch_item(struct list_item *w)
fprintf(out_fp, "%s", w->sname);
for (i = 0; i < w->num_subs; i++) {
sub = w->subs[i];
- fprintf(out_fp, "[\"%s\"]", sub->stptr);
+ fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
}
- fprintf(out_fp, "\n");
+ fprintf(out_fp, "\n");
} else if (IS_FIELD(w))
fprintf(out_fp, "$%ld\n", get_number_si(symbol));
else
@@ -3478,12 +3479,12 @@ next_command()
print_watch_item(w);
}
- /* frame info */
+ /* frame info */
if (stop.print_frame) {
print_frame(frame_ptr->func_node, source, sourceline);
fprintf(out_fp, "\n");
stop.print_frame = false;
- }
+ }
(void) print_lines(source, sourceline, 1);
@@ -3495,12 +3496,12 @@ no_output:
/* update last_printed_line, so that output of 'list' is
* centered around current sourceline
*/
-
+
last_printed_line = sourceline - list_size / 2;
if (last_printed_line < 0)
last_printed_line = 0;
- /* update current source file */
+ /* update current source file */
s = source_find(source);
if (cur_srcfile != s) {
if (cur_srcfile->fd != INVALID_HANDLE) {
@@ -3526,7 +3527,7 @@ no_output:
read_command(); /* zzparse */
}
-/* debug_post_execute --- post_hook in the interpreter */
+/* debug_post_execute --- post_hook in the interpreter */
static void
debug_post_execute(INSTRUCTION *pc)
@@ -3545,14 +3546,14 @@ debug_post_execute(INSTRUCTION *pc)
stop.command = D_illegal;
stop.check_func = NULL;
fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"),
- op2str(pc->opcode));
+ op2str(pc->opcode));
} else if (stop.command == D_until) {
/* cancel until command */
stop.print_frame = false;
stop.command = D_illegal;
stop.check_func = NULL;
fprintf(out_fp, _("'until' not meaningful with non-local jump '%s'\n"),
- op2str(pc->opcode));
+ op2str(pc->opcode));
}
break;
@@ -3579,7 +3580,7 @@ debug_post_execute(INSTRUCTION *pc)
}
}
-/* debug_pre_execute --- pre_hook, called by the interpreter before execution;
+/* debug_pre_execute --- pre_hook, called by the interpreter before execution;
* checks if execution needs to be suspended and control
* transferred to the debugger.
*/
@@ -3609,7 +3610,7 @@ debug_pre_execute(INSTRUCTION **pi)
* yield surprising results. Ditto for Op_push_lhs for special variables
* (upto Op_var_assign, the set_FOO routine).
*/
-
+
switch (cur_pc->opcode) {
case Op_field_spec_lhs:
cant_stop = true;
@@ -3617,7 +3618,7 @@ debug_pre_execute(INSTRUCTION **pi)
case Op_field_assign:
cant_stop = false;
- return true; /* may stop at next instruction */
+ return true; /* may stop at next instruction */
case Op_push_lhs:
m = cur_pc->memory;
@@ -3647,7 +3648,7 @@ debug_pre_execute(INSTRUCTION **pi)
break; /* processed later in check_breakpoint() */
default:
- if (cur_pc->source_line <= 0)
+ if (cur_pc->source_line <= 0)
return true;
break;
}
@@ -3685,7 +3686,7 @@ debug_pre_execute(INSTRUCTION **pi)
/* print_memory --- print a scalar value */
-static void
+static void
print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
{
switch (m->type) {
@@ -3703,18 +3704,10 @@ print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
print_func(fp, "%g", m->numbr);
} else if ((m->flags & STRING) != 0)
pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
- else if ((m->flags & NUMCUR) != 0) {
-#ifdef HAVE_MPFR
- if ((m->flags & MPFN) != 0)
- print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
- else if ((m->flags & MPZN) != 0)
- print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
- else
-#endif
- print_func(fp, "%g", m->numbr);
- } else if ((m->flags & STRCUR) != 0)
- pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
- else
+ else if ((m->flags & REGEX) != 0) {
+ print_func(fp, "@");
+ pp_string_fp(print_func, fp, m->stptr, m->stlen, '/', false);
+ } else
print_func(fp, "-?-");
print_func(fp, " [%s]", flags2str(m->flags));
break;
@@ -3725,7 +3718,7 @@ print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
case Node_dynregex:
break;
-
+
case Node_param_list:
assert(func != NULL);
print_func(fp, "%s", func->fparms[m->param_cnt].param);
@@ -3790,7 +3783,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
func = find_frame(0)->func_node;
}
-
+
switch (pc->opcode) {
case Op_K_if:
print_func(fp, "[branch_if = %p] [branch_else = %p] [branch_else->lasti = %p]\n",
@@ -3954,7 +3947,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
genflags2str(pc->sub_flags, values));
}
break;
-
+
case Op_builtin:
print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin),
pc->expr_count);
@@ -3987,7 +3980,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
break;
case Op_concat:
- /* NB: concat_flag CSVAR only used in grammar, don't display it */
+ /* NB: concat_flag CSVAR only used in grammar, don't display it */
print_func(fp, "[expr_count = %ld] [concat_flag = %s]\n",
pc->expr_count,
(pc->concat_flag & CSUBSEP) != 0 ? "CSUBSEP" : "0");
@@ -4028,10 +4021,18 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
print_func(fp, " [do_reference = %s]\n",
pc->do_reference ? "true" : "false");
break;
-
+
+ case Op_comment:
+ print_memory(pc->memory, func, print_func, fp);
+ fprintf(fp, " [comment_type = %s]\n",
+ pc->memory->comment_type == EOL_COMMENT ?
+ "EOL" : "FULL");
+ break;
+
case Op_push_i:
case Op_push:
case Op_push_arg:
+ case Op_push_arg_untyped:
case Op_push_param:
case Op_push_array:
case Op_push_re:
@@ -4064,7 +4065,7 @@ do_trace_instruction(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
else
do_trace = false;
return false;
-}
+}
/* print_code --- print a list of instructions */
@@ -4148,7 +4149,7 @@ do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
*/
if (strlen(line) > 1
- && strncmp(line, "sa", 2) == 0)
+ && strncmp(line, "sa", 2) == 0)
continue;
fprintf(fp, "%s\n", line);
@@ -4164,9 +4165,9 @@ do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
int
do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
{
- const struct dbg_option *opt;
+ const struct dbg_option *opt;
char *name, *value;
-
+
if (arg == NULL) { /* display all available options and corresponding values */
for (opt = option_list; opt->name; opt++) {
if (opt->str_val != NULL)
@@ -4201,7 +4202,7 @@ do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
#ifdef HAVE_LIBREADLINE
-/* initialize_pager --- initialize our idea of the terminal size */
+/* initialize_pager --- initialize our idea of the terminal size */
void
initialize_pager(FILE *fp)
@@ -4237,9 +4238,9 @@ prompt_continue(FILE *fp)
if (quit_pager)
longjmp(pager_quit_tag, 1);
pager_lines_printed = 0;
-}
+}
-/* gprintf --- like fprintf but allows paging */
+/* gprintf --- like fprintf but allows paging */
int
gprintf(FILE *fp, const char *format, ...)
@@ -4254,13 +4255,13 @@ gprintf(FILE *fp, const char *format, ...)
#define GPRINTF_BUFSIZ 512
if (buf == NULL) {
buflen = GPRINTF_BUFSIZ;
- emalloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
+ emalloc(buf, char *, buflen * sizeof(char), "gprintf");
} else if (buflen - bl < GPRINTF_BUFSIZ/2) {
buflen += GPRINTF_BUFSIZ;
- erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
- }
+ erealloc(buf, char *, buflen * sizeof(char), "gprintf");
+ }
#undef GPRINTF_BUFSIZ
-
+
while (true) {
va_start(args, format);
nchar = vsnprintf(buf + bl, buflen - bl, format, args);
@@ -4274,14 +4275,14 @@ gprintf(FILE *fp, const char *format, ...)
break;
}
- /* enlarge buffer, and try again */
+ /* enlarge buffer, and try again */
buflen *= 2;
- erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
+ erealloc(buf, char *, buflen * sizeof(char), "gprintf");
}
bl = 0;
for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) {
- int sz = (int) (q - p);
+ int sz = (int) (q - p);
while (sz > 0) {
int cnt;
@@ -4301,7 +4302,7 @@ gprintf(FILE *fp, const char *format, ...)
sz -= screen_width;
assert(sz > 0);
p += cnt;
- }
+ }
}
fprintf(fp, "\n");
@@ -4316,7 +4317,7 @@ gprintf(FILE *fp, const char *format, ...)
static int
serialize_subscript(char *buf, int buflen, struct list_item *item)
{
- int bl = 0, nchar, i;
+ int bl, nchar, i;
NODE *sub;
nchar = snprintf(buf, buflen, "%d%c%d%c%s%c%d%c",
@@ -4326,11 +4327,12 @@ serialize_subscript(char *buf, int buflen, struct list_item *item)
return 0;
else if (nchar >= buflen) /* need larger buffer */
return nchar;
- bl += nchar;
+ bl = nchar;
for (i = 0; i < item->num_subs; i++) {
sub = item->subs[i];
- nchar = snprintf(buf + bl, buflen - bl, "%lu%c%s%c",
- (unsigned long) sub->stlen, FSEP, sub->stptr, FSEP);
+ nchar = snprintf(buf + bl, buflen - bl, "%lu%c%.*s%c",
+ (unsigned long) sub->stlen, FSEP,
+ (int) sub->stlen, sub->stptr, FSEP);
if (nchar <= 0)
return 0;
bl += nchar;
@@ -4342,12 +4344,12 @@ serialize_subscript(char *buf, int buflen, struct list_item *item)
-/* serialize --- convert a list structure to a byte stream and
+/* serialize_list--- convert a list structure to a byte stream and
* save in environment.
*/
static void
-serialize(int type)
+serialize_list(int type)
{
static char *buf = NULL;
static int buflen = 0;
@@ -4405,7 +4407,7 @@ serialize(int type)
if (buf == NULL) { /* first time */
buflen = SERIALIZE_BUFSIZ;
- emalloc(buf, char *, buflen + 2, "serialize");
+ emalloc(buf, char *, buflen + 1, "serialize");
}
bl = 0;
@@ -4414,7 +4416,7 @@ serialize(int type)
if (buflen - bl < SERIALIZE_BUFSIZ/2) {
enlarge_buffer:
buflen *= 2;
- erealloc(buf, char *, buflen + 2, "serialize");
+ erealloc(buf, char *, buflen + 1, "serialize");
}
#undef SERIALIZE_BUFSIZ
@@ -4457,7 +4459,7 @@ enlarge_buffer:
else
nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%s%c",
wd->number, FSEP, D_variable, FSEP, wd->sname, FSEP);
- cnum = wd->number;
+ cnum = wd->number;
commands = &wd->commands;
cndn = &wd->cndn;
break;
@@ -4497,7 +4499,7 @@ enlarge_buffer:
case WATCH:
/* recreate the `commands' command strings including the `commands'
* and `end' commands; command seperator is '\034'.
- * re-parsed in unserialize to recover the commands list.
+ * re-parsed in unserialize_list to recover the commands list.
* Alternatively, one could encode(serialize) each command and it's arguments.
*/
@@ -4515,10 +4517,10 @@ enlarge_buffer:
}
if (nchar > 0) { /* non-empty commands list */
- nchar += (strlen("commands ") + 20 + strlen("end") + 2); /* 20 for cnum (an int) */
+ nchar += (strlen("commands ") + 20 + strlen("end") + 1); /* 20 for cnum (an int) */
if (nchar > buflen - bl) {
buflen = bl + nchar;
- erealloc(buf, char *, buflen + 3, "serialize");
+ erealloc(buf, char *, buflen + 3, "serialize_list");
}
nchar = sprintf(buf + bl, "commands %d", cnum);
bl += nchar;
@@ -4548,14 +4550,14 @@ enlarge_buffer:
buf[bl++] = FSEP; /* field */
buf[bl++] = RSEP; /* record */
buf[bl] = '\0';
-
- /* condition expression */
+
+ /* condition expression */
if (cndn->expr) {
bl--; /* undo RSEP from above */
nchar = strlen(cndn->expr);
if (nchar > buflen - bl) {
buflen = bl + nchar;
- erealloc(buf, char *, buflen + 3, "serialize");
+ erealloc(buf, char *, buflen + 3, "serialize_list");
}
memcpy(buf + bl, cndn->expr, nchar);
bl += nchar;
@@ -4577,7 +4579,7 @@ enlarge_buffer:
break;
default:
break;
- }
+ }
}
if (bl > 0) /* non-empty list */
@@ -4600,7 +4602,7 @@ unserialize_commands(char *str, int str_len)
/* unserialize_list_item --- create a list_item structure from unserialized data */
-
+
static struct list_item *
unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int field_cnt)
{
@@ -4650,7 +4652,7 @@ unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int fi
l->subs = subs;
}
l->number = num; /* keep same item number across executions */
-
+
if (list == &watch_list) {
initialize_watch_item(l);
/* unserialize watchpoint `commands' */
@@ -4667,11 +4669,11 @@ unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int fi
} else
list->number = num;
- return l;
+ return l;
}
/* unserialize_breakpoint --- create a breakpoint structure from unserialized data */
-
+
static BREAKPOINT *
unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt)
{
@@ -4706,7 +4708,7 @@ unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt)
if (field_cnt > 6) /* unserialize breakpoint `commands' */
unserialize_commands(pstr[6], pstr_len[6]);
- if (field_cnt > 7) { /* condition expression */
+ if (field_cnt > 7) { /* condition expression */
char *expr;
expr = estrdup(pstr[7], pstr_len[7]);
if (parse_condition(D_break, b->number, expr) != 0)
@@ -4738,12 +4740,12 @@ unserialize_option(char **pstr, int *pstr_len, int field_cnt ATTRIBUTE_UNUSED)
return NULL;
}
-/* unserialize -- reconstruct list from serialized data stored in
+/* unserialize_list -- reconstruct list from serialized data stored in
* environment variable.
*/
static void
-unserialize(int type)
+unserialize_list(int type)
{
char *val;
char *p, *q, *r, *s;
@@ -4774,7 +4776,7 @@ unserialize(int type)
#ifdef GAWKDEBUG
fatal("Increase MAX_FIELD and recompile.\n");
#else
- return;
+ return;
#endif
}
@@ -4864,7 +4866,7 @@ has_break_or_watch_point(int *pnum, bool any)
/* N.B: breakpoints and watchpoints get numbers from a single
* counter/sequencer watch_list.number.
- */
+ */
for (b = breakpoints.next; b != &breakpoints; b = b->next) {
if (b->number == *pnum)
@@ -4899,7 +4901,7 @@ do_commands(CMDARG *arg, int cmd)
static struct list_item *w;
static struct commands_item *commands;
struct commands_item *c;
-
+
if (cmd == D_commands) {
int num = -1, type;
if (arg == NULL)
@@ -4947,7 +4949,7 @@ do_commands(CMDARG *arg, int cmd)
c->next = NULL;
c->cmd = cmd;
- /* N.B.: first arg is the command string, see command.y */
+ /* N.B.: first arg is the command string, see command.y */
c->cmd_string = arg->a_string;
c->arg = arg->next; /* actual arguments to the command */
efree(arg);
@@ -5041,19 +5043,19 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
if (value == NULL)
tmp[i] = Nnull_string; /* FIXME: goto done ? */
else if (value->type == Node_var_array) {
- d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
- name, subs->stptr);
+ d_error(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
+ name, (int) subs->stlen, subs->stptr);
goto done;
- } else
+ } else
tmp[i] = value;
} else {
if (value == NULL) {
- d_error(_("[\"%s\"] not in array `%s'"),
- subs->stptr, name);
+ d_error(_("[\"%.*s\"] not in array `%s'"),
+ (int) subs->stlen, subs->stptr, name);
goto done;
} else if (value->type != Node_var_array) {
- d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
- name, subs->stptr);
+ d_error(_("attempt to use scalar `%s[\"%.*s\"]' as array"),
+ name, (int) subs->stlen, subs->stptr);
goto done;
} else {
r = value;
@@ -5062,7 +5064,7 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
}
}
}
- break;
+ break;
case D_node:
tmp[i] = a->a_node;
break;
@@ -5118,7 +5120,7 @@ static int
open_readfd(const char *file)
{
int fd;
-
+
fd = open(file, O_RDONLY);
if (fd <= INVALID_HANDLE)
return INVALID_HANDLE;
@@ -5150,14 +5152,14 @@ find_option(char *name)
void
option_help()
{
- const struct dbg_option *opt;
+ const struct dbg_option *opt;
for (opt = option_list; opt->name; opt++)
fprintf(out_fp, "\t%-15.15s - %s\n", opt->name, _(opt->help_txt));
}
#ifdef HAVE_LIBREADLINE
-
+
/* option_generator --- generator function for option name completion */
char *
@@ -5219,7 +5221,7 @@ set_gawk_output(const char *file)
output_is_tty = os_isatty(fileno(stderr));
return;
}
-
+
if (strncmp(cp, "fd/", 3) == 0) {
cp += 3;
fd = (int) strtoul(cp, NULL, 10);
@@ -5237,7 +5239,7 @@ set_gawk_output(const char *file)
if (fd > INVALID_HANDLE && fp == NULL) {
fp = fdopen(fd, "w");
if (fp == NULL)
- close(fd);
+ close(fd);
}
} else {
@@ -5268,7 +5270,7 @@ set_prompt(const char *value)
dbg_prompt = dgawk_prompt;
}
-/* set_option_flag --- convert option string to flag value */
+/* set_option_flag --- convert option string to flag value */
static int
set_option_flag(const char *value)
@@ -5352,7 +5354,7 @@ read_commands_string(const char *prompt ATTRIBUTE_UNUSED)
return NULL;
p = (char *) commands_string;
- end = (char *) commands_string + commands_string_len;
+ end = (char *) commands_string + commands_string_len;
for (; p < end; p++) {
if (*p == line_sep) {
line = estrdup(commands_string, p - commands_string);
@@ -5374,7 +5376,7 @@ static void
save_options(const char *file)
{
FILE *fp;
- const struct dbg_option *opt;
+ const struct dbg_option *opt;
fp = fopen(file, "w");
if (fp == NULL)
@@ -5413,7 +5415,7 @@ close_all()
close_extensions();
- set_gawk_output(NULL); /* closes output_fp if not stdout */
+ set_gawk_output(NULL); /* closes output_fp if not stdout */
}
/* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
@@ -5463,7 +5465,7 @@ execute_code(volatile INSTRUCTION *code)
/* We use one global stack for all contexts.
* Save # of items in stack; in case of
* a fatal error, pop stack until it has that many items.
- */
+ */
save_stack_size = (stack_ptr - stack_bottom) + 1;
do_flags = false;
@@ -5499,13 +5501,13 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
int ret;
int save_flags = do_flags;
SRCFILE *the_source;
-
+
if (prog_running) {
this_frame = find_frame(0);
this_func = this_frame->func_node;
}
- install_params(this_func); /* expose current function parameters to eval */
+ install_params(this_func); /* expose current function parameters to eval */
ctxt = new_context();
ctxt->install_func = append_symbol; /* keep track of newly installed globals */
push_context(ctxt);
@@ -5530,9 +5532,9 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
eval->func_name = NULL; /* not needed, func_body already assigned */
(eval + 1)->expr_count = 0;
eval->nexti = bcalloc(Op_stop, 1, 0);
-
+
} else {
- /* execute as a part of the current function */
+ /* execute as a part of the current function */
int i;
INSTRUCTION *t;
@@ -5545,7 +5547,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
/* add or append eval locals to the current frame stack */
ecount = f->param_cnt; /* eval local count */
pcount = this_func->param_cnt;
-
+
if (ecount > 0) {
if (pcount == 0)
emalloc(this_frame->stack, NODE **, ecount * sizeof(NODE *), "do_eval");
@@ -5585,7 +5587,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
/* else
fatal error */
- if (this_func != NULL && ecount > 0) {
+ if (this_func != NULL && ecount > 0) {
int i;
/* undo frame manipulation from above */
@@ -5640,7 +5642,7 @@ GDB Documentation:
immediately for syntactic correctness, and to determine whether symbols
in it have referents in the context of your breakpoint. If expression
uses symbols not referenced in the context of the breakpoint, GDB prints
-an error message:
+an error message:
No symbol "foo" in current context.
*/
@@ -5676,7 +5678,7 @@ parse_condition(int type, int num, char *expr)
cndn = &b->cndn;
rp = find_rule(b->src, b->bpi->source_line);
if (rp != NULL && rp->opcode == Op_func)
- this_func = rp->func_body;
+ this_func = rp->func_body;
} else if (type == D_watch && (w = find_item(&watch_list, num)) != NULL) {
cndn = &w->cndn;
this_func = find_frame(cur_frame)->func_node;
@@ -5696,7 +5698,7 @@ parse_condition(int type, int num, char *expr)
do_flags = false;
ret = parse_program(&code);
do_flags = save_flags;
- remove_params(this_func);
+ remove_params(this_func);
pop_context();
if (ret != 0 || invalid_symbol) {
@@ -5705,7 +5707,7 @@ parse_condition(int type, int num, char *expr)
}
/* condition expression is parsed as awk pattern without
- * any action. The code is then modified to end up with
+ * any action. The code is then modified to end up with
* a `1.0' on stack when the expression is true, `0.0' otherwise.
*/
@@ -5720,7 +5722,7 @@ parse_condition(int type, int num, char *expr)
it->nexti = bcalloc(Op_jmp, 1, 0);
it->nexti->target_jmp = stop;
it->nexti->nexti = rule->lasti;
-
+
it = rule->lasti; /* Op_no_op, target for Op_jmp_false */
assert(it->opcode == Op_no_op);
it->opcode = Op_push_i;
@@ -5798,13 +5800,13 @@ push_cmd_src(
/* eof_status = EXIT_FATAL - exit with status EXIT_FATAL on EOF or error.
* = EXIT_FAILURE - exit status EXIT_FAILURE on error.
- * = EXIT_SUCCESS - don't exit on EOF or error.
+ * = EXIT_SUCCESS - don't exit on EOF or error.
*/
cs->eof_status = eofstatus;
cs->str = NULL;
cs->next = cmd_src;
cmd_src = cs;
-
+
input_fd = fd;
input_from_tty = istty;
read_a_line = readfunc;
diff --git a/depcomp b/depcomp
index fc98710e..b6872321 100755
--- a/depcomp
+++ b/depcomp
@@ -1,9 +1,9 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
-scriptversion=2013-05-30.07; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -251,41 +251,6 @@ hp)
exit 1
;;
-sgi)
- if test "$libtool" = yes; then
- "$@" "-Wp,-MDupdate,$tmpdepfile"
- else
- "$@" -MDupdate "$tmpdepfile"
- fi
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
-
- if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
- echo "$object : \\" > "$depfile"
- # Clip off the initial element (the dependent). Don't try to be
- # clever and replace this with sed code, as IRIX sed won't handle
- # lines with more than a fixed number of characters (4096 in
- # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
- # the IRIX cc adds comments like '#:fec' to the end of the
- # dependency line.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
- | tr "$nl" ' ' >> "$depfile"
- echo >> "$depfile"
- # The second pass generates a dummy entry for each header file.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
- >> "$depfile"
- else
- make_dummy_depfile
- fi
- rm -f "$tmpdepfile"
- ;;
-
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
@@ -786,6 +751,6 @@ exit 0
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 00000000..e12f5de0
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,95 @@
+#
+# doc/CMakeLists.txt --- CMake input file for gawk
+#
+# Copyright (C) 2013
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with CMake to produce Makefile
+
+MACRO(DocDependency outfile)
+ add_dependencies(doc ${outfile})
+ add_custom_target(
+ ${outfile}
+ DEPENDS ${ARGN}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${CMAKE_SOURCE_DIR}/cmake/docmaker ${outfile} ${ARGN}
+ )
+ENDMACRO(DocDependency)
+
+find_program(TEXI2DVI_CONVERTER texi2dvi)
+if (TEXI2DVI_CONVERTER)
+ add_custom_target(doc)
+ DocDependency(gawk.texi gawktexi.in rflashlight.eps api-figure1.fig api-figure2.fig api-figure3.fig general-program.fig process-flow.fig)
+ DocDependency(rflashlight.eps)
+ DocDependency(api-figure1.fig)
+ DocDependency(api-figure2.fig)
+ DocDependency(api-figure3.fig)
+ DocDependency(general-program.fig)
+ DocDependency(process-flow.fig)
+ DocDependency(gawk.dvi gawk.texi)
+ DocDependency(gawk.info gawk.texi)
+ DocDependency(gawkinet.dvi gawkinet.texi)
+ DocDependency(gawkinet.info gawkinet.texi)
+ DocDependency(gawkinet.texi statist.eps)
+ DocDependency(gawk.1.ps gawk.1)
+ DocDependency(igawk.1.ps igawk.1)
+ find_program(DVIPS_CONVERTER dvips)
+ if (DVIPS_CONVERTER)
+ DocDependency(gawk.ps gawk.dvi)
+ DocDependency(gawkinet.ps gawkinet.dvi)
+ find_program(PS2PDF_CONVERTER ps2pdf)
+ if (PS2PDF_CONVERTER)
+ DocDependency(gawk.1.pdf gawk.1.ps)
+ DocDependency(igawk.1.pdf igawk.1.ps)
+ DocDependency(gawk.pdf gawk.ps)
+ DocDependency(gawkinet.pdf gawkinet.ps)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gawk.1.pdf DESTINATION doc)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/igawk.1.pdf DESTINATION doc)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gawk.info DESTINATION doc)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gawk.pdf DESTINATION doc)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gawkinet.info DESTINATION doc)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gawkinet.pdf DESTINATION doc)
+
+ set(CARDSRC macros cardfonts colors awkcard.tr)
+ set(CARDSRC_N macros cardfonts no.colors awkcard.tr)
+ set(CARDFILES ${CARDSRC} ad.block awkcard.in setter.outline)
+ DocDependency(awkcard.tr awkcard.in)
+ DocDependency(awkcard.nc ${CARDFILES})
+ DocDependency(awkcard.ps ${CARDFILES})
+ DocDependency(awkcard.pdf awkcard.ps)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/awkcard.pdf DESTINATION doc)
+
+ else()
+ message(WARNING "Found no ps2pdf tool; no doc will be generated")
+ install(CODE "MESSAGE(\"doc generated only in .ps files\")")
+ endif()
+ else()
+ message(WARNING "Found no dvips tool; no doc will be generated")
+ install(CODE "MESSAGE(\"doc generated only in .dvi files and man pages in .ps files\")")
+ endif()
+else()
+ message(WARNING "Found no texi2dvi tool; no doc will be generated")
+ add_custom_command(
+ TARGET doc
+ COMMAND echo no doc generated because of missing texi2dvi
+ )
+endif()
+
diff --git a/doc/ChangeLog b/doc/ChangeLog
index bf996749..a9433d18 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,12 +1,128 @@
+2017-07-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * texinfo.tex: Pull in latest from Texinfo SVN.
+
+2017-06-19 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in (Memory Allocation Functions and Convenience Macros):
+ Document new ezalloc API macro.
+
+2017-06-18 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkworkflow.texi: Fix typo.
+
2017-06-15 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Expand tab characters.
+2017-06-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in (Checking for MPFR): Fix typo.
+
+2017-05-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document PROCINFO["argv"].
+
+2017-05-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Checking for MPFR): New node on checking if
+ gawk was invoked with -M.
+
+2017-05-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document FIELDWIDTHS much better, including how
+ it works in corner cases. Some general organizational improvements
+ in this chunk of text.
+
+2017-04-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Improve documentation of --source option.
+
+2017-04-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document --disable-mpfr configure option.
+
+2017-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Improve documentation of the intdiv() function.
+
+2017-04-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * it: New directory with Italian translation of the manual.
+ * Makefile.am (EXTRA_DIST): Add `it' and wordlist2.
+
+2017-04-12 Manuel Collado <m-collado@users.sourceforge.net>
+
+ * gawktexi.in, gawk.1: Small clarification of the patsplit behavior.
+
+2017-04-11 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Minor style edits.
+
+2017-04-10 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Document FIELDWIDTHS enhancement to support an optional
+ field skip prefix. Document new PROCINFO["FS"] value "API".
+ Document new get_record field_width argument that enables the API
+ parser to override the default field parsing mechanism.
+
+2017-04-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ * using-git.texi: Removed.
+ * gawkworkflow.texi: Added. New file.
+ * wordlist2: New file.
+ * Makefile.am: Revised for new document. Copyright years updated.
+
+ * gawkworkflow.texi: Fix some spelling errors. :-(
+ * wordlist2: Updated.
+ * Makefile.am: Fix spell checking. :-(
+
+2017-03-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawk.1: Document new PROCINFO["FS"] value "API".
+
+2017-03-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkcard.in: Document FIELDWIDTHS enhancement to support an optional
+ field skip prefix.
+ * gawk.1: Ditto.
+
+2017-03-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Improve the discussion of quoting on
+ MS-Windows. Original text contributed by
+ Vincent Belaiche <vincent.belaiche@gmail.com>.
+
+2017-03-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Additional small writing tip in the notes
+ after the @bye.
+
+2017-03-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Edits preparatory to release.
+
+2017-02-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.1: "timezone" --> "time zone".
+ * awkcard.in: Update copyright year.
+
+2017-02-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawk.1: Document new mktime optional 2nd utc-flag argument.
+ * gawktex.in: Ditto.
+ * awkcard.in: Ditto.
+
2017-02-13 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Fix two typos.
* wordlist.txt: Update.
+ Related:
+
+ * gawktexi.in: Fix more typos.
+ * wordlist.txt: Update again.
+
2017-01-27 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Update UPDATE-MONTH and copyright years.
@@ -16,6 +132,68 @@
* gawktexi.in: Comment out stuff about awk.info, since that
domain is now gone.
+2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Explain why an API extension function might want
+ to use the AWK_STRNUM type to return data.
+
+2016-12-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Update API table of type requested / type returned.
+
+2016-12-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Minor edits after merging branches and some
+ additional work in the code.
+
+2016-12-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Further API clarifications and edits, add a
+ section on backwards compatibility.
+
+2016-12-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Update description of awk_ext_func_t structure,
+ again.
+
+2016-12-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Update description of awk_ext_func_t structure.
+
+2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Document strnum changes as relates to API.
+ Still stuff left to do -- tables for type conversions need
+ to be updated to show new strnum and regex rows and columns.
+
+2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Remove make_regex and replace it with make_const_regex
+ and make_malloced_regex.
+
+2016-12-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Document new flatten_array_typed API function, and
+ indicate that the old flatten_array function has been superseded.
+
+2016-11-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document typed regex changes as relates to API.
+ Still stuff left to do.
+
+2016-11-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Finish off discussion of strongly typed regexp
+ constants and put it in the right place in the manual. A few other
+ minor fixes.
+ * wordlist: Updated.
+
+2016-11-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Variable Typing): Rework and improve discussion
+ of strings, numbers, and strnums. Update description of strnum
+ in other places.
+
2016-11-10 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Fix example use of dcngegttext.
@@ -30,6 +208,18 @@
Works better for Info, text, and HTML. Thanks to
Marco Curreli <marcocurreli@tiscali.it> for the report.
+2016-11-04 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Fix a spelling error.
+ * wordlist: Update.
+
+2016-10-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document that negative arguments are not allowed
+ for bitwise functions. Add a sidebar explaining it a bit and
+ also showing the difference with and without -M.
+ * gawk.1: Document that negative arguments are not allowed.
+
2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Remove references to MS-DOS and OS/2,
@@ -51,11 +241,18 @@
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
+ * gawktexi.in (POSIX String Comparison): Update for new
+ spec where == and != use strcmp, rest use strcoll. Thanks to
+ Chet Ramey for pointing me at the new rules.
+
+2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
+
* 4.1.4: Release tar ball made.
2016-08-24 Arnold D. Robbins <arnold@skeeve.com>
* wordlist: Add more words.
+ * gawktexi.in: Fix more typos.
2016-08-23 Arnold D. Robbins <arnold@skeeve.com>
@@ -65,6 +262,18 @@
* gawktexi.in: Fix typos, adjust update date.
* awkcard.in: Update copyright years.
+2016-08-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ Restored doc on typed regexes.
+
+ * gawk.1, gawktexi.in: Updated.
+
+2016-08-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ Remove typed regexes until they can be done properly.
+
+ * gawk.1, gawktexi.in: Updated.
+
2016-08-01 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Mark DJGPP port as unsupported.
@@ -73,6 +282,12 @@
* gawktexi.in: Fix a typo. Thanks to Marco Curreli for reporting.
+2016-07-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document return value of close on a pipe now like
+ that of system: exit status, status + 256 for signal, or
+ status + 512 for signal with core dump.
+
2016-07-18 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Fix a typo. Thanks to Antonio Colombo for reporting.
@@ -86,6 +301,16 @@
* gawktexi.in (Auto-set): Add example use of multiply function.
+2016-06-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.1: Typo fix. Thanks to Antonio Giovanni Colombo
+ for noticing.
+
+2016-06-15 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.1: Document typeof(), update modified date.
+ * awkcard.in: Document typeof().
+
2016-06-10 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Fix a typo, and replace hard-coded "section" with
@@ -94,6 +319,15 @@
(UPDATE-MONTH, PATCHLEVEL): Update to current before release.
* awkcard.in: Update version.
+2016-05-30 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Replace num_expected_args with max_expected_args.
+ Explain what it's used for.
+
+2016-05-25 Manuel Collado <mcollado2011@gmail.com>.
+
+ * gawktexi.in: Document new 'nonfatal' API function.
+
2016-05-25 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Typo fix in extension section, thanks to
@@ -110,6 +344,12 @@
out since 2001, index RFCs, change function name convention to
match main gawktexi.in. Update the update month.
+2016-04-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Two-way I/O): Document that writing to the closed
+ write end of a two way pipe or reading from the closed read end
+ can be made nonfatal.
+
2016-04-04 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in, gawkinet.texi: Enable use of braces in
@@ -120,6 +360,11 @@
* gawktexi.in (Two-way I/O): Document that closing the "from"
end waits for the process to exit, so it's not such a great idea.
+2016-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawkinet.texi: Small update about end of line vs full
+ comments when pretty printing.
+
2016-03-21 Arnold D. Robbins <arnold@skeeve.com>
* gawkinet.texi: Update UDP client and discussion, update
@@ -152,6 +397,8 @@
dlward134@gmail.com. Added an example of use of rewind(), also
per suggestion from David Ward.
* gawktexi.in: Update info about Texinfo versions.
+ * gawktexi.in (Limitations): Fix Heisenberg Physics example and
+ spelling of Heisenberg's name. Thanks to Hermann Peifer.
2016-02-14 Arnold D. Robbins <arnold@skeeve.com>
@@ -161,6 +408,14 @@
Use @sup for superscripts where possible.
* texinfo.tex: Updated.
+2016-02-05 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.texi: Document that optimization in now the default,
+ there are new -s/--no-optimize options and that
+ pretty-printing and profiling disable optimization.
+ * gawk.1: Ditto.
+ * awkcard.in: Ditto.
+
2016-02-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
* gawktexi.in (Command-Line Options): Change wording of -M description
@@ -193,17 +448,39 @@
* ChangeLog: Remove spurious whitespace.
+ Unrelated:
+
+ * gawk.1: Restore text on PROCINFO["RETRY"] and fix up the
+ formatting while we're at it. Thanks to Andrew Schorr for
+ pointing out the problem.
+
2016-01-13 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in (Array Sorting Functions): Add an example of
using a function name with asort(). Response to bug report
Stephane Goujet <stephane.goujet@wanadoo.fr>.
+2016-01-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Finish documenting that --pretty-print
+ doesn't run the program. Thanks to Antonio
+ Giovanni Colombo for the report and patch.
+
+2016-01-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document that GNU/Linux on Alpha is no
+ longer supported.
+
2015-12-27 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Fix some @c endfile. Thanks to Antonio
Giovanni Colombo for the report and patch.
+2015-12-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Add PROCINFO["NONFATAL"] to the list for PROCINFO.
+ * gawk.1: Ditto.
+
2015-12-18 Arnold D. Robbins <arnold@skeeve.com>
* gawk.1: Update description of PROCINFO, and sort it properly.
@@ -217,6 +494,11 @@
2015-11-15 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Minor edits.
+ * gawk.1: Revise \x to maximum of two digits.
+
+2015-11-04 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (pdf-local): Remove igawk.1.pdf. Ooops.
2015-10-30 Arnold D. Robbins <arnold@skeeve.com>
@@ -229,6 +511,10 @@
* gawk.1: Put commas outside quoting in regexps to avoid
confusion. Thanks to Mike Frysinger <vapier@gentoo.org>.
+2015-10-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * awkcard.in: Fix tbl complaint.
+
2015-10-07 Arnold D. Robbins <arnold@skeeve.com>
* texinfo.tex: Updated to a working version.
@@ -260,11 +546,26 @@
* gawktexi.in: Typo fixes in Appendix A.
Thanks to Antonio Colombo.
+2015-07-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Small typo fix; thanks to Antonio Colombo
+ for noticing.
+
2015-07-01 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Update info on Quiktrim awk; thanks to
Antonio Colombo for the pointer.
+2015-06-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Limitations): Document that sometimes the
+ debugger can affect the program being run.
+ Thanks to Hermann Peifer for the test case.
+
+2015-06-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Update description of values returned by typeof.
+
2015-06-19 Arnold D. Robbins <arnold@skeeve.com>
* gawkinet.info: Fix an old arnold@gnu.org.
@@ -290,6 +591,13 @@
* gawktexi.in: Add another pithy quote from Chet Ramey. Currently
commented out.
+2015-05-31 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Revised description of default field parsing
+ for POSIX. Newline is now a separator also. Thanks to
+ Michael Klement <michael.klement@usa.net> for pointing this out.
+ * gawk.1: Updated too.
+
2015-05-30 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in (Bitwise Functions): Update results of testbits.awk.
@@ -314,15 +622,33 @@
* gawktexi.in: Fix description of nextfile within a function. Sigh.
+2015-05-15 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in (Undocumented): Describe the new PROCINFO["argv"] array.
+
2015-05-14 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in (Bugs): Add that email should be in plain
text and not in HTML. Sigh.
+2015-05-11 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Add doc on conversions for strongly typed
+ regexp variables.
+
+2015-05-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Add initial documentation for strongly typed
+ regexps and for `typeof'.
+
2015-04-29 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.2: Release tar ball made.
+2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Undocumented): More info added.
+
2015-04-08 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Update feature history section.
@@ -344,6 +670,11 @@
* gawktexi.in: Fix a figure caption. Thanks to Antonio Colombo
for pointing this out.
+ * gawktexi.in: Additional typo fix, also thanks to Antonio.
+
+2015-04-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in, gawk.1, awkcard.in: Name change: div() --> intdiv().
2015-03-31 Arnold D. Robbins <arnold@skeeve.com>
@@ -351,10 +682,17 @@
indirectly. Small additional fix relating to rand(). Thanks
to Antonio Colombo.
+2015-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Minor edits.
+
2015-03-24 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Minor fixes from Antonio Colombo and new exercise
in chapter 16.
+ * gawk.1: Minor edits.
+ * gawktexi.in: Edits in material on errno and retryable and get_file
+ API.
2015-03-17 Andrew J. Schorr <aschorr@telemetry-investments.com>
@@ -368,6 +706,12 @@
Thanks to Nicholas Mills <nlmills@clemson.edu> for pointing out
the issue.
+2015-03-08 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Briefly describe that nonfatal I/O overrides
+ GAWK_SOCK_RETRIES, in the env var part and in the nonfatal I/O
+ part.
+
2015-03-01 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Change quotes to @dfn for pseudorandom.
@@ -424,6 +768,7 @@
2015-02-08 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: O'Reilly fixes.
+ Make non-fatal i/o use "NONFATAL".
2015-02-06 Arnold D. Robbins <arnold@skeeve.com>
@@ -432,6 +777,7 @@
2015-02-04 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: O'Reilly fixes.
+ * gawktexi.in: Update various version-related bits of info.
2015-02-02 Arnold D. Robbins <arnold@skeeve.com>
@@ -461,7 +807,7 @@
2015-01-25 Arnold D. Robbins <arnold@skeeve.com>
- * gawktexi.in: Fix a bad URL.
+ * gawktexi.in: Fix a bad URL. And another one.
More O'Reilly fixes.
2015-01-23 Arnold D. Robbins <arnold@skeeve.com>
@@ -483,12 +829,40 @@
* gawkinet.texi: Fix capitalization in document title.
* gawktexi.in: Here we go again: Starting on more O'Reilly fixes.
+2014-12-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Add info that nonfatal I/O works with stdout and
+ stderr. Revise version info and what was added when.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Improve get_file documentation.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Replace "Retrying I/O" with "Retrying Input", since this
+ feature pertains to input, not output.
+
+2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Document the get_file API function.
+
+2015-01-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawk.1: Document new features PROCINFO["errno"] and
+ PROCINFO["input", "RETRY"], and new getline return value of -2.
+ * gawktexi.in: Ditto.
+
2014-12-26 Antonio Giovanni Colombo <azc100@gmail.com>
* gawktexi.in (Glossary): Really sort the items.
2014-12-24 Arnold D. Robbins <arnold@skeeve.com>
+ * gawktexi.in: Start documenting nonfatal output.
+
+2014-12-24 Arnold D. Robbins <arnold@skeeve.com>
+
* gawktexi.in: Add one more paragraph to new foreword.
* gawktexi.in: Fix exponentiation in TeX mode. Thanks to
Marco Curreli by way of Antonio Giovanni Colombo.
@@ -520,6 +894,11 @@
* gawktexi.in: Various minor fixes and updates.
+2014-11-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Update that TZ env. var can influnce mktime
+ in running program. Thanks to Hermann Peifer.
+
2014-11-19 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Update that RFC 4180 documents CSV data.
@@ -533,6 +912,11 @@
* gawktexi.in: Comment out that I need an owner for awk.info.
I may have found one or two people.
+2014-10-29 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawktexi.in: Document new extras directory containing shell startup
+ files to manipulate AWKPATH and AWKLIBPATH environment variables.
+
2014-10-28 Arnold D. Robbins <arnold@skeeve.com>
* gawk.1: Clarification that debugger reads stdin.
@@ -546,6 +930,7 @@
2014-10-25 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Minor typo fixes.
+ Fix discussion of \x, per note from Antonio Colombo.
2014-10-17 Arnold D. Robbins <arnold@skeeve.com>
@@ -587,10 +972,25 @@
* gawktexi.in: Pretty much done!
+ Unrelated:
+
+ * gawktexi.in: Fix braino in awk version of div function.
+ Thanks to Katie Wasserman for the catch.
+
2014-10-01 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: More fixes after reading through the MS.
+ Unrelated:
+
+ * gawktexi.in: Add Katie Wasserman's program to compute
+ the digits of PI.
+
+ Unrelated:
+
+ * gawktexi.in: Document the differences between profiling
+ and pretty printing.
+
2014-09-30 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: More fixes after reading through the MS.
@@ -686,6 +1086,10 @@
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.
@@ -719,6 +1123,10 @@
* 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.
+
2014-08-06 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Misc minor additions.
@@ -733,6 +1141,18 @@
* gawktexi.in: Fix doc for API get_record - errcode needs to
be greater than zero.
+2014-07-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Numeric Functions): For `div()', clarify
+ truncation is towards zero. Thanks to Michal Jaegermann
+ for pointing out the need to clarify this.
+
+2014-07-10 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Numeric Functions): Document new `div()' function.
+ (Arbitrary Precision Integers): Document raison d'etre for div().
+ * gawk.1, awkcard.in: Document `div()'.
+
2014-07-04 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in (Bracket Expressions): Add a note about how to
@@ -743,6 +1163,11 @@
* gawktexi.in: Update permissions on copyright page per
latest maintain.texi. Add GPL to print version of book.
+2014-06-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in: Document that --pretty-print no longer runs the
+ program. Remove mention of GAWK_NO_PP_RUN env var.
+
2014-06-22 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: Typo fixes and minor corrections.
@@ -1039,7 +1464,7 @@
2013-12-26 Arnold D. Robbins <arnold@skeeve.com>
* gawktexi.in: More minor additions / fixes.
- (Bugs): Add John Malmberg for VMS.
+ (Bugs): Add John Malmberg for VMS. Other minor edits.
2013-12-25 Arnold D. Robbins <arnold@skeeve.com>
@@ -1113,6 +1538,11 @@
* gawktexi.in (FN, FFN, DF,DDF, PVERSION, CTL): Remove macros.
They have no alternate versions and are just in the way.
+2013-08-15 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.1: Document that ENVIRON updates affect the environment.
+ * gawktexi.in: Ditto.
+
2013-06-27 Arnold D. Robbins <arnold@skeeve.com>
* texinfo.tex: Update from Karl, fixes a formating problem.
diff --git a/doc/Makefile.am b/doc/Makefile.am
index bda97de7..0b9316bc 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,7 +1,7 @@
#
# doc/Makefile.am --- automake input file for gawk
#
-# Copyright (C) 2000, 2001, 2002, 2004, 2005, 2007, 2010, 2011
+# Copyright (C) 2000, 2001, 2002, 2004, 2005, 2007, 2010, 2011, 2016, 2017
# the Free Software Foundation, Inc.
#
# This file is part of GAWK, the GNU implementation of the
@@ -24,9 +24,9 @@
## process this file with automake to produce Makefile.in
-info_TEXINFOS = gawk.texi gawkinet.texi
+info_TEXINFOS = gawk.texi gawkinet.texi gawkworkflow.texi
-man_MANS = gawk.1 igawk.1
+man_MANS = gawk.1
EXTRA_DIST = ChangeLog ChangeLog.0 README.card ad.block setter.outline \
awkcard.in awkforai.txt texinfo.tex cardfonts \
@@ -41,17 +41,18 @@ EXTRA_DIST = ChangeLog ChangeLog.0 README.card ad.block setter.outline \
gawktexi.in sidebar.awk \
general-program.eps general-program.fig general-program.pdf \
general-program.png general-program.txt \
+ it \
process-flow.eps process-flow.fig process-flow.pdf \
process-flow.png process-flow.txt \
macros colors no.colors $(man_MANS) \
lflashlight-small.xpic lflashlight.eps lflashlight.pdf \
rflashlight-small.xpic rflashlight.eps rflashlight.pdf \
statist.jpg statist.eps statist.pdf \
- wordlist \
+ wordlist wordlist2 \
bc_notes
# Get rid of generated files when cleaning
-CLEANFILES = *.ps *.html *.dvi *~ awkcard.nc awkcard.tr gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf igawk.1.pdf
+CLEANFILES = *.ps *.html *.dvi *~ awkcard.nc awkcard.tr gawk.pdf gawkinet.pdf gawkworkflow.pdf awkcard.pdf gawk.1.pdf
MAKEINFO = @MAKEINFO@ --no-split --force
@@ -77,9 +78,9 @@ AWKCARD = awkcard.ps
gawk.texi: $(srcdir)/gawktexi.in $(srcdir)/sidebar.awk
awk -f $(srcdir)/sidebar.awk < $(srcdir)/gawktexi.in > gawk.texi
-postscript: gawk.ps gawkinet.ps gawk.1.ps igawk.1.ps $(AWKCARD)
+postscript: gawk.ps gawkinet.ps gawkworkflow.ps gawk.1.ps $(AWKCARD)
-pdf-local: postscript gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf igawk.1.pdf
+pdf-local: postscript gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf
gawk.ps: gawk.dvi
TEXINPUTS=$(srcdir): dvips -o gawk.ps gawk.dvi
@@ -87,18 +88,15 @@ gawk.ps: gawk.dvi
gawkinet.ps: gawkinet.dvi
TEXINPUTS=$(srcdir): dvips -o gawkinet.ps gawkinet.dvi
+gawkworkflow.ps: gawkworkflow.dvi
+ TEXINPUTS=$(srcdir): dvips -o gawkworkflow.ps gawkworkflow.dvi
+
gawk.1.ps: gawk.1
-groff -man $(srcdir)/gawk.1 > gawk.1.ps
gawk.1.pdf: gawk.1.ps
ps2pdf gawk.1.ps gawk.1.pdf
-igawk.1.ps: igawk.1
- -groff -man $(srcdir)/igawk.1 > igawk.1.ps
-
-igawk.1.pdf: igawk.1.ps
- ps2pdf igawk.1.ps igawk.1.pdf
-
awkcard.tr: awkcard.in
sed 's:SRCDIR:$(srcdir):' < $(srcdir)/awkcard.in > awkcard.tr
@@ -111,6 +109,14 @@ awkcard.nc: $(CARDFILES)
awkcard.pdf: awkcard.ps
ps2pdf awkcard.ps awkcard.pdf
-spell:
+spell: spellmanual spellworkflow
+
+spellmanual:
+ @echo ==== gawktexi.in ====;
export LC_ALL=C ; spell "$(srcdir)"/gawktexi.in | \
sort -u | comm -23 - "$(srcdir)"/wordlist
+
+spellworkflow:
+ @echo ==== gawkworkflow.texi ====
+ export LC_ALL=C ; spell "$(srcdir)"/gawkworkflow.texi | \
+ sort -u | comm -23 - "$(srcdir)"/wordlist2
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 96103d72..078a006c 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -17,7 +17,7 @@
#
# doc/Makefile.am --- automake input file for gawk
#
-# Copyright (C) 2000, 2001, 2002, 2004, 2005, 2007, 2010, 2011
+# Copyright (C) 2000, 2001, 2002, 2004, 2005, 2007, 2010, 2011, 2016, 2017
# the Free Software Foundation, Inc.
#
# This file is part of GAWK, the GNU implementation of the
@@ -116,14 +116,14 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
- $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libsigsegv.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -173,13 +173,14 @@ AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
am__v_texidevnull_0 = > /dev/null
am__v_texidevnull_1 =
-INFO_DEPS = $(srcdir)/gawk.info $(srcdir)/gawkinet.info
+INFO_DEPS = $(srcdir)/gawk.info $(srcdir)/gawkinet.info \
+ $(srcdir)/gawkworkflow.info
am__TEXINFO_TEX_DIR = $(srcdir)
-DVIS = gawk.dvi gawkinet.dvi
-PDFS = gawk.pdf gawkinet.pdf
-PSS = gawk.ps gawkinet.ps
-HTMLS = gawk.html gawkinet.html
-TEXINFOS = gawk.texi gawkinet.texi
+DVIS = gawk.dvi gawkinet.dvi gawkworkflow.dvi
+PDFS = gawk.pdf gawkinet.pdf gawkworkflow.pdf
+PSS = gawk.ps gawkinet.ps gawkworkflow.ps
+HTMLS = gawk.html gawkinet.html gawkworkflow.html
+TEXINFOS = gawk.texi gawkinet.texi gawkworkflow.texi
TEXI2DVI = texi2dvi
TEXI2PDF = $(TEXI2DVI) --pdf --batch
MAKEINFOHTML = $(MAKEINFO) --html
@@ -287,6 +288,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POSUB = @POSUB@
+RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -352,8 +354,8 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-info_TEXINFOS = gawk.texi gawkinet.texi
-man_MANS = gawk.1 igawk.1
+info_TEXINFOS = gawk.texi gawkinet.texi gawkworkflow.texi
+man_MANS = gawk.1
EXTRA_DIST = ChangeLog ChangeLog.0 README.card ad.block setter.outline \
awkcard.in awkforai.txt texinfo.tex cardfonts \
api-figure1.eps api-figure1.fig api-figure1.pdf \
@@ -367,18 +369,19 @@ EXTRA_DIST = ChangeLog ChangeLog.0 README.card ad.block setter.outline \
gawktexi.in sidebar.awk \
general-program.eps general-program.fig general-program.pdf \
general-program.png general-program.txt \
+ it \
process-flow.eps process-flow.fig process-flow.pdf \
process-flow.png process-flow.txt \
macros colors no.colors $(man_MANS) \
lflashlight-small.xpic lflashlight.eps lflashlight.pdf \
rflashlight-small.xpic rflashlight.eps rflashlight.pdf \
statist.jpg statist.eps statist.pdf \
- wordlist \
+ wordlist wordlist2 \
bc_notes
# Get rid of generated files when cleaning
-CLEANFILES = *.ps *.html *.dvi *~ awkcard.nc awkcard.tr gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf igawk.1.pdf
+CLEANFILES = *.ps *.html *.dvi *~ awkcard.nc awkcard.tr gawk.pdf gawkinet.pdf gawkworkflow.pdf awkcard.pdf gawk.1.pdf
TROFF = groff -t -Tps -U
SEDME = sed -e "s/^level0 restore/level0 restore flashme 100 72 moveto (Copyright `date '+%m-%d-%y %T'`, FSF, Inc. (all)) show/" \
-e "s/^\/level0 save def/\/level0 save def 30 -48 translate/"
@@ -476,6 +479,10 @@ $(srcdir)/gawkinet.info: gawkinet.texi
gawkinet.dvi: gawkinet.texi
gawkinet.pdf: gawkinet.texi
gawkinet.html: gawkinet.texi
+$(srcdir)/gawkworkflow.info: gawkworkflow.texi
+gawkworkflow.dvi: gawkworkflow.texi
+gawkworkflow.pdf: gawkworkflow.texi
+gawkworkflow.html: gawkworkflow.texi
.dvi.ps:
$(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
$(DVIPS) $(AM_V_texinfo) -o $@ $<
@@ -557,13 +564,16 @@ dist-info: $(INFO_DEPS)
done
mostlyclean-aminfo:
- -rm -rf gawk.t2d gawk.t2p gawkinet.t2d gawkinet.t2p
+ -rm -rf gawk.t2d gawk.t2p gawkinet.t2d gawkinet.t2p gawkworkflow.t2d \
+ gawkworkflow.t2p
clean-aminfo:
-test -z "gawk.dvi gawk.pdf gawk.ps gawk.html gawkinet.dvi gawkinet.pdf \
- gawkinet.ps gawkinet.html" \
+ gawkinet.ps gawkinet.html gawkworkflow.dvi gawkworkflow.pdf \
+ gawkworkflow.ps gawkworkflow.html" \
|| rm -rf gawk.dvi gawk.pdf gawk.ps gawk.html gawkinet.dvi gawkinet.pdf \
- gawkinet.ps gawkinet.html
+ gawkinet.ps gawkinet.html gawkworkflow.dvi gawkworkflow.pdf \
+ gawkworkflow.ps gawkworkflow.html
maintainer-clean-aminfo:
@list='$(INFO_DEPS)'; for i in $$list; do \
@@ -882,9 +892,9 @@ uninstall-man: uninstall-man1
gawk.texi: $(srcdir)/gawktexi.in $(srcdir)/sidebar.awk
awk -f $(srcdir)/sidebar.awk < $(srcdir)/gawktexi.in > gawk.texi
-postscript: gawk.ps gawkinet.ps gawk.1.ps igawk.1.ps $(AWKCARD)
+postscript: gawk.ps gawkinet.ps gawkworkflow.ps gawk.1.ps $(AWKCARD)
-pdf-local: postscript gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf igawk.1.pdf
+pdf-local: postscript gawk.pdf gawkinet.pdf awkcard.pdf gawk.1.pdf
gawk.ps: gawk.dvi
TEXINPUTS=$(srcdir): dvips -o gawk.ps gawk.dvi
@@ -892,18 +902,15 @@ gawk.ps: gawk.dvi
gawkinet.ps: gawkinet.dvi
TEXINPUTS=$(srcdir): dvips -o gawkinet.ps gawkinet.dvi
+gawkworkflow.ps: gawkworkflow.dvi
+ TEXINPUTS=$(srcdir): dvips -o gawkworkflow.ps gawkworkflow.dvi
+
gawk.1.ps: gawk.1
-groff -man $(srcdir)/gawk.1 > gawk.1.ps
gawk.1.pdf: gawk.1.ps
ps2pdf gawk.1.ps gawk.1.pdf
-igawk.1.ps: igawk.1
- -groff -man $(srcdir)/igawk.1 > igawk.1.ps
-
-igawk.1.pdf: igawk.1.ps
- ps2pdf igawk.1.ps igawk.1.pdf
-
awkcard.tr: awkcard.in
sed 's:SRCDIR:$(srcdir):' < $(srcdir)/awkcard.in > awkcard.tr
@@ -916,10 +923,18 @@ awkcard.nc: $(CARDFILES)
awkcard.pdf: awkcard.ps
ps2pdf awkcard.ps awkcard.pdf
-spell:
+spell: spellmanual spellworkflow
+
+spellmanual:
+ @echo ==== gawktexi.in ====;
export LC_ALL=C ; spell "$(srcdir)"/gawktexi.in | \
sort -u | comm -23 - "$(srcdir)"/wordlist
+spellworkflow:
+ @echo ==== gawkworkflow.texi ====
+ export LC_ALL=C ; spell "$(srcdir)"/gawkworkflow.texi | \
+ sort -u | comm -23 - "$(srcdir)"/wordlist2
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/doc/awkcard.in b/doc/awkcard.in
index 34648bef..86aeee2e 100644
--- a/doc/awkcard.in
+++ b/doc/awkcard.in
@@ -1,7 +1,7 @@
.\" AWK Reference Card --- Arnold Robbins, arnold@skeeve.com
.\"
-.\" Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-.\" 2003, 2004, 2005, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
+.\" Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+.\" 2005, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
.\" Free Software Foundation, Inc.
.\"
.\" Permission is granted to make and distribute verbatim copies of
@@ -244,7 +244,7 @@ Overridden by \*(FC\-\^\-posix\*(FR.
.TI "\*(FC\-c\*(FR, \*(FC\-\^\-traditional\*(FR
Disable \*(GK-specific extensions.
.TI "\*(FC\-C\*(FR, \*(FC\-\^\-copyright\*(FR
-Print the short version of the GNU
+Print the short GNU
copyright information on \*(FCstdout\*(FR.
.TI "\*(FC\-d\*(FR[\*(FIfile\*(FR], \*(FC\-\^\-dump-variables\*(FR[\*(FC=\*(FIfile\*(FR]
Print a sorted list of global variables,
@@ -292,7 +292,7 @@ Force use of the locale's decimal point character when parsing input data.
Output a pretty printed version of the program to \*(FIfile\*(FR
(default: \*(FCawkprof.out\*(FR).
.TI "\*(FC\-O\*(FR, \*(FC\-\^\-optimize\*(FR
-Enable some internal optimizations.
+Enable internal optimizations (default is on).
.TI "\*(FC\-p\*(FR[\*(FC\*(FIfile\*(FR], \*(FC\-\^\-profile\*(FR[\*(FC=\*(FIfile\*(FR]
Send profiling data to \*(FIfile\*(FR
(default: \*(FCawkprof.out\*(FR).
@@ -300,6 +300,9 @@ The profile contains execution counts in the left margin
of each statement in the program.
.TI "\*(FC\-P\*(FR, \*(FC\-\^\-posix\*(FR
Disable common and GNU extensions.\*(CB
+.TI "\*(FC\-r\*(FR, \*(FC\-\^\-re\-interval\*(FR
+Enable \*(FIinterval expressions\*(FR.
+(Needed with \*(FC\-c\*(FR.)
.in -4n
.EB "\s+2\f(HBCOMMAND LINE ARGUMENTS (\*(GK\f(HB)\*(FR\s0"
@@ -311,9 +314,8 @@ Disable common and GNU extensions.\*(CB
.ES
.fi
.in +4n
-.TI "\*(FC\-r\*(FR, \*(FC\-\^\-re\-interval\*(FR
-Enable \*(FIinterval expressions\*(FR.
-(Needed with \*(FC\-c\*(FR.)
+.TI "\*(FC\-s\*(FR, \*(FC\-\^\-no\-optimize\*(FR
+Disable internal optimizations.
.TI "\*(FC\-S\*(FR, \*(FC\-\^\-sandbox\*(FR
Disable the \*(FCsystem()\*(FR function,
input redirection with \*(FCgetline\*(FR,
@@ -554,8 +556,10 @@ fails, or if
\*(FCclose()\*(FR fails.
T}
\*(FCFIELDWIDTHS\fP T{
-Whitespace separated list of field widths. Used
-to parse the input into fields of fixed width,
+Whitespace-separated list of field widths.
+Each field width may optionally be preceded by a colon-separated
+value specifying the number of characters to skip before the field starts.
+Used to parse the input into fields of fixed width,
instead of the value of \*(FCFS\fP.\*(CD
T}
\*(FCFILENAME\fP T{
@@ -1015,6 +1019,8 @@ also affects how fields are split when
variable is set to a space-separated list of numbers, each field is
expected to have a fixed width, and \*(GK
splits up the record using the specified widths.
+Each field width may optionally be preceded by a colon-separated
+value specifying the number of characters to skip before the field starts.
The value of \*(FCFS\fP is ignored.
Assigning a new value to \*(FCFS\fP or \*(FCFPAT\fP
overrides the use of \*(FCFIELDWIDTHS\*(FR.
@@ -1606,11 +1612,14 @@ may be used in place of
.fi
.TS
expand;
-l lw(2i).
+l lw(1.9i).
\*(CD\*(FCatan2(\*(FIy\*(FC, \*(FIx\*(FC)\*(FR The arctangent of \*(FIy/x\fP in radians.
\*(FCcos(\*(FIexpr\*(FC)\*(FR The cosine of \*(FIexpr\fP, which is in radians.
\*(FCexp(\*(FIexpr\*(FC)\*(FR The exponential function (\*(FIe \*(FC^ \*(FIx\*(FR).
\*(FCint(\*(FIexpr\*(FC)\*(FR Truncate to integer.
+\*(CB\*(FCintdiv(\*(FIn\*(FR\*(FC,\*(FI d\*(FR\*(FC,\*(FI r\*(FR\*(FC)\*(FR T{
+Return result of integer division in \*(FIr\*(FR.\*(CD
+T}
\*(FClog(\*(FIexpr\*(FC)\*(FR The natural logarithm function (base \*(FIe\^\*(FR).
\*(FCrand()\fP A random number \*(FIN\fP such that 0 \(<= \*(FIN\fP < 1.
\*(FCsin(\*(FIexpr\*(FC)\*(FR The sine of \*(FIexpr\fP, which is in radians.
@@ -1789,13 +1798,16 @@ formatting them.
.fi
.in +.2i
.ti -.2i
-\*(FCmktime(\*(FIdatespec\*(FC)\*(FR
+\*(FCmktime(\*(FIdatespec \*(FR[\*(FC, \*(FIutc-flag\*(FR]\*(FC)\*(FR
.br
Convert \*(FIdatespec\fP into a time
stamp of the same form as returned by \*(FCsystime()\*(FR
and return it.
The \*(FIdatespec\fP is a string of the form
\*(FC"\*(FIYYYY MM DD HH MM SS[ DST]\*(FC"\*(FR.
+If \*(FIutc-flag\*(FR
+is present and is non-zero or non-null, the result
+is in UTC, otherwise it is in local time.
.ti -.2i
\*(FCstrftime(\*(FR[\*(FIformat \*(FR[\*(FC, \*(FItimestamp\*(FR[\*(FC, \*(FIutc-flag\*(FR]]]\*(FC)\*(FR
.br
@@ -1882,7 +1894,12 @@ See the manual for details.\*(CB
.ti -.2i
\*(CD\*(FCisarray(\*(FIx\*(FC)\*(FR
.br
-Return true if \*(FIx\fP is an array, false otherwise.\*(CB
+Return true if \*(FIx\fP is an array, false otherwise.
+.br
+.ti -.2i
+\*(FCtypeof(\*(FIx\*(FC)\*(FR
+.br
+Return a string indicating the type of \*(FIx\fP.\*(CB
.in -.2i
.EB "\s+2\f(HBTYPE FUNCTIONS (\*(GK\f(HB)\*(FR\s0"
.sp .5
diff --git a/doc/gawk.1 b/doc/gawk.1
index 2caa87ad..b04cb013 100644
--- a/doc/gawk.1
+++ b/doc/gawk.1
@@ -13,7 +13,7 @@
. if \w'\(rq' .ds rq "\(rq
. \}
.\}
-.TH GAWK 1 "Mar 7 2016" "Free Software Foundation" "Utility Commands"
+.TH GAWK 1 "Jun 30 2016" "Free Software Foundation" "Utility Commands"
.SH NAME
gawk \- pattern scanning and processing language
.SH SYNOPSIS
@@ -405,17 +405,20 @@ is provided,
uses a file named
.B awkprof.out
in the current directory.
+Implies
+.BR \-\^\-no\-optimize .
.TP
.PD 0
.B \-O
.TP
.PD
.B \-\^\-optimize
-Enable optimizations upon the internal representation of the program.
+Enable
+.IR gawk 's
+default optimizations upon the internal representation of the program.
Currently, this includes simple constant-folding, and tail call
-elimination for recursive functions. The
-.I gawk
-maintainer hopes to add additional optimizations over time.
+elimination for recursive functions.
+This option is on by default.
.TP
.PD 0
\fB\-p\fR[\fIprof-file\fR]
@@ -428,6 +431,8 @@ The default is
.BR awkprof.out .
The profile contains execution counts of each statement in the program
in the left margin and function call counts for each user-defined function.
+Implies
+.BR \-\^\-no\-optimize .
.TP
.PD 0
.B \-P
@@ -444,11 +449,6 @@ mode, with the following additional restrictions:
escape sequences are not recognized.
.TP
\(bu
-Only space and tab act as field separators when
-.B FS
-is set to a single space, newline does not.
-.TP
-\(bu
You cannot continue lines after
.B ?
and
@@ -493,6 +493,15 @@ They are enabled by default, but this option remains for use with
.BR \-\^\-traditional .
.TP
.PD 0
+.B \-s
+.TP
+.PD
+.B \-\^\-no\-optimize
+Disable
+.IR gawk 's
+default optimizations upon the internal representation of the program.
+.TP
+.PD 0
.BI \-S
.TP
.PD
@@ -785,9 +794,6 @@ In the special case that
.B FS
is a single space, fields are separated
by runs of spaces and/or tabs and/or newlines.
-(But see the section
-.BR "POSIX COMPATIBILITY" ,
-below).
.BR NOTE :
The value of
.B IGNORECASE
@@ -799,10 +805,13 @@ is a regular expression.
.PP
If the
.B FIELDWIDTHS
-variable is set to a space separated list of numbers, each field is
+variable is set to a space-separated list of numbers, each field is
expected to have fixed width, and
.I gawk
-splits up the record using the specified widths. The value of
+splits up the record using the specified widths.
+Each field width may optionally be preceded by a colon-separated
+value specifying the number of characters to skip before the field starts.
+The value of
.B FS
is ignored.
Assigning a new value to
@@ -918,11 +927,17 @@ An array containing the values of the current environment.
The array is indexed by the environment variables, each element being
the value of that variable (e.g., \fBENVIRON["HOME"]\fP might be
\fB"/home/arnold"\fR).
-Changing this array does not affect the environment seen by programs which
+.sp
+In POSIX mode,
+changing this array does not affect the environment seen by programs which
.I gawk
spawns via redirection or the
.B system()
function.
+Otherwise,
+.I gawk
+updates its real environment so that programs it spawns see
+the changes.
.TP
.B ERRNO
If a system error occurs either doing a redirection for
@@ -936,14 +951,25 @@ then
will contain
a string describing the error.
The value is subject to translation in non-English locales.
+If the string in
+.B ERRNO
+corresponds to a system error in the
+.IR errno (3)
+variable, then the numeric value can be found in
+.B PROCINFO["errno"].
+For non-system errors,
+.B PROCINFO["errno"]
+will be zero.
.TP
.B FIELDWIDTHS
-A whitespace separated list of field widths. When set,
+A whitespace-separated list of field widths. When set,
.I gawk
parses the input into fields of fixed width, instead of using the
value of the
.B FS
variable as the field separator.
+Each field width may optionally be preceded by a colon-separated
+value specifying the number of characters to skip before the field starts.
See
.BR Fields ,
above.
@@ -1093,6 +1119,13 @@ The value of the
.IR getegid (2)
system call.
.TP
+\fBPROCINFO["errno"]\fP
+The value of
+.IR errno (3)
+when
+.BR ERRNO
+is set to the associated error message.
+.TP
\fBPROCINFO["euid"]\fP
The value of the
.IR geteuid (2)
@@ -1105,8 +1138,10 @@ is in effect,
\fB"FPAT"\fP if field splitting with
.B FPAT
is in effect,
-or \fB"FIELDWIDTHS"\fP if field splitting with
+\fB"FIELDWIDTHS"\fP if field splitting with
.B FIELDWIDTHS
+is in effect,
+or \fB"API"\fP if API input parser field splitting
is in effect.
.TP
\fBPROCINFO["gid"]\fP
@@ -1124,7 +1159,7 @@ knows about the identifiers after it has finished parsing the program; they are
updated while the program runs.
For each identifier, the value of the element is one of the following:
.RS
-.TP
+.TP \w'\fB"extension"\fR'u+1n
\fB"array"\fR
The identifier is an array.
.TP
@@ -1207,6 +1242,14 @@ change
.IR gawk 's
behavior:
.TP
+\fBPROCINFO["NONFATAL"]\fR
+If this exists, then I/O errors for all output redirections become nonfatal.
+.TP
+\fBPROCINFO["\fIoutput_name\fB", "NONFATAL"]\fR
+Make output errors for
+.I output_name
+be nonfatal.
+.TP
\fBPROCINFO["\fIcommand\fB", "pty"]\fR
Use a pseudo-tty for two-way communication with
.I command
@@ -1220,6 +1263,23 @@ where
is a redirection string or a filename. A value of zero or
less than zero means no timeout.
.TP
+\fBPROCINFO["\fIinput\^\fB", "RETRY"]\fR
+If an I/O error that may be retried occurs when reading data from
+.IR input ,
+and this array entry exists, then
+.B getline
+will return \-2 instead of following the default behavior of returning \-1
+and configuring
+.IR input
+to return no further data.
+An I/O error that may be retried is one where
+.IR errno (3)
+has the value EAGAIN, EWOULDBLOCK, EINTR, or ETIMEDOUT.
+This may be useful in conjunction with
+\fBPROCINFO["\fIinput\^\fB", "READ_TIMEOUT"]\fR
+or situations where a file descriptor has been configured to behave in a
+non-blocking fashion.
+.TP
\fBPROCINFO["sorted_in"]\fP
If this element exists in
.BR PROCINFO ,
@@ -1240,7 +1300,9 @@ Supported values are
\fB"@val_num_desc"\fR,
and
\fB"@unsorted"\fR.
-The value can also be the name of any comparison function defined
+The value can also be the name (as a
+.IR string )
+of any comparison function defined
as follows:
.sp
.in +5m
@@ -1544,9 +1606,9 @@ Vertical tab.
The character represented by the string of hexadecimal digits following
the
.BR \ex .
-As in ISO C, all following hexadecimal digits are considered part of
+Up to two
+following hexadecimal digits are considered part of
the escape sequence.
-(This feature should tell us something about language design by committee.)
E.g., \fB"\ex1B"\fR is the \s-1ASCII\s+1 \s-1ESC\s+1 (escape) character.
.TP
.BI \e ddd
@@ -2291,6 +2353,13 @@ below.)
The
.B getline
command returns 1 on success, 0 on end of file, and \-1 on an error.
+If the
+.IR errno (3)
+value indicates that the I/O operation may be retried,
+and \fBPROCINFO["\fIinput\^\fP", "RETRY"]\fR
+is set, then \-2 will be returned instead of \-1, and further calls to
+.B getline
+may be attempted.
Upon an error,
.B ERRNO
is set to a string describing the problem.
@@ -2643,6 +2712,23 @@ The exponential function.
.BI int( expr )
Truncate to integer.
.TP
+.BI intdiv( num ", " denom ", " result )
+Truncate
+.I num
+and
+.I denom
+to integers. Return the quotient of
+.I num
+divided by
+.I denom
+in \fIresult\fB["quotient"]\fR
+and the remainder in
+in \fIresult\fB["remainder"]\fR.
+This is a
+.I gawk
+extension, primarily of value when working with
+arbitrarily large integers.
+.TP
.BI log( expr )
The natural logarithm function.
.TP
@@ -2891,9 +2977,11 @@ that matched
.IR r .
The value of
.BI seps[ i ]
-is the separator that appeared in
-front of
-.BI a[ i +1]\fR.
+is the possibly null separator that appeared after
+.BI a[ i ]\fR.
+The value of
+.B seps[0]
+is the possibly null leading separator.
\&\fRIf
.I r
is omitted,
@@ -3026,7 +3114,7 @@ provides the following functions for obtaining time stamps and
formatting them.
.PP
.TP "\w'\fBsystime()\fR'u+1n"
-\fBmktime(\fIdatespec\fB)\fR
+\fBmktime(\fIdatespec\fR [\fB, \fIutc-flag\fR]\fB)\fR
Turn
.I datespec
into a time stamp of the same form as returned by
@@ -3048,7 +3136,11 @@ The values of these numbers need not be within the ranges specified;
for example, an hour of \-1 means 1 hour before midnight.
The origin-zero Gregorian calendar is assumed,
with year 0 preceding year 1 and year \-1 preceding year 0.
-The time is assumed to be in the local timezone.
+If
+.I utc-flag
+is present and is non-zero or non-null, the time is assumed to be in
+the UTC time zone; otherwise, the
+time is assumed to be in the local time zone.
If the daylight saving flag is positive,
the time is assumed to be daylight saving time;
if zero, the time is assumed to be standard time;
@@ -3102,6 +3194,11 @@ values to
.B uintmax_t
integers, doing the operation, and then converting the
result back to floating point.
+.PP
+.BR NOTE :
+Passing negative operands to any of these functions causes
+a fatal error.
+.PP
The functions are:
.TP "\w'\fBrshift(\fIval\fB, \fIcount\fB)\fR'u+2n"
\fBand(\fIv1\fB, \fIv2 \fR[, ...]\fB)\fR
@@ -3134,13 +3231,28 @@ bits.
Return the bitwise XOR of the values provided in the argument list.
There must be at least two.
.PP
-.SS Type Function
+.SS Type Functions
The following function is for use with multidimensional arrays.
.TP
\fBisarray(\fIx\fB)\fR
Return true if
.I x
is an array, false otherwise.
+.PP
+You can tell the type of any variable or array element with the
+following function:
+.TP
+\fBtypeof(\fIx\fB)\fR
+Return a string indicating the type of
+.IR x .
+The string will be one of
+\fB"array"\fP,
+\fB"number"\fP,
+\fB"regexp"\fP,
+\fB"string"\fP,
+\fB"strnum"\fP,
+or
+\fB"undefined"\fP.
.SS Internationalization Functions
The following functions may be used from within your AWK program for
translating strings at run-time.
@@ -3987,7 +4099,7 @@ We thank him.
.SH COPYING PERMISSIONS
Copyright \(co 1989, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2007, 2009,
-2010, 2011, 2012, 2013, 2014, 2016
+2010, 2011, 2012, 2013, 2014, 2015, 2016
Free Software Foundation, Inc.
.PP
Permission is granted to make and distribute verbatim copies of
diff --git a/doc/gawk.info b/doc/gawk.info
index 188f22ca..752eec86 100644
--- a/doc/gawk.info
+++ b/doc/gawk.info
@@ -196,7 +196,13 @@ in (a) below. A copy of the license is included in the section entitled
field.
* Field Splitting Summary:: Some final points and a summary table.
* Constant Size:: Reading constant width data.
+* Fixed width data:: Processing fixed-width data.
+* Skipping intervening:: Skipping intervening fields.
+* Allowing trailing data:: Capturing optional trailing data.
+* Fields with fixed data:: Field values with fixed-width data.
* Splitting By Content:: Defining Fields By Content
+* Testing field creation:: Checking how 'gawk' is
+ splitting records.
* Multiple Line:: Reading multiline records.
* Getline:: Reading files under explicit program
control using the 'getline'
@@ -217,6 +223,7 @@ in (a) below. A copy of the license is included in the section entitled
'getline'.
* Getline Summary:: Summary of 'getline' Variants.
* Read Timeout:: Reading input with a timeout.
+* Retrying Input:: Retrying input after certain errors.
* Command-line directories:: What happens if you put a directory on
the command line.
* Input Summary:: Input summary.
@@ -246,6 +253,7 @@ in (a) below. A copy of the license is included in the section entitled
* Special Caveats:: Things to watch out for.
* Close Files And Pipes:: Closing Input and Output Files and
Pipes.
+* Nonfatal:: Enabling Nonfatal Output.
* Output Summary:: Output summary.
* Output Exercises:: Exercises.
* Values:: Constants, Variables, and Regular
@@ -255,6 +263,9 @@ in (a) below. A copy of the license is included in the section entitled
* Nondecimal-numbers:: What are octal and hex numbers.
* Regexp Constants:: Regular Expression constants.
* Using Constant Regexps:: When and how to use a regexp constant.
+* Standard Regexp Constants:: Regexp constants in standard
+ 'awk'.
+* Strong Regexp Constants:: Strongly typed regexp constants.
* Variables:: Variables give names to values for
later use.
* Using Variables:: Using variables in your programs.
@@ -525,6 +536,7 @@ in (a) below. A copy of the license is included in the section entitled
* Setting the rounding mode:: How to set the rounding mode.
* Arbitrary Precision Integers:: Arbitrary Precision Integer Arithmetic
with 'gawk'.
+* Checking for MPFR:: How to check if MPFR is available.
* POSIX Floating Point Problems:: Standards Versus Existing Practice.
* Floating point summary:: Summary of floating point discussion.
* Extension Intro:: What is an extension.
@@ -557,11 +569,14 @@ in (a) below. A copy of the license is included in the section entitled
* Array Functions:: Functions for working with arrays.
* Flattening Arrays:: How to flatten arrays.
* Creating Arrays:: How to create and populate arrays.
+* Redirection API:: How to access and manipulate
+ redirections.
* Extension API Variables:: Variables provided by the API.
* Extension Versioning:: API Version information.
* Extension API Informational Variables:: Variables providing information about
'gawk''s invocation.
* Extension API Boilerplate:: Boilerplate code for using the API.
+* Changes from API V1:: Changes from V1 of the API.
* Finding Extensions:: How 'gawk' finds compiled
extensions.
* Extension Example:: Example C code for an extension.
@@ -615,14 +630,16 @@ in (a) below. A copy of the license is included in the section entitled
* Unix Installation:: Installing 'gawk' under
various versions of Unix.
* Quick Installation:: Compiling 'gawk' under Unix.
+* Shell Startup Files:: Shell convenience functions.
* Additional Configuration Options:: Other compile-time options.
* Configuration Philosophy:: How it's all supposed to work.
* Non-Unix Installation:: Installation on Other Operating
Systems.
-* PC Installation:: Installing and Compiling 'gawk' on
- Microsoft Windows.
+* PC Installation:: Installing and Compiling
+ 'gawk' on Microsoft Windows.
* PC Binary Installation:: Installing a prepared distribution.
-* PC Compiling:: Compiling 'gawk' for Windows32.
+* PC Compiling:: Compiling 'gawk' for
+ Windows32.
* PC Using:: Running 'gawk' on Windows32.
* Cygwin:: Building and running 'gawk'
for Cygwin.
@@ -1849,11 +1866,45 @@ that it is worth addressing.
The "shells" on Microsoft Windows systems use the double-quote
character for quoting, and make it difficult or impossible to include an
escaped double-quote character in a command-line script. The following
-example, courtesy of Jeroen Brink, shows how to print all lines in a
-file surrounded by double quotes:
+example, courtesy of Jeroen Brink, shows how to escape the double quotes
+from this one liner script that prints all lines in a file surrounded by
+double quotes:
+
+ { print "\"" $0 "\"" }
+
+In an MS-Windows command-line the one-liner script above may be passed
+as follows:
gawk "{ print \"\042\" $0 \"\042\" }" FILE
+ In this example the '\042' is the octal code for a double-quote;
+'gawk' converts it into a real double-quote for output by the 'print'
+statement.
+
+ In MS-Windows escaping double-quotes is a little tricky because you
+use backslashes to escape double-quotes, but backslashes themselves are
+not escaped in the usual way; indeed they are either duplicated or not,
+depending upon whether there is a subsequent double-quote. The
+MS-Windows rule for double-quoting a string is the following:
+
+ 1. For each double quote in the orginal string, let N be the number of
+ backslash(es) before it, N might be zero. Replace these N
+ backslash(es) by 2*N+1 backslash(es)
+
+ 2. Let N be the number of backslash(es) tailing the original string, N
+ might be zero. Replace these N backslash(es) by 2*N backslash(es)
+
+ 3. Surround the resulting string by double-quotes.
+
+ So to double-quote the one-liner script '{ print "\"" $0 "\"" }' from
+the previous example you would do it this way:
+
+ gawk "{ print \"\\\"\" $0 \"\\\"\" }" FILE
+
+However, the use of '\042' instead of '\\\"' is also possible and easier
+to read, because backslashes that are not followed by a double-quote
+don't need duplication.
+

File: gawk.info, Node: Sample Data Files, Next: Very Simple, Prev: Running gawk, Up: Getting Started
@@ -2513,6 +2564,20 @@ The following list describes options mandated by the POSIX standard:
have library functions that you want to use from your command-line
programs (*note AWKPATH Variable::).
+ Note that 'gawk' treats each string as if it ended with a newline
+ character (even if it doesn't). This makes building the total
+ program easier.
+
+ CAUTION: At the moment, there is no requirement that each
+ PROGRAM-TEXT be a full syntactic unit. I.e., the following
+ currently works:
+
+ $ gawk -e 'BEGIN { a = 5 ;' -e 'print a }'
+ -| 5
+
+ However, this could change in the future, so it's not a good
+ idea to rely upon this feature.
+
'-E' FILE
'--exec' FILE
Similar to '-f', read 'awk' program text from FILE. There are two
@@ -2613,30 +2678,33 @@ The following list describes options mandated by the POSIX standard:
'-o'[FILE]
'--pretty-print'['='FILE]
- Enable pretty-printing of 'awk' programs. By default, the output
- program is created in a file named 'awkprof.out' (*note
- Profiling::). The optional FILE argument allows you to specify a
- different file name for the output. No space is allowed between
- the '-o' and FILE, if FILE is supplied.
+ Enable pretty-printing of 'awk' programs. Implies '--no-optimize'.
+ By default, the output program is created in a file named
+ 'awkprof.out' (*note Profiling::). The optional FILE argument
+ allows you to specify a different file name for the output. No
+ space is allowed between the '-o' and FILE, if FILE is supplied.
- NOTE: Due to the way 'gawk' has evolved, with this option your
- program still executes. This will change in the next major
- release, such that 'gawk' will only pretty-print the program
- and not run it.
+ NOTE: In the past, this option would also execute your
+ program. This is no longer the case.
'-O'
'--optimize'
- Enable some optimizations on the internal representation of the
- program. At the moment, this includes just simple constant
- folding.
+ Enable 'gawk''s default optimizations on the internal
+ representation of the program. At the moment, this includes simple
+ constant folding and tail recursion elimination in function calls.
+
+ These optimizations are enabled by default. This option remains
+ primarily for backwards compatibility. However, it may be used to
+ cancel the effect of an earlier '-s' option (see later in this
+ list).
'-p'[FILE]
'--profile'['='FILE]
- Enable profiling of 'awk' programs (*note Profiling::). By
- default, profiles are created in a file named 'awkprof.out'. The
- optional FILE argument allows you to specify a different file name
- for the profile file. No space is allowed between the '-p' and
- FILE, if FILE is supplied.
+ Enable profiling of 'awk' programs (*note Profiling::). Implies
+ '--no-optimize'. By default, profiles are created in a file named
+ 'awkprof.out'. The optional FILE argument allows you to specify a
+ different file name for the profile file. No space is allowed
+ between the '-p' and FILE, if FILE is supplied.
The profile contains execution counts for each statement in the
program in the left margin, and function call counts for each
@@ -2650,9 +2718,6 @@ The following list describes options mandated by the POSIX standard:
in 'gawk' that are disabled by this option. Also, the following
additional restrictions apply:
- * Newlines do not act as whitespace to separate fields when 'FS'
- is equal to a single space (*note Fields::).
-
* Newlines are not allowed after '?' or ':' (*note Conditional
Exp::).
@@ -2673,6 +2738,11 @@ The following list describes options mandated by the POSIX standard:
remains (both for backward compatibility and for use in combination
with '--traditional').
+'-s'
+'--no-optimize'
+ Disable 'gawk''s default optimizations on the internal
+ representation of the program.
+
'-S'
'--sandbox'
Disable the 'system()' function, input redirections with 'getline',
@@ -2921,6 +2991,9 @@ Since '.' is included at the beginning, 'gawk' searches first in the
current directory and then in '/usr/local/share/awk'. In practice, this
means that you will rarely need to change the value of 'AWKPATH'.
+ *Note Shell Startup Files::, for information on functions that help
+to manipulate the 'AWKPATH' variable.
+
'gawk' places the value of the search path that it used into
'ENVIRON["AWKPATH"]'. This provides access to the actual search path
value from within an 'awk' program.
@@ -2960,6 +3033,9 @@ empty value, 'gawk' uses a default path; this is typically
'/usr/local/lib/gawk', although it can vary depending upon how 'gawk'
was built.
+ *Note Shell Startup Files::, for information on functions that help
+to manipulate the 'AWKLIBPATH' variable.
+
'gawk' places the value of the search path that it used into
'ENVIRON["AWKLIBPATH"]'. This provides access to the actual search path
value from within an 'awk' program.
@@ -2986,7 +3062,8 @@ used by regular users:
'GAWK_SOCK_RETRIES'
Controls the number of times 'gawk' attempts to retry a two-way
TCP/IP (socket) connection before giving up. *Note TCP/IP
- Networking::.
+ Networking::. Note that when nonfatal I/O is enabled (*note
+ Nonfatal::), 'gawk' only tries to open a TCP/IP socket once.
'POSIXLY_CORRECT'
Causes 'gawk' to switch to POSIX-compatibility mode, disabling all
@@ -3036,13 +3113,6 @@ change. The variables are:
supposed to be differences, but occasionally theory and practice
don't coordinate with each other.)
-'GAWK_NO_PP_RUN'
- When 'gawk' is invoked with the '--pretty-print' option, it will
- not run the program if this environment variable exists.
-
- CAUTION: This variable will not survive into the next major
- release.
-
'GAWK_STACKSIZE'
This specifies the amount by which 'gawk' should grow its internal
evaluation stack, when needed.
@@ -3433,15 +3503,18 @@ sequences 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'.)
-
- CAUTION: The next major release of 'gawk' will change, such
- that a maximum of two hexadecimal digits following the '\x'
- will be used.
+ 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.) (The '\x' escape sequence is not allowed in POSIX awk.)
+
+ CAUTION: In ISO C, the escape sequence continues until the
+ first nonhexadecimal digit is seen. For many years, 'gawk'
+ would continue incorporating hexadecimal digits into the value
+ until a non-hexadecimal digit or the end of the string was
+ encountered. However, using more than two hexadecimal digits
+ produced undefined results. As of version 4.2, only two
+ digits are processed.
'\/'
A literal slash (necessary for regexp constants only). This
@@ -4162,10 +4235,13 @@ be named on the 'awk' command line (*note Getline::).
* Field Separators:: The field separator and how to change it.
* Constant Size:: Reading constant width data.
* Splitting By Content:: Defining Fields By Content
+* Testing field creation:: Checking how 'gawk' is splitting
+ records.
* Multiple Line:: Reading multiline records.
* Getline:: Reading files under explicit program control
using the 'getline' function.
* Read Timeout:: Reading input with a timeout.
+* Retrying Input:: Retrying input after certain errors.
* Command-line directories:: What happens if you put a directory on the
command line.
* Input Summary:: Input summary.
@@ -4427,7 +4503,7 @@ When 'awk' reads an input record, the record is automatically "parsed"
or separated by the 'awk' utility into chunks called "fields". By
default, fields are separated by "whitespace", like words in a line.
Whitespace in 'awk' means any string of one or more spaces, TABs, or
-newlines;(1) other characters that are considered whitespace by other
+newlines; other characters that are considered whitespace by other
languages (such as formfeed, vertical tab, etc.) are _not_ considered
whitespace by 'awk'.
@@ -4479,11 +4555,6 @@ record:
-| Julie F
-| Samuel A
- ---------- Footnotes ----------
-
- (1) In POSIX 'awk', newlines are not considered whitespace for
-separating fields.
-

File: gawk.info, Node: Nonconstant Fields, Next: Changing Fields, Prev: Fields, Up: Reading Files
@@ -5062,10 +5133,25 @@ This minor node discusses an advanced feature of 'gawk'. If you are a
novice 'awk' user, you might want to skip it on the first reading.
'gawk' provides a facility for dealing with fixed-width fields with
-no distinctive field separator. For example, data of this nature arises
-in the input for old Fortran programs where numbers are run together, or
-in the output of programs that did not anticipate the use of their
-output as input for other programs.
+no distinctive field separator. We discuss this feature in the
+following nodes.
+
+* Menu:
+
+* Fixed width data:: Processing fixed-width data.
+* Skipping intervening:: Skipping intervening fields.
+* Allowing trailing data:: Capturing optional trailing data.
+* Fields with fixed data:: Field values with fixed-width data.
+
+
+File: gawk.info, Node: Fixed width data, Next: Skipping intervening, Up: Constant Size
+
+4.6.1 Processing Fixed-Width Data
+---------------------------------
+
+An example of fixed-width data would be the input for old Fortran
+programs where numbers are run together, or the output of programs that
+did not anticipate the use of their output as input for other programs.
An example of the latter is a table where all the columns are lined
up by the use of a variable number of spaces and _empty fields are just
@@ -5080,8 +5166,10 @@ variable 'FIELDWIDTHS'. Each number specifies the width of the field,
_including_ columns between fields. If you want to ignore the columns
between fields, you can specify the width as a separate field that is
subsequently ignored. It is a fatal error to supply a field width that
-has a negative value. The following data is the output of the Unix 'w'
-utility. It is useful to illustrate the use of 'FIELDWIDTHS':
+has a negative value.
+
+ The following data is the output of the Unix 'w' utility. It is
+useful to illustrate the use of 'FIELDWIDTHS':
10:06pm up 21 days, 14:04, 23 users
User tty login idle JCPU PCPU what
@@ -5104,7 +5192,7 @@ calculated idle time:
sub(/^ +/, "", idle) # strip leading spaces
if (idle == "")
idle = 0
- if (idle ~ /:/) {
+ if (idle ~ /:/) { # hh:mm
split(idle, t, ":")
idle = t[1] * 60 + t[2]
}
@@ -5138,27 +5226,92 @@ An 'awk' program for processing such data could use the 'FIELDWIDTHS'
feature to simplify reading the data. (Of course, getting 'gawk' to run
on a system with card readers is another story!)
- Assigning a value to 'FS' causes 'gawk' to use 'FS' for field
-splitting again. Use 'FS = FS' to make this happen, without having to
-know the current value of 'FS'. In order to tell which kind of field
-splitting is in effect, use 'PROCINFO["FS"]' (*note Auto-set::). The
-value is '"FS"' if regular field splitting is being used, or
-'"FIELDWIDTHS"' if fixed-width field splitting is being used:
+
+File: gawk.info, Node: Skipping intervening, Next: Allowing trailing data, Prev: Fixed width data, Up: Constant Size
- if (PROCINFO["FS"] == "FS")
- REGULAR FIELD SPLITTING ...
- else if (PROCINFO["FS"] == "FIELDWIDTHS")
- FIXED-WIDTH FIELD SPLITTING ...
- else
- CONTENT-BASED FIELD SPLITTING ... (see next minor node)
+4.6.2 Skipping Intervening Fields
+---------------------------------
- This information is useful when writing a function that needs to
-temporarily change 'FS' or 'FIELDWIDTHS', read some records, and then
-restore the original settings (*note Passwd Functions:: for an example
-of such a function).
+Starting in version 4.2, each field width may optionally be preceded by
+a colon-separated value specifying the number of characters to skip
+before the field starts. Thus, the preceding program could be rewritten
+to specify 'FIELDWIDTHS' like so:
+
+ BEGIN { FIELDWIDTHS = "8 1:5 4:7 6 1:6 1:6 2:33" }
+
+ This strips away some of the white space separating the fields. With
+such a change, the program produces the following results:
+
+ hzang ttyV3 50
+ eklye ttyV5 0
+ dportein ttyV6 107
+ gierd ttyD3 1
+ dave ttyD4 0
+ brent ttyp0 286
+ dave ttyq4 1296000

-File: gawk.info, Node: Splitting By Content, Next: Multiple Line, Prev: Constant Size, Up: Reading Files
+File: gawk.info, Node: Allowing trailing data, Next: Fields with fixed data, Prev: Skipping intervening, Up: Constant Size
+
+4.6.3 Capturing Optional Trailing Data
+--------------------------------------
+
+There are times when fixed-width data may be followed by additional data
+that has no fixed length. Such data may or may not be present, but if
+it is, it should be possible to get at it from an 'awk' program.
+
+ Starting with version 4.2, in order to provide a way to say "anything
+else in the record after the defined fields," 'gawk' allows you to add a
+final '*' character to the value of 'FIELDWIDTHS'. There can only be
+one such character, and it must be the final non-whitespace character in
+'FIELDWIDTHS'. For example:
+
+ $ cat fw.awk Show the program
+ -| BEGIN { FIELDWIDTHS = "2 2 *" }
+ -| { print NF, $1, $2, $3 }
+ $ cat fw.in Show sample input
+ -| 1234abcdefghi
+ $ gawk -f fw.awk fw.in Run the program
+ -| 3 12 34 abcdefghi
+
+
+File: gawk.info, Node: Fields with fixed data, Prev: Allowing trailing data, Up: Constant Size
+
+4.6.4 Field Values With Fixed-Width Data
+----------------------------------------
+
+So far, so good. But what happens if there isn't as much data as there
+should be based on the contents of 'FIELDWIDTHS'? Or, what happens if
+there is more data than expected?
+
+ For many years, what happens in these cases was not well defined.
+Starting with version 4.2, the rules are as follows:
+
+Enough data for some fields
+ For example, if 'FIELDWIDTHS' is set to '"2 3 4"' and the input
+ record is 'aabbb'. In this case, 'NF' is set to two.
+
+Not enough data for a field
+ For example, if 'FIELDWIDTHS' is set to '"2 3 4"' and the input
+ record is 'aab'. In this case, 'NF' is set to two and '$2' has the
+ value '"b"'. The idea is that even though there aren't as many
+ characters as were expected, there are some, so the data should be
+ made available to the program.
+
+Too much data
+ For example, if 'FIELDWIDTHS' is set to '"2 3 4"' and the input
+ record is 'aabbbccccddd'. In this case, 'NF' is set to three and
+ the extra characters ('ddd') are ignored. If you want 'gawk' to
+ capture the extra characters, supply a final '*' in the value of
+ 'FIELDWIDTHS'.
+
+Too much data, but with '*' supplied
+ For example, if 'FIELDWIDTHS' is set to '"2 3 4 *"' and the input
+ record is 'aabbbccccddd'. In this case, 'NF' is set to four, and
+ '$4' has the value '"ddd"'.
+
+
+File: gawk.info, Node: Splitting By Content, Next: Testing field creation, Prev: Constant Size, Up: Reading Files
4.7 Defining Fields by Content
==============================
@@ -5234,9 +5387,7 @@ would be to remove the quotes when they occur, with something like this:
affects field splitting with 'FPAT'.
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.
+with 'FIELDWIDTHS'.
NOTE: Some programs export CSV data that contains embedded newlines
between the double quotes. 'gawk' provides no way to deal with
@@ -5254,10 +5405,6 @@ contain at least one character. A straightforward modification
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. The mechanism used is based on which of the three
-variables--'FS', 'FIELDWIDTHS', or 'FPAT'--was last assigned to.
-
---------- Footnotes ----------
(1) The CSV format lacked a formal standard definition for many
@@ -5265,9 +5412,46 @@ years. RFC 4180 (http://www.ietf.org/rfc/rfc4180.txt) standardizes the
most common practices.

-File: gawk.info, Node: Multiple Line, Next: Getline, Prev: Splitting By Content, Up: Reading Files
+File: gawk.info, Node: Testing field creation, Next: Multiple Line, Prev: Splitting By Content, Up: Reading Files
-4.8 Multiple-Line Records
+4.8 Checking How 'gawk' Is Splitting Records
+============================================
+
+As we've seen, 'gawk' provides three independent methods to split input
+records into fields. The mechanism used is based on which of the three
+variables--'FS', 'FIELDWIDTHS', or 'FPAT'--was last assigned to. In
+addition, an API input parser may choose to override the record parsing
+mechanism; please refer to *note Input Parsers:: for further information
+about this feature.
+
+ To restore normal field splitting after using 'FIELDWIDTHS' and/or
+'FPAT', simply assign a value to 'FS'. You can use 'FS = FS' to do
+this, without having to know the current value of 'FS'.
+
+ In order to tell which kind of field splitting is in effect, use
+'PROCINFO["FS"]' (*note Auto-set::). The value is '"FS"' if regular
+field splitting is being used, '"FIELDWIDTHS"' if fixed-width field
+splitting is being used, or '"FPAT"' if content-based field splitting is
+being used:
+
+ if (PROCINFO["FS"] == "FS")
+ REGULAR FIELD SPLITTING ...
+ else if (PROCINFO["FS"] == "FIELDWIDTHS")
+ FIXED-WIDTH FIELD SPLITTING ...
+ else if (PROCINFO["FS"] == "FPAT")
+ CONTENT-BASED FIELD SPLITTING
+ else
+ API INPUT PARSER FIELD SPLITTING ... (advanced feature)
+
+ This information is useful when writing a function that needs to
+temporarily change 'FS' or 'FIELDWIDTHS', read some records, and then
+restore the original settings (*note Passwd Functions:: for an example
+of such a function).
+
+
+File: gawk.info, Node: Multiple Line, Next: Getline, Prev: Testing field creation, Up: Reading Files
+
+4.9 Multiple-Line Records
=========================
In some databases, a single line cannot conveniently hold all the
@@ -5407,8 +5591,8 @@ separator of a single space: 'FS = " "'.

File: gawk.info, Node: Getline, Next: Read Timeout, Prev: Multiple Line, Up: Reading Files
-4.9 Explicit Input with 'getline'
-=================================
+4.10 Explicit Input with 'getline'
+==================================
So far we have been getting our input data from 'awk''s main input
stream--either the standard input (usually your keyboard, sometimes the
@@ -5429,6 +5613,11 @@ 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.
+ If 'ERRNO' indicates that the I/O operation may be retried, and
+'PROCINFO["INPUT", "RETRY"]' is set, then 'getline' returns -2 instead
+of -1, and further calls to 'getline' may be attempted. *Note Retrying
+Input:: for further information about this feature.
+
In the following examples, COMMAND stands for a string value that
represents a shell command.
@@ -5454,8 +5643,8 @@ represents a shell command.

File: gawk.info, Node: Plain Getline, Next: Getline/Variable, Up: Getline
-4.9.1 Using 'getline' with No Arguments
----------------------------------------
+4.10.1 Using 'getline' with No Arguments
+----------------------------------------
The 'getline' command can be used without arguments to read input from
the current input file. All it does in this case is read the next input
@@ -5515,8 +5704,8 @@ the value of '$0'.

File: gawk.info, Node: Getline/Variable, Next: Getline/File, Prev: Plain Getline, Up: Getline
-4.9.2 Using 'getline' into a Variable
--------------------------------------
+4.10.2 Using 'getline' into a Variable
+--------------------------------------
You can use 'getline VAR' to read the next record from 'awk''s input
into the variable VAR. No other processing is done. For example,
@@ -5556,8 +5745,8 @@ fields, so the values of the fields (including '$0') and the value of

File: gawk.info, Node: Getline/File, Next: Getline/Variable/File, Prev: Getline/Variable, Up: Getline
-4.9.3 Using 'getline' from a File
----------------------------------
+4.10.3 Using 'getline' from a File
+----------------------------------
Use 'getline < FILE' to read the next record from FILE. Here, FILE is a
string-valued expression that specifies the file name. '< FILE' is
@@ -5589,8 +5778,8 @@ portable to all 'awk' implementations.

File: gawk.info, Node: Getline/Variable/File, Next: Getline/Pipe, Prev: Getline/File, Up: Getline
-4.9.4 Using 'getline' into a Variable from a File
--------------------------------------------------
+4.10.4 Using 'getline' into a Variable from a File
+--------------------------------------------------
Use 'getline VAR < FILE' to read input from the file FILE, and put it in
the variable VAR. As earlier, FILE is a string-valued expression that
@@ -5633,8 +5822,8 @@ regular expression.

File: gawk.info, Node: Getline/Pipe, Next: Getline/Variable/Pipe, Prev: Getline/Variable/File, Up: Getline
-4.9.5 Using 'getline' from a Pipe
----------------------------------
+4.10.5 Using 'getline' from a Pipe
+----------------------------------
Omniscience has much to recommend it. Failing that, attention to
details would be useful.
@@ -5703,8 +5892,8 @@ you want your program to be portable to all 'awk' implementations.

File: gawk.info, Node: Getline/Variable/Pipe, Next: Getline/Coprocess, Prev: Getline/Pipe, Up: Getline
-4.9.6 Using 'getline' into a Variable from a Pipe
--------------------------------------------------
+4.10.6 Using 'getline' into a Variable from a Pipe
+--------------------------------------------------
When you use 'COMMAND | getline VAR', the output of COMMAND is sent
through a pipe to 'getline' and into the variable VAR. For example, the
@@ -5730,8 +5919,8 @@ to other 'awk' implementations.

File: gawk.info, Node: Getline/Coprocess, Next: Getline/Variable/Coprocess, Prev: Getline/Variable/Pipe, Up: Getline
-4.9.7 Using 'getline' from a Coprocess
---------------------------------------
+4.10.7 Using 'getline' from a Coprocess
+---------------------------------------
Reading input into 'getline' from a pipe is a one-way operation. The
command that is started with 'COMMAND | getline' only sends data _to_
@@ -5760,8 +5949,8 @@ coprocesses are discussed in more detail.

File: gawk.info, Node: Getline/Variable/Coprocess, Next: Getline Notes, Prev: Getline/Coprocess, Up: Getline
-4.9.8 Using 'getline' into a Variable from a Coprocess
-------------------------------------------------------
+4.10.8 Using 'getline' into a Variable from a Coprocess
+-------------------------------------------------------
When you use 'COMMAND |& getline VAR', the output from the coprocess
COMMAND is sent through a two-way pipe to 'getline' and into the
@@ -5778,8 +5967,8 @@ coprocesses are discussed in more detail.

File: gawk.info, Node: Getline Notes, Next: Getline Summary, Prev: Getline/Variable/Coprocess, Up: Getline
-4.9.9 Points to Remember About 'getline'
-----------------------------------------
+4.10.9 Points to Remember About 'getline'
+-----------------------------------------
Here are some miscellaneous points about 'getline' that you should bear
in mind:
@@ -5838,8 +6027,8 @@ in mind:

File: gawk.info, Node: Getline Summary, Prev: Getline Notes, Up: Getline
-4.9.10 Summary of 'getline' Variants
-------------------------------------
+4.10.10 Summary of 'getline' Variants
+-------------------------------------
*note Table 4.1: table-getline-variants. summarizes the eight variants
of 'getline', listing which predefined variables are set by each one,
@@ -5864,9 +6053,9 @@ 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: Retrying Input, Prev: Getline, Up: Reading Files
-4.10 Reading Input with a Timeout
+4.11 Reading Input with a Timeout
=================================
This minor node describes a feature that is specific to 'gawk'.
@@ -5943,7 +6132,8 @@ per-command or per-connection basis.
'gawk' considers a timeout event to be an error even though the
attempt to read from the underlying device may succeed in a later
attempt. This is a limitation, and it also means that you cannot use
-this to multiplex input from two or more sources.
+this to multiplex input from two or more sources. *Note Retrying
+Input:: for a way to enable later I/O attempts to succeed.
Assigning a timeout value prevents read operations from blocking
indefinitely. But bear in mind that there are other ways 'gawk' can
@@ -5957,9 +6147,36 @@ can block indefinitely until some other process opens it for 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: Retrying Input, Next: Command-line directories, Prev: Read Timeout, Up: Reading Files
+
+4.12 Retrying Reads After Certain Input Errors
+==============================================
+
+This minor node describes a feature that is specific to 'gawk'.
+
+ When 'gawk' encounters an error while reading input, by default
+'getline' returns -1, and subsequent attempts to read from that file
+result in an end-of-file indication. However, you may optionally
+instruct 'gawk' to allow I/O to be retried when certain errors are
+encountered by setting a special element in the 'PROCINFO' array (*note
+Auto-set::):
+
+ PROCINFO["INPUT_NAME", "RETRY"] = 1
+
+ When this element exists, 'gawk' checks the value of the system (C
+language) 'errno' variable when an I/O error occurs. If 'errno'
+indicates a subsequent I/O attempt may succeed, 'getline' instead
+returns -2 and further calls to 'getline' may succeed. This applies to
+the 'errno' values 'EAGAIN', 'EWOULDBLOCK', 'EINTR', or 'ETIMEDOUT'.
+
+ This feature is useful in conjunction with 'PROCINFO["INPUT_NAME",
+"READ_TIMEOUT"]' or situations where a file descriptor has been
+configured to behave in a non-blocking fashion.
+
+
+File: gawk.info, Node: Command-line directories, Next: Input Summary, Prev: Retrying Input, Up: Reading Files
-4.11 Directories on the Command Line
+4.13 Directories on the Command Line
====================================
According to the POSIX standard, files named on the 'awk' command line
@@ -5982,7 +6199,7 @@ usable data from an 'awk' program.

File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-line directories, Up: Reading Files
-4.12 Summary
+4.14 Summary
============
* Input is split into records based on the value of 'RS'. The
@@ -6054,7 +6271,7 @@ File: gawk.info, Node: Input Summary, Next: Input Exercises, Prev: Command-li

File: gawk.info, Node: Input Exercises, Prev: Input Summary, Up: Reading Files
-4.13 Exercises
+4.15 Exercises
==============
1. Using the 'FIELDWIDTHS' variable (*note Constant Size::), write a
@@ -6104,6 +6321,7 @@ function.
'gawk' allows access to inherited file
descriptors.
* Close Files And Pipes:: Closing Input and Output Files and Pipes.
+* Nonfatal:: Enabling Nonfatal Output.
* Output Summary:: Output summary.
* Output Exercises:: Exercises.
@@ -7011,7 +7229,7 @@ that 'gawk' provides:
behavior.

-File: gawk.info, Node: Close Files And Pipes, Next: Output Summary, Prev: Special Files, Up: Printing
+File: gawk.info, Node: Close Files And Pipes, Next: Nonfatal, Prev: Special Files, Up: Printing
5.9 Closing Input and Output Redirections
=========================================
@@ -7156,11 +7374,23 @@ there is a system problem closing the file or process. In these cases,
'gawk' sets the predefined variable 'ERRNO' to a string describing the
problem.
- In 'gawk', when closing a pipe or coprocess (input or output), the
-return value is the exit status of the command.(2) Otherwise, it is the
-return value from the system's 'close()' or 'fclose()' C functions when
-closing input or output files, respectively. This value is zero if the
-close succeeds, or -1 if it fails.
+ In 'gawk', starting with version 4.2, when closing a pipe or
+coprocess (input or output), the return value is the exit status of the
+command, as described in *note Table 5.1:
+table-close-pipe-return-values.(2) Otherwise, it is the return value
+from the system's 'close()' or 'fclose()' C functions when closing input
+or output files, respectively. This value is zero if the close
+succeeds, or -1 if it fails.
+
+Situation Return value from 'close()'
+--------------------------------------------------------------------------
+Normal exit of command Command's exit status
+Death by signal of command 256 + number of murderous signal
+Death by signal of command 512 + number of murderous signal
+with core dump
+Some kind of error -1
+
+Table 5.1: Return values from 'close()' of a pipe
The POSIX standard is very vague; it says that 'close()' returns zero
on success and a nonzero value otherwise. In general, different
@@ -7174,14 +7404,73 @@ Options::), 'gawk' just returns zero when closing a pipe.
is called a "zombie," and cleaning up after it is referred to as
"reaping."
- (2) This is a full 16-bit value as returned by the 'wait()' system
-call. See the system manual pages for information on how to decode this
-value.
+ (2) Prior to version 4.2, the return value from closing a pipe or
+co-process was the full 16-bit exit value as defined by the 'wait()'
+system call.

-File: gawk.info, Node: Output Summary, Next: Output Exercises, Prev: Close Files And Pipes, Up: Printing
+File: gawk.info, Node: Nonfatal, Next: Output Summary, Prev: Close Files And Pipes, Up: Printing
+
+5.10 Enabling Nonfatal Output
+=============================
+
+This minor node describes a 'gawk'-specific feature.
-5.10 Summary
+ In standard 'awk', output with 'print' or 'printf' to a nonexistent
+file, or some other I/O error (such as filling up the disk) is a fatal
+error.
+
+ $ gawk 'BEGIN { print "hi" > "/no/such/file" }'
+ error-> gawk: cmd. line:1: fatal: can't redirect to `/no/such/file' (No such file or directory)
+
+ 'gawk' makes it possible to detect that an error has occurred,
+allowing you to possibly recover from the error, or at least print an
+error message of your choosing before exiting. You can do this in one
+of two ways:
+
+ * For all output files, by assigning any value to
+ 'PROCINFO["NONFATAL"]'.
+
+ * On a per-file basis, by assigning any value to 'PROCINFO[FILENAME,
+ "NONFATAL"]'. Here, FILENAME is the name of the file to which you
+ wish output to be nonfatal.
+
+ Once you have enabled nonfatal output, you must check 'ERRNO' after
+every relevant 'print' or 'printf' statement to see if something went
+wrong. It is also a good idea to initialize 'ERRNO' to zero before
+attempting the output. For example:
+
+ $ gawk '
+ > BEGIN {
+ > PROCINFO["NONFATAL"] = 1
+ > ERRNO = 0
+ > print "hi" > "/no/such/file"
+ > if (ERRNO) {
+ > print("Output failed:", ERRNO) > "/dev/stderr"
+ > exit 1
+ > }
+ > }'
+ error-> Output failed: No such file or directory
+
+ Here, 'gawk' did not produce a fatal error; instead it let the 'awk'
+program code detect the problem and handle it.
+
+ This mechanism works also for standard output and standard error.
+For standard output, you may use 'PROCINFO["-", "NONFATAL"]' or
+'PROCINFO["/dev/stdout", "NONFATAL"]'. For standard error, use
+'PROCINFO["/dev/stderr", "NONFATAL"]'.
+
+ When attempting to open a TCP/IP socket (*note TCP/IP Networking::),
+'gawk' tries multiple times. The 'GAWK_SOCK_RETRIES' environment
+variable (*note Other Environment Variables::) allows you to override
+'gawk''s builtin default number of attempts. However, once nonfatal I/O
+is enabled for a given socket, 'gawk' only retries once, relying on
+'awk'-level code to notice that there was a problem.
+
+
+File: gawk.info, Node: Output Summary, Next: Output Exercises, Prev: Nonfatal, Up: Printing
+
+5.11 Summary
============
* The 'print' statement prints comma-separated expressions. Each
@@ -7203,10 +7492,15 @@ File: gawk.info, Node: Output Summary, Next: Output Exercises, Prev: Close Fi
For coprocesses, it is possible to close only one direction of the
communications.
+ * Normally errors with 'print' or 'printf' are fatal. 'gawk' lets
+ you make output errors be nonfatal either for all files or on a
+ per-file basis. You must then check for errors after every
+ relevant output statement.
+

File: gawk.info, Node: Output Exercises, Prev: Output Summary, Up: Printing
-5.11 Exercises
+5.12 Exercises
==============
1. Rewrite the program:
@@ -7337,9 +7631,9 @@ octal (base 8) and hexadecimal (base 16). In octal, the numbers go 0,
1 times 10 plus 1, so '11' in octal is 1 times 8 plus 1. This equals 9
in decimal. In hexadecimal, there are 16 digits. Because the everyday
decimal number system only has ten digits ('0'-'9'), the letters 'a'
-through 'f' are used to represent the rest. (Case in the letters is
-usually irrelevant; hexadecimal 'a' and 'A' have the same value.) Thus,
-'11' in hexadecimal is 1 times 16 plus 1, which equals 17 in decimal.
+through 'f' represent the rest. (Case in the letters is usually
+irrelevant; hexadecimal 'a' and 'A' have the same value.) Thus, '11' in
+hexadecimal is 1 times 16 plus 1, which equals 17 in decimal.
Just by looking at plain '11', you can't tell what base it's in. So,
in C, C++, and other languages derived from C, there is a special
@@ -7416,6 +7710,23 @@ File: gawk.info, Node: Using Constant Regexps, Next: Variables, Prev: Constan
6.1.2 Using Regular Expression Constants
----------------------------------------
+Regular expression constants consist of text describing a regular
+expression enclosed in slashes (such as '/the +answer/'). This minor
+node describes how such constants work in POSIX 'awk' and 'gawk', and
+then goes on to describe "strongly typed regexp constants", which are a
+'gawk' extension.
+
+* Menu:
+
+* Standard Regexp Constants:: Regexp constants in standard 'awk'.
+* Strong Regexp Constants:: Strongly typed regexp constants.
+
+
+File: gawk.info, Node: Standard Regexp Constants, Next: Strong Regexp Constants, Up: Using Constant Regexps
+
+6.1.2.1 Standard Regular Expression Constants
+.............................................
+
When used on the righthand side of the '~' or '!~' operators, a regexp
constant merely stands for the regexp that is to be matched. However,
regexp constants (such as '/foo/') may be used like simple expressions.
@@ -7490,6 +7801,73 @@ function, because passing a truth value in this way is probably not what
was intended.

+File: gawk.info, Node: Strong Regexp Constants, Prev: Standard Regexp Constants, Up: Using Constant Regexps
+
+6.1.2.2 Strongly Typed Regexp Constants
+.......................................
+
+This minor node describes a 'gawk'-specific feature.
+
+ As we saw in the previous minor node, regexp constants ('/.../') hold
+a strange position in the 'awk' language. In most contexts, they act
+like an expression: '$0 ~ /.../'. In other contexts, they denote only a
+regexp to be matched. In no case are they really a "first class
+citizen" of the language. That is, you cannot define a scalar variable
+whose type is "regexp" in the same sense that you can define a variable
+to be a number or a string:
+
+ num = 42 Numeric variable
+ str = "hi" String variable
+ re = /foo/ Wrong! re is the result of $0 ~ /foo/
+
+ For a number of more advanced use cases, it would be nice to have
+regexp constants that are "strongly typed"; in other words, that denote
+a regexp useful for matching, and not an expression.
+
+ 'gawk' provides this feature. A strongly typed regexp constant looks
+almost like a regular regexp constant, except that it is preceded by an
+'@' sign:
+
+ re = @/foo/ Regexp variable
+
+ Strongly typed regexp constants _cannot_ be used everywhere that a
+regular regexp constant can, because this would make the language even
+more confusing. Instead, you may use them only in certain contexts:
+
+ * On the righthand side of the '~' and '!~' operators: 'some_var ~
+ @/foo/' (*note Regexp Usage::).
+
+ * In the 'case' part of a 'switch' statement (*note Switch
+ Statement::).
+
+ * As an argument to one of the built-in functions that accept regexp
+ constants: 'gensub()', 'gsub()', 'match()', 'patsplit()',
+ 'split()', and 'sub()' (*note String Functions::).
+
+ * As a parameter in a call to a user-defined function (*note
+ User-defined::).
+
+ * On the righthand side of an assignment to a variable: 'some_var =
+ @/foo/'. In this case, the type of 'some_var' is regexp.
+ Additionally, 'some_var' can be used with '~' and '!~', passed to
+ one of the built-in functions listed above, or passed as a
+ parameter to a user-defined function.
+
+ You may use the 'typeof()' built-in function (*note Type Functions::)
+to determine if a variable or function parameter is a regexp variable.
+
+ The true power of this feature comes from the ability to create
+variables that have regexp type. Such variables can be passed on to
+user-defined functions, without the confusing aspects of computed
+regular expressions created from strings or string constants. They may
+also be passed through indirect function calls (*note Indirect Calls::)
+and on to the built-in functions that accept regexp constants.
+
+ When used in numeric conversions, strongly typed regexp variables
+convert to zero. When used in string conversions, they convert to the
+string value of the original regexp text.
+
+
File: gawk.info, Node: Variables, Next: Conversion, Prev: Using Constant Regexps, Up: Values
6.1.3 Variables
@@ -8265,11 +8643,74 @@ File: gawk.info, Node: Variable Typing, Next: Comparison Operators, Up: Typin
6.3.2.1 String Type versus Numeric Type
.......................................
-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:
+Scalar objects in 'awk' (variables, array elements, and fields) are
+_dynamically_ typed. This means their type can change as the program
+runs, from "untyped" before any use,(1) to string or number, and then
+from string to number or number to string, as the program progresses.
+('gawk' also provides regexp-typed scalars, but let's ignore that for
+now; *note Strong Regexp Constants::.)
+
+ You can't do much with untyped variables, other than tell that they
+are untyped. The following program tests 'a' against '""' and '0'; the
+test succeeds when 'a' has never been assigned a value. It also uses
+the built-in 'typeof()' function (not presented yet; *note Type
+Functions::) to show 'a''s type:
+
+ $ gawk 'BEGIN { print (a == "" && a == 0 ?
+ > "a is untyped" : "a has a type!") ; print typeof(a) }'
+ -| a is untyped
+ -| unassigned
+
+ A scalar has numeric type when assigned a numeric value, such as from
+a numeric constant, or from another scalar with numeric type:
+
+ $ gawk 'BEGIN { a = 42 ; print typeof(a)
+ > b = a ; print typeof(b) }'
+ number
+ number
+
+ Similarly, a scalar has string type when assigned a string value,
+such as from a string constant, or from another scalar with string type:
+
+ $ gawk 'BEGIN { a = "forty two" ; print typeof(a)
+ > b = a ; print typeof(b) }'
+ string
+ string
+
+ So far, this is all simple and straightforward. What happens,
+though, when 'awk' has to process data from a user? Let's start with
+field data. What should the following command produce as output?
+
+ echo hello | awk '{ printf("%s %s < 42\n", $1,
+ ($1 < 42 ? "is" : "is not")) }'
+
+Since 'hello' is alphabetic data, 'awk' can only do a string comparison.
+Internally, it converts '42' into '"42"' and compares the two string
+values '"hello"' and '"42"'. Here's the result:
+
+ $ echo hello | awk '{ printf("%s %s < 42\n", $1,
+ > ($1 < 42 ? "is" : "is not")) }'
+ -| hello is not < 42
+
+ However, what happens when data from a user _looks like_ a number?
+On the one hand, in reality, the input data consists of characters, not
+binary numeric values. But, on the other hand, the data looks numeric,
+and 'awk' really ought to treat it as such. And indeed, it does:
+
+ $ echo 37 | awk '{ printf("%s %s < 42\n", $1,
+ > ($1 < 42 ? "is" : "is not")) }'
+ -| 37 is < 42
+
+ Here are the rules for when 'awk' treats data as a number, and for
+when it treats data as a string.
+
+ The POSIX standard uses the term "numeric string" for input data that
+looks numeric. The '37' in the previous example is a numeric string.
+So what is the type of a numeric string? Answer: numeric.
+
+ The type of a variable is important because the types of two
+variables determine how they are compared. Variable typing follows
+these definitions and rules:
* A numeric constant or the result of a numeric operation has the
"numeric" attribute.
@@ -8280,8 +8721,9 @@ they are compared. Variable typing follows these rules:
* Fields, 'getline' input, 'FILENAME', 'ARGV' elements, 'ENVIRON'
elements, and the elements of an array created by 'match()',
'split()', and 'patsplit()' that are numeric strings have the
- "strnum" attribute. Otherwise, they have the "string" attribute.
- Uninitialized variables also have the "strnum" attribute.
+ "strnum" attribute.(2) Otherwise, they have the "string"
+ attribute. Uninitialized variables also have the "strnum"
+ attribute.
* Attributes propagate across assignments but are not changed by any
use.
@@ -8300,16 +8742,16 @@ operation:
comparison may be used. This depends upon the attributes of the
operands, according to the following symmetric matrix:
- +-------------------------------
- | STRING NUMERIC STRNUM
- -----+-------------------------------
- |
- STRING | string string string
- |
- NUMERIC | string numeric numeric
- |
- STRNUM | string numeric numeric
- -----+-------------------------------
+ +----------------------------------------------
+ | STRING NUMERIC STRNUM
+--------+----------------------------------------------
+ |
+STRING | string string string
+ |
+NUMERIC | string numeric numeric
+ |
+STRNUM | string numeric numeric
+--------+----------------------------------------------
The basic idea is that user input that looks numeric--and _only_ user
input--should be treated as numeric, even though it is actually made of
@@ -8320,16 +8762,18 @@ for comparison purposes.
In short, when one operand is a "pure" string, such as a string
constant, then a string comparison is performed. Otherwise, a numeric
-comparison is performed.
+comparison is performed. (The primary difference between a number and a
+strnum is that for strnums 'gawk' preserves the original string value
+that the scalar had when it came in.)
- This point bears additional emphasis: All user input is made of
-characters, and so is first and foremost of string type; input strings
-that look numeric are additionally given the strnum attribute. Thus,
-the six-character input string ' +3.14' receives the strnum attribute.
-In contrast, the eight characters '" +3.14"' appearing in program text
-comprise a string constant. The following examples print '1' when the
-comparison between the two different constants is true, and '0'
-otherwise:
+ This point bears additional emphasis: Input that looks numeric _is_
+numeric. All other input is treated as strings.
+
+ Thus, the six-character input string ' +3.14' receives the strnum
+attribute. In contrast, the eight characters '" +3.14"' appearing in
+program text comprise a string constant. The following examples print
+'1' when the comparison between the two different constants is true, and
+'0' otherwise:
$ echo ' +3.14' | awk '{ print($0 == " +3.14") }' True
-| 1
@@ -8348,6 +8792,19 @@ otherwise:
$ echo ' +3.14' | awk '{ print($1 == 3.14) }' True
-| 1
+ You can see the type of an input field (or other user input) using
+'typeof()':
+
+ $ echo hello 37 | gawk '{ print typeof($1), typeof($2) }'
+ -| string strnum
+
+ ---------- Footnotes ----------
+
+ (1) 'gawk' calls this "unassigned", as the following example shows.
+
+ (2) Thus, a POSIX numeric string and 'gawk''s strnum are the same
+thing.
+

File: gawk.info, Node: Comparison Operators, Next: POSIX String Comparison, Prev: Variable Typing, Up: Typing and Comparison
@@ -8464,18 +8921,18 @@ Constant Regexps::, where this is discussed in more detail.

File: gawk.info, Node: POSIX String Comparison, Prev: Comparison Operators, Up: Typing and Comparison
-6.3.2.3 String Comparison with POSIX Rules
-..........................................
+6.3.2.3 String Comparison Based on Locale Collating Order
+.........................................................
-The POSIX standard says that string comparison is performed based on the
-locale's "collating order". This is the order in which characters sort,
-as defined by the locale (for more discussion, *note Locales::). This
-order is usually very different from the results obtained when doing
-straight character-by-character comparison.(1)
+The POSIX standard used to say that all string comparisons are performed
+based on the locale's "collating order". This is the order in which
+characters sort, as defined by the locale (for more discussion, *note
+Locales::). This order is usually very different from the results
+obtained when doing straight byte-by-byte comparison.(1)
Because this behavior differs considerably from existing practice,
-'gawk' only implements it when in POSIX mode (*note Options::). Here is
-an example to illustrate the difference, in an 'en_US.UTF-8' locale:
+'gawk' only implemented it when in POSIX mode (*note Options::). Here
+is an example to illustrate the difference, in an 'en_US.UTF-8' locale:
$ gawk 'BEGIN { printf("ABC < abc = %s\n",
> ("ABC" < "abc" ? "TRUE" : "FALSE")) }'
@@ -8484,11 +8941,28 @@ an example to illustrate the difference, in an 'en_US.UTF-8' locale:
> ("ABC" < "abc" ? "TRUE" : "FALSE")) }'
-| ABC < abc = FALSE
+ Fortunately, as of August 2016, comparison based on locale collating
+order is no longer required for the '==' and '!=' operators.(2)
+However, comparison based on locales is still required for '<', '<=',
+'>', and '>='. POSIX thus recommends as follows:
+
+ Since the '==' operator checks whether strings are identical, not
+ whether they collate equally, applications needing to check whether
+ strings collate equally can use:
+
+ a <= b && a >= b
+
+ As of version 4.2, 'gawk' continues to use locale collating order for
+'<', '<=', '>', and '>=' only in POSIX mode.
+
---------- Footnotes ----------
(1) Technically, string comparison is supposed to behave the same way
as if the strings were compared with the C 'strcoll()' function.
+ (2) See the Austin Group website
+(http://austingroupbugs.net/view.php?id=1070).
+

File: gawk.info, Node: Boolean Ops, Next: Conditional Exp, Prev: Typing and Comparison, Up: Truth Values and Conditions
@@ -10103,9 +10577,12 @@ each variable.)
'FIELDWIDTHS #'
A space-separated list of columns that tells 'gawk' how to split
- input with fixed columnar boundaries. Assigning a value to
- 'FIELDWIDTHS' overrides the use of 'FS' and 'FPAT' for field
- splitting. *Note Constant Size:: for more information.
+ input with fixed columnar boundaries. Starting in version 4.2,
+ each field width may optionally be preceded by a colon-separated
+ value specifying the number of characters to skip before the field
+ starts. Assigning a value to 'FIELDWIDTHS' overrides the use of
+ 'FS' and 'FPAT' for field splitting. *Note Constant Size:: for
+ more information.
'FPAT #'
A regular expression (as a string) that tells 'gawk' to create the
@@ -10126,7 +10603,7 @@ each variable.)
The default value is '" "', a string consisting of a single space.
As a special exception, this value means that any sequence of
- spaces, TABs, and/or newlines is a single separator.(1) It also
+ spaces, TABs, and/or newlines is a single separator. It also
causes spaces, TABs, and newlines at the beginning and end of a
record to be ignored.
@@ -10223,10 +10700,6 @@ each variable.)
Internationalization::). The default value of 'TEXTDOMAIN' is
'"messages"'.
- ---------- Footnotes ----------
-
- (1) In POSIX 'awk', newline does not count as whitespace.
-

File: gawk.info, Node: Auto-set, Next: ARGC and ARGV, Prev: User-modified, Up: Built-in Variables
@@ -10290,10 +10763,24 @@ they are not special:
An associative array containing the values of the environment. The
array indices are the environment variable names; the elements are
the values of the particular environment variables. For example,
- 'ENVIRON["HOME"]' might be '"/home/arnold"'. Changing this array
- does not affect the environment passed on to any programs that
- 'awk' may spawn via redirection or the 'system()' function. (In a
- future version of 'gawk', it may do so.)
+ 'ENVIRON["HOME"]' might be '/home/arnold'.
+
+ For POSIX 'awk', changing this array does not affect the
+ environment passed on to any programs that 'awk' may spawn via
+ redirection or the 'system()' function.
+
+ However, beginning with version 4.2, if not in POSIX compatibility
+ mode, 'gawk' does update its own environment when 'ENVIRON' is
+ changed, thus changing the environment seen by programs that it
+ creates. You should therefore be especially careful if you modify
+ 'ENVIRON["PATH"]', which is the search path for finding executable
+ programs.
+
+ This can also affect the running 'gawk' program, since some of the
+ built-in functions may pay attention to certain environment
+ variables. The most notable instance of this is 'mktime()' (*note
+ Time Functions::), which pays attention the value of the 'TZ'
+ environment variable on many systems.
Some operating systems may not have environment variables. On such
systems, the 'ENVIRON' array is empty (except for
@@ -10316,6 +10803,11 @@ they are not special:
'getline' returning -1. You are, of course, free to clear it
yourself before doing an I/O operation.
+ If the value of 'ERRNO' corresponds to a system error in the C
+ 'errno' variable, then 'PROCINFO["errno"]' will be set to the value
+ of 'errno'. For non-system errors, 'PROCINFO["errno"]' will be
+ zero.
+
'FILENAME'
The name of the current input file. When no data files are listed
on the command line, 'awk' reads from the standard input and
@@ -10361,17 +10853,41 @@ they are not special:
running 'awk' program. The following elements (listed
alphabetically) are guaranteed to be available:
+ 'PROCINFO["argv"]'
+ The 'PROCINFO["argv"]' array contains all of the command-line
+ arguments (after glob expansion and redirection processing on
+ platforms where that must be done manually by the program)
+ with subscripts ranging from 0 through 'argc' - 1. For
+ example, 'PROCINFO["argv"][0]' will contain the name by which
+ 'gawk' was invoked. Here is an example of how this feature
+ may be used:
+
+ gawk '
+ BEGIN {
+ for (i = 0; i < length(PROCINFO["argv"]); i++)
+ print i, PROCINFO["argv"][i]
+ }'
+
+ Please note that this differs from the standard 'ARGV' array
+ which does not include command-line arguments that have
+ already been processed by 'gawk' (*note ARGC and ARGV::).
+
'PROCINFO["egid"]'
The value of the 'getegid()' system call.
+ 'PROCINFO["errno"]'
+ The value of the C 'errno' variable when 'ERRNO' is set to the
+ associated error message.
+
'PROCINFO["euid"]'
The value of the 'geteuid()' system call.
'PROCINFO["FS"]'
This is '"FS"' if field splitting with 'FS' is in effect,
'"FIELDWIDTHS"' if field splitting with 'FIELDWIDTHS' is in
- effect, or '"FPAT"' if field matching with 'FPAT' is in
- effect.
+ effect, '"FPAT"' if field matching with 'FPAT' is in effect,
+ or '"API"' if field splitting is controlled by an API input
+ parser.
'PROCINFO["gid"]'
The value of the 'getgid()' system call.
@@ -10462,6 +10978,14 @@ they are not special:
The following elements allow you to change 'gawk''s behavior:
+ 'PROCINFO["NONFATAL"]'
+ If this element exists, then I/O errors for all output
+ redirections become nonfatal. *Note Nonfatal::.
+
+ 'PROCINFO["OUTPUT_NAME", "NONFATAL"]'
+ Make output errors for OUTPUT_NAME be nonfatal. *Note
+ Nonfatal::.
+
'PROCINFO["COMMAND", "pty"]'
For two-way communication to COMMAND, use a pseudo-tty instead
of setting up a two-way pipe. *Note Two-way I/O:: for more
@@ -11876,6 +12400,24 @@ brackets ([ ]):
truncated toward zero. For example, 'int(3)' is 3, 'int(3.9)' is
3, 'int(-3.9)' is -3, and 'int(-3)' is -3 as well.
+'intdiv(NUMERATOR, DENOMINATOR, RESULT)'
+ Perform integer division, similar to the standard C 'div()'
+ function. First, truncate 'numerator' and 'denominator' towards
+ zero, creating integer values. Clear the 'result' array, and then
+ set 'result["quotient"]' to the result of 'numerator /
+ denominator', truncated towards zero to an integer, and set
+ 'result["remainder"]' to the result of 'numerator % denominator',
+ truncated towards zero to an integer. Attempting division by zero
+ causes a fatal error. The function returns zero upon success, and
+ -1 upon error.
+
+ This function is primarily intended for use with arbitrary length
+ integers; it avoids creating MPFR arbitrary precision
+ floating-point values (*note Arbitrary Precision Integers::).
+
+ This function is a 'gawk' extension. It is not available in
+ compatibility mode (*note Options::).
+
'log(X)'
Return the natural logarithm of X, if X is positive; otherwise,
return 'NaN' ("not a number") on IEEE 754 systems. Additionally,
@@ -12264,16 +12806,18 @@ Options::):
fatal error.
'patsplit(STRING, ARRAY' [', FIELDPAT' [', SEPS' ] ]') #'
- Divide STRING into pieces defined by FIELDPAT and store the pieces
- in ARRAY and the separator strings in the SEPS array. The first
- piece is stored in 'ARRAY[1]', the second piece in 'ARRAY[2]', and
- so forth. The third argument, FIELDPAT, is a regexp describing the
- fields in STRING (just as 'FPAT' is a regexp describing the fields
- in input records). It may be either a regexp constant or a string.
- If FIELDPAT is omitted, the value of 'FPAT' is used. 'patsplit()'
- returns the number of elements created. 'SEPS[I]' is the separator
- string between 'ARRAY[I]' and 'ARRAY[I+1]'. Any leading separator
- will be in 'SEPS[0]'.
+ Divide STRING into pieces (or "fields") defined by FIELDPAT and
+ store the pieces in ARRAY and the separator strings in the SEPS
+ array. The first piece is stored in 'ARRAY[1]', the second piece
+ in 'ARRAY[2]', and so forth. The third argument, FIELDPAT, is a
+ regexp describing the fields in STRING (just as 'FPAT' is a regexp
+ describing the fields in input records). It may be either a regexp
+ constant or a string. If FIELDPAT is omitted, the value of 'FPAT'
+ is used. 'patsplit()' returns the number of elements created.
+ 'SEPS[I]' is the possibly null separator string after 'ARRAY[I]'.
+ The possibly null leading separator will be in 'SEPS[0]'. So a
+ non-null STRING with N fields will have N+1 separators. A null
+ STRING will not have neither fields nor separators.
The 'patsplit()' function splits strings into pieces in a manner
similar to the way input lines are split into fields using 'FPAT'
@@ -12911,7 +13455,7 @@ POSIX standard.(2) However, recent versions of 'mawk' (*note Other
Versions::) also support these functions. Optional parameters are
enclosed in square brackets ([ ]):
-'mktime(DATESPEC)'
+'mktime(DATESPEC' [', UTC-FLAG' ]')'
Turn DATESPEC into a timestamp in the same form as is returned by
'systime()'. It is similar to the function of the same name in ISO
C. The argument, DATESPEC, is a string of the form
@@ -12924,12 +13468,14 @@ enclosed in square brackets ([ ]):
The values of these numbers need not be within the ranges
specified; for example, an hour of -1 means 1 hour before midnight.
The origin-zero Gregorian calendar is assumed, with year 0
- preceding year 1 and year -1 preceding year 0. The time is assumed
- to be in the local time zone. If the daylight-savings flag is
- positive, the time is assumed to be daylight savings time; if zero,
- the time is assumed to be standard time; and if negative (the
- default), 'mktime()' attempts to determine whether daylight savings
- time is in effect for the specified time.
+ preceding year 1 and year -1 preceding year 0. If UTC-FLAG is
+ present and is either nonzero or non-null, the time is assumed to
+ be in the UTC time zone; otherwise, the time is assumed to be in
+ the local time zone. If the daylight-savings flag is positive, the
+ time is assumed to be daylight savings time; if zero, the time is
+ assumed to be standard time; and if negative (the default),
+ 'mktime()' attempts to determine whether daylight savings time is
+ in effect for the specified time.
If DATESPEC does not contain enough elements or if the resulting
time is out of range, 'mktime()' returns -1.
@@ -13263,13 +13809,10 @@ are enclosed in square brackets ([ ]):
Return the bitwise XOR of the arguments. There must be at least
two.
- For all of these functions, first the double-precision floating-point
-value is converted to the widest C unsigned integer type, then the
-bitwise operation is performed. If the result cannot be represented
-exactly as a C 'double', leading nonzero bits are removed one by one
-until it can be represented exactly. The result is then converted back
-into a C 'double'. (If you don't understand this paragraph, don't worry
-about it.)
+ CAUTION: Beginning with 'gawk' version 4.2, negative operands are
+ not allowed for any of these functions. A negative operand
+ produces a fatal error. See the sidebar "Beware The Smoke and
+ Mirrors!" for more information as to why.
Here is a user-defined function (*note User-defined::) that
illustrates the use of these functions:
@@ -13331,26 +13874,118 @@ decimal and octal values for the same numbers (*note
Nondecimal-numbers::), and then demonstrates the results of the
'compl()', 'lshift()', and 'rshift()' functions.
+ Beware The Smoke and Mirrors!
+
+ It other languages, bitwise operations are performed on integer
+values, not floating-point values. As a general statement, such
+operations work best when performed on unsigned integers.
+
+ 'gawk' attempts to treat the arguments to the bitwise functions as
+unsigned integers. For this reason, negative arguments produce a fatal
+error.
+
+ In normal operation, for all of these functions, first the
+double-precision floating-point value is converted to the widest C
+unsigned integer type, then the bitwise operation is performed. If the
+result cannot be represented exactly as a C 'double', leading nonzero
+bits are removed one by one until it can be represented exactly. The
+result is then converted back into a C 'double'.(2)
+
+ However, when using arbitrary precision arithmetic with the '-M'
+option (*note Arbitrary Precision Arithmetic::), the results may differ.
+This is particularly noticeable with the 'compl()' function:
+
+ $ gawk 'BEGIN { print compl(42) }'
+ -| 9007199254740949
+ $ gawk -M 'BEGIN { print compl(42) }'
+ -| -43
+
+ What's going on becomes clear when printing the results in
+hexadecimal:
+
+ $ gawk 'BEGIN { printf "%#x\n", compl(42) }'
+ -| 0x1fffffffffffd5
+ $ gawk -M 'BEGIN { printf "%#x\n", compl(42) }'
+ -| 0xffffffffffffffd5
+
+ When using the '-M' option, under the hood, 'gawk' uses GNU MP
+arbitrary precision integers which have at least 64 bits of precision.
+When not using '-M', 'gawk' stores integral values in regular
+double-precision floating point, which only maintain 53 bits of
+precision. Furthermore, the GNU MP library treats (or at least seems to
+treat) the leading bit as a sign bit; thus the result with '-M' in this
+case is a negative number.
+
+ In short, using 'gawk' for any but the simplest kind of bitwise
+operations is probably a bad idea; caveat emptor!
+
---------- Footnotes ----------
(1) This example shows that zeros come in on the left side. For
'gawk', this is always true, but in some languages, it's possible to
have the left side fill with ones.
+ (2) If you don't understand this paragraph, the upshot is that 'gawk'
+can only store a particular range of integer values; numbers outside
+that range are reduced to fit within the range.
+

File: gawk.info, Node: Type Functions, Next: I18N Functions, Prev: Bitwise Functions, Up: Built-in
9.1.7 Getting Type Information
------------------------------
-'gawk' provides a single function that lets you distinguish an array
-from a scalar variable. This is necessary for writing code that
-traverses every element of an array of arrays (*note Arrays of
-Arrays::).
+'gawk' provides two functions that let you distinguish the type of a
+variable. This is necessary for writing code that traverses every
+element of an array of arrays (*note Arrays of Arrays::), and in other
+contexts.
'isarray(X)'
Return a true value if X is an array. Otherwise, return false.
+'typeof(X)'
+ Return one of the following strings, depending upon the type of X:
+
+ '"array"'
+ X is an array.
+
+ '"regexp"'
+ X is a strongly typed regexp (*note Strong Regexp
+ Constants::).
+
+ '"number"'
+ X is a number.
+
+ '"string"'
+ X is a string.
+
+ '"strnum"'
+ X is a number that started life as user input, such as a field
+ or the result of calling 'split()'. (I.e., X has the strnum
+ attribute; *note Variable Typing::.)
+
+ '"unassigned"'
+ X is a scalar variable that has not been assigned a value yet.
+ For example:
+
+ BEGIN {
+ # creates a[1] but it has no assigned value
+ a[1]
+ print typeof(a[1]) # unassigned
+ }
+
+ '"untyped"'
+ X has not yet been used yet at all; it can become a scalar or
+ an array. For example:
+
+ BEGIN {
+ print typeof(x) # x never used --> untyped
+ mk_arr(x)
+ print typeof(x) # x now an array --> array
+ }
+
+ function mk_arr(a) { a[1] = 1 }
+
'isarray()' is meant for use in two circumstances. The first is when
traversing a multidimensional array: you can test if an element is
itself an array or not. The second is inside the body of a user-defined
@@ -13364,6 +13999,14 @@ parameter is an array or not.
that has not been previously used to 'isarray()', 'gawk' ends up
turning it into a scalar.
+ The 'typeof()' function is general; it allows you to determine if a
+variable or function parameter is a scalar, an array, or a strongly
+typed regexp.
+
+ 'isarray()' is deprecated; you should use 'typeof()' instead. You
+should replace any existing uses of 'isarray(var)' in your code with
+'typeof(var) == "array"'.
+

File: gawk.info, Node: I18N Functions, Prev: Type Functions, Up: Built-in
@@ -19679,9 +20322,15 @@ case 'gawk' waits for the child process to exit, which may cause your
program to hang. (Thus, this particular feature is of much less use in
practice than being able to close the '"to"' end.)
- CAUTION: It is a fatal error to write to the '"to"' end of a
- two-way pipe which has been closed. It is also a fatal error to
- read from the '"from"' end of a two-way pipe that has been closed.
+ CAUTION: Normally, it is a fatal error to write to the '"to"' end
+ of a two-way pipe which has been closed, and it is also a fatal
+ error to read from the '"from"' end of a two-way pipe that has been
+ closed.
+
+ You may set 'PROCINFO["COMMAND", "NONFATAL"]' to make such
+ operations become nonfatal. If you do so, you then need to check
+ 'ERRNO' after each 'print', 'printf', or 'getline'. *Note
+ Nonfatal::, for more information.
You may also use pseudo-ttys (ptys) for two-way communication instead
of pipes, if your system supports them. This is done on a per-command
@@ -19969,8 +20618,7 @@ output. They are as follows:
you typed when you wrote it. This is because 'gawk' creates the
profiled version by "pretty-printing" its internal representation of the
program. The advantage to this is that 'gawk' can produce a standard
-representation. The disadvantage is that all source code comments are
-lost. Also, things such as:
+representation. Also, things such as:
/foo/
@@ -20029,8 +20677,40 @@ the 'Ctrl-\' key.
called this way, 'gawk' "pretty-prints" the program into 'awkprof.out',
without any execution counts.
- NOTE: The '--pretty-print' option still runs your program. This
- will change in the next major release.
+ NOTE: Once upon a time, the '--pretty-print' option would also run
+ your program. This is is no longer the case.
+
+ There is a significant difference between the output created when
+profiling, and that created when pretty-printing. Pretty-printed output
+preserves the original comments that were in the program, although their
+placement may not correspond exactly to their original locations in the
+source code.(1)
+
+ However, as a deliberate design decision, profiling output _omits_
+the original program's comments. This allows you to focus on the
+execution count data and helps you avoid the temptation to use the
+profiler for pretty-printing.
+
+ Additionally, pretty-printed output does not have the leading
+indentation that the profiling output does. This makes it easy to
+pretty-print your code once development is completed, and then use the
+result as the final version of your program.
+
+ Because the internal representation of your program is formatted to
+recreate an 'awk' program, profiling and pretty-printing automatically
+disable 'gawk''s default optimizations.
+
+ Pretty printing also preserves the original format of numeric
+constants; if you used an octal or hexadecimal value in your source
+code, it will appear that way in the output.
+
+ ---------- Footnotes ----------
+
+ (1) 'gawk' does the best it can to preserve the distinction between
+comments at the end of a statement and comments on lines by themselves.
+Due to implementation constraints, it does not always do so correctly,
+particularly for 'switch' statements. The 'gawk' maintainers hope to
+improve this in a subsequent release.

File: gawk.info, Node: Advanced Features Summary, Prev: Profiling, Up: Advanced Features
@@ -20071,8 +20751,7 @@ File: gawk.info, Node: Advanced Features Summary, Prev: Profiling, Up: Advanc
'USR1' signal while profiling causes 'gawk' to dump the profile and
keep going, including a function call stack.
- * You can also just "pretty-print" the program. This currently also
- runs the program, but that will change in the next major release.
+ * You can also just "pretty-print" the program.

File: gawk.info, Node: Internationalization, Next: Debugger, Prev: Advanced Features, Up: Top
@@ -21797,6 +22476,9 @@ File: gawk.info, Node: Debugging Summary, Prev: Limitations, Up: Debugger
it is used by the debugger to provide command-line history and
editing.
+ * Usually, the debugger does not not affect the program being
+ debugged, but occasionally it can.
+

File: gawk.info, Node: Arbitrary Precision Arithmetic, Next: Dynamic Extensions, Prev: Debugger, Up: Top
@@ -21824,6 +22506,7 @@ are not quite in agreement.
* FP Math Caution:: Things to know.
* Arbitrary Precision Integers:: Arbitrary Precision Integer Arithmetic with
'gawk'.
+* Checking for MPFR:: How to check if MPFR is available.
* POSIX Floating Point Problems:: Standards Versus Existing Practice.
* Floating point summary:: Summary of floating point discussion.
@@ -22463,7 +23146,7 @@ library in your system does not use the IEEE 754 even-rounding rule to
round halfway cases for 'printf'.

-File: gawk.info, Node: Arbitrary Precision Integers, Next: POSIX Floating Point Problems, Prev: FP Math Caution, Up: Arbitrary Precision Arithmetic
+File: gawk.info, Node: Arbitrary Precision Integers, Next: Checking for MPFR, Prev: FP Math Caution, Up: Arbitrary Precision Arithmetic
15.5 Arbitrary-Precision Integer Arithmetic with 'gawk'
=======================================================
@@ -22530,6 +23213,62 @@ the following:
gawk -M 'BEGIN { n = 13; print n % 2 }'
+ When dividing two arbitrary precision integers with either '/' or
+'%', the result is typically an arbitrary precision floating point value
+(unless the denominator evenly divides into the numerator). In order to
+do integer division or remainder with arbitrary precision integers, use
+the built-in 'intdiv()' function (*note Numeric Functions::).
+
+ You can simulate the 'intdiv()' function in standard 'awk' using this
+user-defined function:
+
+ # intdiv --- do integer division
+
+ function intdiv(numerator, denominator, result)
+ {
+ split("", result)
+
+ numerator = int(numerator)
+ denominator = int(denominator)
+ result["quotient"] = int(numerator / denominator)
+ result["remainder"] = int(numerator % denominator)
+
+ return 0.0
+ }
+
+ The following example program, contributed by Katie Wasserman, uses
+'intdiv()' to compute the digits of pi to as many places as you choose
+to set:
+
+ # pi.awk --- compute the digits of pi
+
+ BEGIN {
+ digits = 100000
+ two = 2 * 10 ^ digits
+ pi = two
+ for (m = digits * 4; m > 0; --m) {
+ d = m * 2 + 1
+ x = pi * m
+ intdiv(x, d, result)
+ pi = result["quotient"]
+ pi = pi + two
+ }
+ print pi
+ }
+
+ When asked about the algorithm used, Katie replied:
+
+ It's not that well known but it's not that obscure either. It's
+ Euler's modification to Newton's method for calculating pi. Take a
+ look at lines (23) - (25) here:
+ <http://mathworld.wolfram.com/PiFormulas.html>.
+
+ The algorithm I wrote simply expands the multiply by 2 and works
+ from the innermost expression outwards. I used this to program HP
+ calculators because it's quite easy to modify for tiny memory
+ devices with smallish word sizes. See
+ <http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899>.
+
---------- Footnotes ----------
(1) Weisstein, Eric W. 'Sylvester's Sequence'. From MathWorld--A
@@ -22537,9 +23276,46 @@ Wolfram Web Resource
(<http://mathworld.wolfram.com/SylvestersSequence.html>).

-File: gawk.info, Node: POSIX Floating Point Problems, Next: Floating point summary, Prev: Arbitrary Precision Integers, Up: Arbitrary Precision Arithmetic
+File: gawk.info, Node: Checking for MPFR, Next: POSIX Floating Point Problems, Prev: Arbitrary Precision Integers, Up: Arbitrary Precision Arithmetic
+
+15.6 How To Check If MPFR Is Available
+======================================
+
+Occasionally, you might like to be able to check if 'gawk' was invoked
+with the '-M' option, enabling arbitrary-precision arithmetic. You can
+do so with the following function, contributed by Andrew Schorr:
+
+ # adequate_math_precision --- return true if we have enough bits
+
+ function adequate_math_precision(n)
+ {
+ return (1 != (1+(1/(2^(n-1)))))
+ }
+
+ Here is code that invokes the function in order to check if
+arbitrary-precision arithmetic is available:
+
+ BEGIN {
+ # How many bits of mantissa precision are required
+ # for this program to function properly?
+ fpbits = 123
+
+ # We hope that we were invoked with MPFR enabled. If so, the
+ # following statement should configure calculations to our desired
+ # precision.
+ PREC = fpbits
+
+ if (! adequate_math_precision(fpbits)) {
+ print("Error: insufficient computation precision available.\n" \
+ "Try again with the -M argument?") > "/dev/stderr"
+ exit 1
+ }
+ }
+
+
+File: gawk.info, Node: POSIX Floating Point Problems, Next: Floating point summary, Prev: Checking for MPFR, Up: Arbitrary Precision Arithmetic
-15.6 Standards Versus Existing Practice
+15.7 Standards Versus Existing Practice
=======================================
Historically, 'awk' has converted any nonnumeric-looking string to the
@@ -22626,7 +23402,7 @@ and infinity values. The solution implemented in 'gawk' is as follows:

File: gawk.info, Node: Floating point summary, Prev: POSIX Floating Point Problems, Up: Arbitrary Precision Arithmetic
-15.7 Summary
+15.8 Summary
============
* Most computer arithmetic is done using either integers or
@@ -22892,8 +23668,11 @@ API in detail.
* Symbol Table Access:: Functions for accessing global
variables.
* Array Manipulation:: Functions for working with arrays.
+* Redirection API:: How to access and manipulate
+ redirections.
* Extension API Variables:: Variables provided by the API.
* Extension API Boilerplate:: Boilerplate code for using the API.
+* Changes from API V1:: Changes from V1 of the API.

File: gawk.info, Node: Extension API Functions Introduction, Next: General Data Types, Up: Extension API Description
@@ -22947,6 +23726,8 @@ operations:
- Flattening an array for easy C-style looping over all its
indices and elements
+ * Accessing and manipulating redirections.
+
Some points about using the API:
* The following types, macros, and/or functions are referenced in
@@ -22987,16 +23768,25 @@ operations:
* The API defines several simple 'struct's that map values as seen
from 'awk'. A value can be a 'double', a string, or an array (as
- in multidimensional arrays, or when creating a new array). String
- values maintain both pointer and length, because embedded NUL
- characters are allowed.
+ in multidimensional arrays, or when creating a new array).
+
+ String values maintain both pointer and length, because embedded
+ NUL characters are allowed.
- NOTE: By intent, strings are maintained using the current
+ NOTE: By intent, 'gawk' maintains strings using the current
multibyte encoding (as defined by 'LC_XXX' environment
variables) and not using wide characters. This matches how
'gawk' stores strings internally and also how characters are
likely to be input into and output from files.
+ NOTE: String values passed to an extension by 'gawk' are
+ always NUL-terminated. Thus it is safe to pass such string
+ values to standard library and system routines. However,
+ because 'gawk' allows embedded NUL characters in string data,
+ before using the data as a regular C string, you should check
+ that the length for that string passed to the extension
+ matches the return value of 'strlen()' for it.
+
* When retrieving a value (such as a parameter or that of a global
variable or array element), the extension requests a specific type
(number, string, scalar, value cookie, array, or "undefined").
@@ -23067,6 +23857,8 @@ use them.
' AWK_UNDEFINED,'
' AWK_NUMBER,'
' AWK_STRING,'
+' AWK_REGEX,'
+' AWK_STRNUM,'
' AWK_ARRAY,'
' AWK_SCALAR, /* opaque access to a variable */'
' AWK_VALUE_COOKIE /* for updating a previously created value */'
@@ -23089,6 +23881,8 @@ use them.
type.
'#define str_value u.s'
+'#define strnum_value str_value'
+'#define regex_value str_value'
'#define num_value u.d'
'#define array_cookie u.a'
'#define scalar_cookie u.scl'
@@ -23107,15 +23901,35 @@ use them.
This is also discussed in a general fashion in the text following
this list, and in more detail in *note Cached values::.
- Scalar values in 'awk' are either numbers or strings. The
-'awk_value_t' struct represents values. The 'val_type' member indicates
-what is in the 'union'.
+ Scalar values in 'awk' are numbers, strings, strnums, or typed
+regexps. The 'awk_value_t' struct represents values. The 'val_type'
+member indicates what is in the 'union'.
Representing numbers is easy--the API uses a C 'double'. Strings
require more work. Because 'gawk' allows embedded NUL bytes in string
values, a string must be represented as a pair containing a data pointer
and length. This is the 'awk_string_t' type.
+ A strnum (numeric string) value is represented as a string and
+consists of user input data that appears to be numeric. When an
+extension creates a strnum value, the result is a string flagged as user
+input. Subsequent parsing by 'gawk' then determines whether it looks
+like a number and should be treated as a strnum, or as a regular string.
+
+ This is useful in cases where an extension function would like to do
+something comparable to the 'split()' function which sets the strnum
+attribute on the array elements it creates. For example, an extension
+that implements CSV splitting would want to use this feature. This is
+also useful for a function that retrieves a data item from a database.
+The PostgreSQL 'PQgetvalue()' function, for example, returns a string
+that may be numeric or textual depending on the contents.
+
+ Typed regexp values (*note Strong Regexp Constants::) are not of much
+use to extension functions. Extension functions can tell that they've
+received them, and create them for scalar values. Otherwise, they can
+examine the text of the regexp through 'regex_value.str' and
+'regex_value.len'.
+
Identifiers (i.e., the names of global variables) can be associated
with either scalar values or with arrays. In addition, 'gawk' provides
true arrays of arrays, where any given array element can itself be an
@@ -23195,10 +24009,11 @@ library than was used for the 'gawk' executable.(1) If 'gawk' were to
use its version of 'free()' when the memory came from an unrelated
version of 'malloc()', unexpected behavior would likely result.
- Two convenience macros may be used for allocating storage from
-'gawk_malloc()' and 'gawk_realloc()'. If the allocation fails, they
-cause 'gawk' to exit with a fatal error message. They should be used as
-if they were procedure calls that do not return a value:
+ Three convenience macros may be used for allocating storage from
+'gawk_malloc()', 'gawk_calloc', and 'gawk_realloc()'. If the allocation
+fails, they cause 'gawk' to exit with a fatal error message. They
+should be used as if they were procedure calls that do not return a
+value:
'#define emalloc(pointer, type, size, message) ...'
The arguments to this macro are as follows:
@@ -23227,6 +24042,12 @@ if they were procedure calls that do not return a value:
strcpy(message, greet);
make_malloced_string(message, strlen(message), & result);
+'#define ezalloc(pointer, type, size, message) ...'
+ This is like 'emalloc()', but it calls 'gawk_calloc()' instead of
+ 'gawk_malloc()'. The arguments are the same as for the 'emalloc()'
+ macro, but this macro guarantees that the memory returned is
+ initialized to zero.
+
'#define erealloc(pointer, type, size, message) ...'
This is like 'emalloc()', but it calls 'gawk_realloc()' instead of
'gawk_malloc()'. The arguments are the same as for the 'emalloc()'
@@ -23275,6 +24096,31 @@ code would use them:
This function simply creates a numeric value in the 'awk_value_t'
variable pointed to by 'result'.
+'static inline awk_value_t *'
+'make_const_user_input(const char *string, size_t length, awk_value_t *result);'
+ This function is identical to 'make_const_string()', but the string
+ is flagged as user input that should be treated as a strnum value
+ if the contents of the string are numeric.
+
+'static inline awk_value_t *'
+'make_malloced_user_input(const char *string, size_t length, awk_value_t *result);'
+ This function is identical to 'make_malloced_string()', but the
+ string is flagged as user input that should be treated as a strnum
+ value if the contents of the string are numeric.
+
+'static inline awk_value_t *'
+'make_const_regex(const char *string, size_t length, awk_value_t *result);'
+ This function creates a strongly typed regexp value by allocating a
+ copy of the string. 'string' is the regular expression of length
+ 'len'.
+
+'static inline awk_value_t *'
+'make_malloced_regex(const char *string, size_t length, awk_value_t *result);'
+ This function creates a strongly typed regexp value. 'string' is
+ the regular expression of length 'len'. It expects 'string' to be
+ a 'char *' value pointing to data previously obtained from
+ 'gawk_malloc()', 'gawk_calloc()', or 'gawk_realloc()'.
+

File: gawk.info, Node: Registration Functions, Next: Printing Messages, Prev: Constructor Functions, Up: Extension API Description
@@ -23303,8 +24149,13 @@ Extension functions are described by the following record:
typedef struct awk_ext_func {
const char *name;
- awk_value_t *(*function)(int num_actual_args, awk_value_t *result);
- size_t num_expected_args;
+ awk_value_t *(*const function)(int num_actual_args,
+ awk_value_t *result,
+ struct awk_ext_func *finfo);
+ const size_t max_expected_args;
+ const size_t min_required_args;
+ awk_bool_t suppress_lint;
+ void *data; /* opaque pointer to any extra state */
} awk_ext_func_t;
The fields are:
@@ -23318,34 +24169,89 @@ Extension functions are described by the following record:
which may be followed by any number of letters, digits, and
underscores. Letter case in function names is significant.
-'awk_value_t *(*function)(int num_actual_args, awk_value_t *result);'
+'awk_value_t *(*const function)(int num_actual_args,'
+' awk_value_t *result,'
+' struct awk_ext_func *finfo);'
This is a pointer to the C function that provides the extension's
functionality. The function must fill in '*result' with either a
- number or a string. 'gawk' takes ownership of any string memory.
- As mentioned earlier, string memory _must_ come from one of
- 'gawk_malloc()', 'gawk_calloc()', or 'gawk_realloc()'.
+ number, a string, or a regexp. 'gawk' takes ownership of any
+ string memory. As mentioned earlier, string memory _must_ come
+ from one of 'gawk_malloc()', 'gawk_calloc()', or 'gawk_realloc()'.
The 'num_actual_args' argument tells the C function how many actual
parameters were passed from the calling 'awk' code.
+ The 'finfo' parameter is a pointer to the 'awk_ext_func_t' for this
+ function. The called function may access data within it as
+ desired, or not.
+
The function must return the value of 'result'. This is for the
convenience of the calling code inside 'gawk'.
-'size_t num_expected_args;'
- This is the number of arguments the function expects to receive.
- Each extension function may decide what to do if the number of
- arguments isn't what it expected. As with real 'awk' functions, it
- is likely OK to ignore extra arguments.
+'const size_t max_expected_args;'
+ This is the maximum number of arguments the function expects to
+ receive. If called with more arguments than this, and if lint
+ checking has been enabled, then 'gawk' prints a warning message.
+ For more information, see the entry for 'suppress_lint', later in
+ this list.
+
+'const size_t min_required_args;'
+ This is the minimum number of arguments the function expects to
+ receive. If called with fewer arguments, 'gawk' prints a fatal
+ error message and exits.
+
+'awk_bool_t suppress_lint;'
+ This flag tells 'gawk' not to print a lint message if lint checking
+ has been enabled and if more arguments were supplied in the call
+ than expected. An extension function can tell if 'gawk' already
+ printed at least one such message by checking if 'num_actual_args >
+ finfo->max_expected_args'. If so, and the function does not want
+ more lint messages to be printed, it should set
+ 'finfo->suppress_lint' to 'awk_true'.
+
+'void *data;'
+ This is an opaque pointer to any data that an extension function
+ may wish to have available when called. Passing the
+ 'awk_ext_func_t' structure to the extension function, and having
+ this pointer available in it enable writing a single C or C++
+ function that implements multiple 'awk'-level extension functions.
Once you have a record representing your extension function, you
register it with 'gawk' using this API function:
-'awk_bool_t add_ext_func(const char *namespace, const awk_ext_func_t *func);'
+'awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func);'
This function returns true upon success, false otherwise. The
'namespace' parameter is currently not used; you should pass in an
empty string ('""'). The 'func' pointer is the address of a
'struct' representing your function, as just described.
+ 'gawk' does not modify what 'func' points to, but the extension
+ function itself receives this pointer and can modify what it points
+ to, thus it is purposely not declared to be 'const'.
+
+ The combination of 'min_required_args', 'max_expected_args', and
+'suppress_lint' may be confusing. Here is how you should set things up.
+
+Any number of arguments is valid
+ Set 'min_required_args' and 'max_expected_args' to zero and set
+ 'suppress_lint' to 'awk_true'.
+
+A minimum number of arguments is required, no limit on maximum number of arguments
+ Set 'min_required_args' to the minimum required. Set
+ 'max_expected_args' to zero and set 'suppress_lint' to 'awk_true'.
+
+A minimum number of arguments is required, a maximum number is expected
+ Set 'min_required_args' to the minimum required. Set
+ 'max_expected_args' to the maximum expected. Set 'suppress_lint'
+ to 'awk_false'.
+
+A minimum number of arguments is required, and no more than a maximum is allowed
+ Set 'min_required_args' to the minimum required. Set
+ 'max_expected_args' to the maximum expected. Set 'suppress_lint'
+ to 'awk_false'. In your extension function, check that
+ 'num_actual_args' does not exceed 'f->max_expected_args'. If it
+ does, issue a fatal error message.
+

File: gawk.info, Node: Exit Callback Functions, Next: Extension Version String, Prev: Extension Functions, Up: Registration Functions
@@ -23470,7 +24376,8 @@ for 'RT', if any.
#define INVALID_HANDLE (-1)
void *opaque; /* private data for input parsers */
int (*get_record)(char **out, struct awk_input *iobuf,
- int *errcode, char **rt_start, size_t *rt_len);
+ int *errcode, char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **field_width);
ssize_t (*read_func)();
void (*close_func)(struct awk_input *iobuf);
struct stat sbuf; /* stat buf */
@@ -23516,7 +24423,8 @@ may be filled by 'XXX_take_control_of()':
' struct awk_input *iobuf,'
' int *errcode,'
' char **rt_start,'
-' size_t *rt_len);'
+' size_t *rt_len,'
+' const awk_fieldwidth_info_t **field_width);'
This function pointer should point to a function that creates the
input records. Said function is the core of the input parser. Its
behavior is described in the text following this list.
@@ -23566,6 +24474,20 @@ records. The parameters are as follows:
'*rt_len' should be set to zero. 'gawk' makes its own copy of this
data, so the extension must manage this storage.
+'const awk_fieldwidth_info_t **field_width'
+ If 'field_width' is not 'NULL', then '*field_width' will be
+ initialized to 'NULL', and the function may set it to point to a
+ structure supplying field width information to override the default
+ field parsing mechanism. Note that this structure will not be
+ copied by 'gawk'; it must persist at least until the next call to
+ 'get_record' or 'close_func'. Note also that 'field_width' is
+ 'NULL' when 'getline' is assigning the results to a variable, thus
+ field parsing is not needed. If the parser does set
+ '*field_width', then 'gawk' uses this layout to parse the input
+ record, and the 'PROCINFO["FS"]' value will be '"API"' while this
+ record is active in '$0'. The 'awk_fieldwidth_info_t' data
+ structure is described below.
+
The return value is the length of the buffer pointed to by '*out', or
'EOF' if end-of-file was reached or an error occurred.
@@ -23615,6 +24537,46 @@ activate an input parser (*note BEGINFILE/ENDFILE::).
'void register_input_parser(awk_input_parser_t *input_parser);'
Register the input parser pointed to by 'input_parser' with 'gawk'.
+ If you would like to override the default field parsing mechanism for
+a given record, then you must populate an 'awk_fieldwidth_info_t'
+structure, which looks like this:
+
+ typedef struct {
+ awk_bool_t use_chars; /* false ==> use bytes */
+ size_t nf; /* number of fields in record (NF) */
+ struct awk_field_info {
+ size_t skip; /* amount to skip before field starts */
+ size_t len; /* length of field */
+ } fields[1]; /* actual dimension should be nf */
+ } awk_fieldwidth_info_t;
+
+ The fields are:
+
+'awk_bool_t use_chars;'
+ Set this to 'awk_true' if the field lengths are specified in terms
+ of potentially multi-byte characters, and set it to 'awk_false' if
+ the lengths are in terms of bytes. Performance will be better if
+ the values are supplied in terms of bytes.
+
+'size_t nf;'
+ Set this to the number of fields in the input record, i.e. 'NF'.
+
+'struct awk_field_info fields[nf];'
+ This is a variable-length array whose actual dimension should be
+ 'nf'. For each field, the 'skip' element should be set to the
+ number of characters or bytes, as controlled by the 'use_chars'
+ flag, to skip before the start of this field. The 'len' element
+ provides the length of the field. The values in 'fields[0]'
+ provide the information for '$1', and so on through the
+ 'fields[nf-1]' element containing the information for '$NF'.
+
+ A convenience macro 'awk_fieldwidth_info_size(NF)' is provided to
+calculate the appropriate size of a variable-length
+'awk_fieldwidth_info_t' structure containing 'NF' fields. This can be
+used as an argument to 'malloc()' or in a union to allocate space
+statically. Please refer to the 'readdir_test' sample extension for an
+example.
+

File: gawk.info, Node: Output Wrappers, Next: Two-way processors, Prev: Input Parsers, Up: Registration Functions
@@ -23788,6 +24750,9 @@ extension ID received from 'gawk' when the extension was loaded:(1)
'void fatal(awk_ext_id_t id, const char *format, ...);'
Print a message and then cause 'gawk' to exit immediately.
+'void nonfatal(awk_ext_id_t id, const char *format, ...);'
+ Print a nonfatal error message.
+
'void warning(awk_ext_id_t id, const char *format, ...);'
Print a warning message.
@@ -23844,18 +24809,17 @@ summarized in *note Table 16.1: table-value-types-returned.
Type of Actual Value
--------------------------------------------------------------------------
- String Number Array Undefined
-------------------------------------------------------------------------------
- String String String False False
- Number Number if Number False False
- can be
- converted,
- else false
-Type Array False False Array False
-Requested Scalar Scalar Scalar False False
- Undefined String Number Array Undefined
- Value False False False False
- cookie
+ String Strnum Number Regex Array Undefined
+-------------------------------------------------------------------------------
+ String String String String String false false
+ Strnum false Strnum Strnum false false false
+ Number Number Number Number false false false
+Type Regex false false false Regex false false
+Requested Array false false false false Array false
+ Scalar Scalar Scalar Scalar Scalar false false
+ Undefined String Strnum Number Regex Array Undefined
+ Value false false false false false false
+ cookie
Table 16.1: API value types returned
@@ -23936,11 +24900,6 @@ termed a "symbol table". The functions are as follows:
However, with the exception of the 'PROCINFO' array, an extension cannot
change any of those variables.
- CAUTION: It is possible for the lookup of 'PROCINFO' to fail. This
- happens if the 'awk' program being run does not reference
- 'PROCINFO'; in this case, 'gawk' doesn't bother to create the array
- and populate it.
-

File: gawk.info, Node: Symbol table by cookie, Next: Cached values, Prev: Symbol table by name, Up: Symbol Table Access
@@ -23964,8 +24923,9 @@ was discussed earlier, in *note General Data Types::.
'awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *value);'
Update the value associated with a scalar cookie. Return false if
- the new value is not of type 'AWK_STRING' or 'AWK_NUMBER'. Here
- too, the predefined variables may not be updated.
+ the new value is not of type 'AWK_STRING', 'AWK_STRNUM',
+ 'AWK_REGEX', or 'AWK_NUMBER'. Here too, the predefined variables
+ may not be updated.
It is not obvious at first glance how to work with scalar cookies or
what their raison d'e^tre really is. In theory, the 'sym_lookup()' and
@@ -24079,10 +25039,10 @@ follows:
'awk_bool_t create_value(awk_value_t *value, awk_value_cookie_t *result);'
Create a cached string or numeric value from 'value' for efficient
- later assignment. Only values of type 'AWK_NUMBER' and
- 'AWK_STRING' are allowed. Any other type is rejected.
- 'AWK_UNDEFINED' could be allowed, but doing so would result in
- inferior performance.
+ later assignment. Only values of type 'AWK_NUMBER', 'AWK_REGEX',
+ 'AWK_STRNUM', and 'AWK_STRING' are allowed. Any other type is
+ rejected. 'AWK_UNDEFINED' could be allowed, but doing so would
+ result in inferior performance.
'awk_bool_t release_value(awk_value_cookie_t vc);'
Release the memory associated with a value cookie obtained from
@@ -24152,7 +25112,7 @@ using 'release_value()'.
'double' to store.

-File: gawk.info, Node: Array Manipulation, Next: Extension API Variables, Prev: Symbol Table Access, Up: Extension API Description
+File: gawk.info, Node: Array Manipulation, Next: Redirection API, Prev: Symbol Table Access, Up: Extension API Description
16.4.11 Array Manipulation
--------------------------
@@ -24309,12 +25269,21 @@ The following functions relate to individual array elements:
array, but after calling this function, it has no elements. This
is equivalent to using the 'delete' statement (*note Delete::).
+'awk_bool_t flatten_array_typed(awk_array_t a_cookie, awk_flat_array_t **data, awk_valtype_t index_type, awk_valtype_t value_type);'
+ For the array represented by 'a_cookie', create an
+ 'awk_flat_array_t' structure and fill it in with indices and values
+ of the requested types. Set the pointer whose address is passed as
+ 'data' to point to this structure. Return true upon success, or
+ false otherwise. *Note Flattening Arrays::, for a discussion of
+ how to flatten an array and work with it.
+
'awk_bool_t flatten_array(awk_array_t a_cookie, awk_flat_array_t **data);'
For the array represented by 'a_cookie', create an
- 'awk_flat_array_t' structure and fill it in. Set the pointer whose
- address is passed as 'data' to point to this structure. Return
- true upon success, or false otherwise. *Note Flattening Arrays::,
- for a discussion of how to flatten an array and work with it.
+ 'awk_flat_array_t' structure and fill it in with 'AWK_STRING'
+ indices and 'AWK_UNDEFINED' values. This is superseded by
+ 'flatten_array_typed()'. It is provided as a macro, and remains
+ for convenience and for source code compatibility with the previous
+ version of the API.
'awk_bool_t release_flattened_array(awk_array_t a_cookie,'
' awk_flat_array_t *data);'
@@ -24416,7 +25385,7 @@ count of elements in the array and print it:
double-check that the count in the 'awk_flat_array_t' is the same as the
count just retrieved:
- if (! flatten_array(value2.array_cookie, & flat_array)) {
+ if (! flatten_array_typed(value2.array_cookie, & flat_array, AWK_STRING, AWK_UNDEFINED)) {
printf("dump_array_and_delete: could not flatten array\n");
goto out;
}
@@ -24636,9 +25605,78 @@ array:
environment variable.)

-File: gawk.info, Node: Extension API Variables, Next: Extension API Boilerplate, Prev: Array Manipulation, Up: Extension API Description
+File: gawk.info, Node: Redirection API, Next: Extension API Variables, Prev: Array Manipulation, Up: Extension API Description
+
+16.4.12 Accessing and Manipulating Redirections
+-----------------------------------------------
+
+The following function allows extensions to access and manipulate
+redirections.
+
+'awk_bool_t get_file(const char *name,'
+' size_t name_len,'
+' const char *filetype,'
+' int fd,'
+' const awk_input_buf_t **ibufp,'
+' const awk_output_buf_t **obufp);'
+ Look up file 'name' in 'gawk''s internal redirection table. If
+ 'name' is 'NULL' or 'name_len' is zero, return data for the
+ currently open input file corresponding to 'FILENAME'. (This does
+ not access the 'filetype' argument, so that may be undefined). If
+ the file is not already open, attempt to open it. The 'filetype'
+ argument must be zero-terminated and should be one of:
+
+ '">"'
+ A file opened for output.
+
+ '">>"'
+ A file opened for append.
+
+ '"<"'
+ A file opened for input.
+
+ '"|>"'
+ A pipe opened for output.
+
+ '"|<"'
+ A pipe opened for input.
+
+ '"|&"'
+ A two-way coprocess.
+
+ On error, return an 'awk_false' value. Otherwise, return
+ 'awk_true', and return additional information about the redirection
+ in the 'ibufp' and 'obufp' pointers. For input redirections, the
+ '*ibufp' value should be non-'NULL', and '*obufp' should be 'NULL'.
+ For output redirections, the '*obufp' value should be non-'NULL',
+ and '*ibufp' should be 'NULL'. For two-way coprocesses, both
+ values should be non-'NULL'.
+
+ In the usual case, the extension is interested in '(*ibufp)->fd'
+ and/or 'fileno((*obufp)->fp)'. If the file is not already open,
+ and the 'fd' argument is nonnegative, 'gawk' will use that file
+ descriptor instead of opening the file in the usual way. If 'fd'
+ is nonnegative, but the file exists already, 'gawk' ignores 'fd'
+ and returns the existing file. It is the caller's responsibility
+ to notice that neither the 'fd' in the returned 'awk_input_buf_t'
+ nor the 'fd' in the returned 'awk_output_buf_t' matches the
+ requested value.
+
+ Note that supplying a file descriptor is currently _not_ supported
+ for pipes. However, supplying a file descriptor should work for
+ input, output, append, and two-way (coprocess) sockets. If
+ 'filetype' is two-way, 'gawk' assumes that it is a socket! Note
+ that in the two-way case, the input and output file descriptors may
+ differ. To check for success, you must check whether either
+ matches.
+
+ It is anticipated that this API function will be used to implement
+I/O multiplexing and a socket library.
+
+
+File: gawk.info, Node: Extension API Variables, Next: Extension API Boilerplate, Prev: Redirection API, Up: Extension API Description
-16.4.12 API Variables
+16.4.13 API Variables
---------------------
The API provides two sets of variables. The first provides information
@@ -24655,7 +25693,7 @@ information about how 'gawk' was invoked.

File: gawk.info, Node: Extension Versioning, Next: Extension API Informational Variables, Up: Extension API Variables
-16.4.12.1 API Version Constants and Variables
+16.4.13.1 API Version Constants and Variables
.............................................
The API provides both a "major" and a "minor" version number. The API
@@ -24663,10 +25701,10 @@ versions are available at compile time as C preprocessor defines to
support conditional compilation, and as enum constants to facilitate
debugging:
-API Version C preprocessor define enum constant
----------------------------------------------------------------------------
-Major gawk_api_major_version GAWK_API_MAJOR_VERSION
-Minor gawk_api_minor_version GAWK_API_MINOR_VERSION
+API Version C Preprocessor Define enum constant
+--------------------------------------------------------------------
+Major 'gawk_api_major_version' 'GAWK_API_MAJOR_VERSION'
+Minor 'gawk_api_minor_version' 'GAWK_API_MINOR_VERSION'
Table 16.2: gawk API version constants
@@ -24683,10 +25721,10 @@ For this reason, the major and minor API versions of the running 'gawk'
are included in the API 'struct' as read-only constant integers:
'api->major_version'
- The major version of the running 'gawk'
+ The major version of the running 'gawk'.
'api->minor_version'
- The minor version of the running 'gawk'
+ The minor version of the running 'gawk'.
It is up to the extension to decide if there are API
incompatibilities. Typically, a check like this is enough:
@@ -24707,7 +25745,7 @@ Boilerplate::).

File: gawk.info, Node: Extension API Informational Variables, Prev: Extension Versioning, Up: Extension API Variables
-16.4.12.2 Informational Variables
+16.4.13.2 Informational Variables
.................................
The API provides access to several variables that describe whether the
@@ -24740,9 +25778,9 @@ predefined variable (*note Built-in Variables::). The others should not
change during execution.

-File: gawk.info, Node: Extension API Boilerplate, Prev: Extension API Variables, Up: Extension API Description
+File: gawk.info, Node: Extension API Boilerplate, Next: Changes from API V1, Prev: Extension API Variables, Up: Extension API Description
-16.4.13 Boilerplate Code
+16.4.14 Boilerplate Code
------------------------
As mentioned earlier (*note Extension Mechanism Outline::), the function
@@ -24760,7 +25798,7 @@ the 'gawkapi.h' header file:
static const char *ext_version = NULL; /* or ... = "some string" */
static awk_ext_func_t func_table[] = {
- { "name", do_name, 1 },
+ { "name", do_name, 1, 0, awk_false, NULL },
/* ... */
};
@@ -24841,6 +25879,22 @@ does the following:
'gawk'.

+File: gawk.info, Node: Changes from API V1, Prev: Extension API Boilerplate, Up: Extension API Description
+
+16.4.15 Changes From Version 1 of the API
+-----------------------------------------
+
+The current API is _not_ binary compatible with version 1 of the API.
+You will have to recompile your extensions in order to use them with the
+current version of 'gawk'.
+
+ Fortunately, at the possible expense of some compile-time warnings,
+the API remains source-code-compatible with the previous API. The major
+differences are the additional members in the 'awk_ext_func_t'
+structure, and the addition of the third argument to the C
+implementation function.
+
+
File: gawk.info, Node: Finding Extensions, Next: Extension Example, Prev: Extension API Description, Up: Dynamic Extensions
16.5 How 'gawk' Finds Extensions
@@ -25057,24 +26111,20 @@ is a pointer to an 'awk_value_t' structure, usually named 'result':
/* do_chdir --- provide dynamically loaded chdir() function for gawk */
static awk_value_t *
- do_chdir(int nargs, awk_value_t *result)
+ do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t newdir;
int ret = -1;
assert(result != NULL);
- if (do_lint && nargs != 1)
- lintwarn(ext_id,
- _("chdir: called with incorrect number of arguments, "
- "expecting 1"));
-
The 'newdir' variable represents the new directory to change to,
which is retrieved with 'get_argument()'. Note that the first argument
is numbered zero.
If the argument is retrieved successfully, the function calls the
-'chdir()' system call. If the 'chdir()' fails, 'ERRNO' is updated:
+'chdir()' system call. Otherwise, if the 'chdir()' fails, it updates
+'ERRNO':
if (get_argument(0, AWK_STRING, & newdir)) {
ret = chdir(newdir.str_value.str);
@@ -25261,7 +26311,7 @@ declarations and argument checking:
/* do_stat --- provide a stat() function for gawk */
static awk_value_t *
- do_stat(int nargs, awk_value_t *result)
+ do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t file_param, array_param;
char *name;
@@ -25273,13 +26323,6 @@ declarations and argument checking:
assert(result != NULL);
- if (nargs != 2 && nargs != 3) {
- if (do_lint)
- lintwarn(ext_id,
- _("stat: called with wrong number of arguments"));
- return make_number(-1, result);
- }
-
Then comes the actual work. First, the function gets the arguments.
Next, it gets the information for the file. If the called function
('lstat()' or 'stat()') returns an error, the code sets 'ERRNO' and
@@ -25336,11 +26379,9 @@ there is an initialization function:
for loading each function into 'gawk':
static awk_ext_func_t func_table[] = {
- { "chdir", do_chdir, 1 },
- { "stat", do_stat, 2 },
- #ifndef __MINGW32__
- { "fts", do_fts, 3 },
- #endif
+ { "chdir", do_chdir, 1, 1, awk_false, NULL },
+ { "stat", do_stat, 3, 2, awk_false, NULL },
+ ...
};
Each extension must have a routine named 'dl_load()' to load
@@ -26070,15 +27111,17 @@ project.
* GD graphics library extension
+ * MPFR library extension (this provides access to a number of MPFR
+ functions that 'gawk''s native MPFR support does not)
+
* PDF extension
* PostgreSQL extension
- * MPFR library extension (this provides access to a number of MPFR
- functions that 'gawk''s native MPFR support does not)
-
* Redis extension
+ * Select extension
+
* XML parser extension, using the Expat
(http://expat.sourceforge.net) XML parsing library
@@ -26156,7 +27199,7 @@ File: gawk.info, Node: Extension summary, Next: Extension Exercises, Prev: ga
exit callbacks, a version string, input parsers, output
wrappers, and two-way processors)
- * Printing fatal, warning, and "lint" warning messages
+ * Printing fatal, nonfatal, warning, and "lint" warning messages
* Updating 'ERRNO', or unsetting it
@@ -26491,6 +27534,9 @@ current version of 'gawk'.
- Directories on the command line produce a warning and are
skipped (*note Command-line directories::)
+ - Output with 'print' and 'printf' need not be fatal (*note
+ Nonfatal::)
+
* New keywords:
- The 'BEGINFILE' and 'ENDFILE' special patterns (*note
@@ -26540,6 +27586,9 @@ current version of 'gawk'.
- The 'bindtextdomain()', 'dcgettext()', and 'dcngettext()'
functions for internationalization (*note Programmer i18n::)
+ - The 'intdiv()' function for doing integer division and
+ remainder (*note Numeric Functions::)
+
* Changes and/or additions in the command-line options:
- The 'AWKPATH' environment variable for specifying a path
@@ -26550,16 +27599,16 @@ current version of 'gawk'.
- The '-b', '-c', '-C', '-d', '-D', '-e', '-E', '-g', '-h',
'-i', '-l', '-L', '-M', '-n', '-N', '-o', '-O', '-p', '-P',
- '-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',
+ '-r', '-s', '-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', '--exec',
'--field-separator', '--file', '--gen-pot', '--help',
'--include', '--lint', '--lint-old', '--load',
- '--non-decimal-data', '--optimize', '--posix',
- '--pretty-print', '--profile', '--re-interval', '--sandbox',
- '--source', '--traditional', '--use-lc-numeric', and
- '--version' long options (*note Options::).
+ '--non-decimal-data', '--optimize', '--no-optimize',
+ '--posix', '--pretty-print', '--profile', '--re-interval',
+ '--sandbox', '--source', '--traditional', '--use-lc-numeric',
+ and '--version' long options (*note Options::).
* Support for the following obsolete systems was removed from the
code and the documentation for 'gawk' version 4.0:
@@ -26593,6 +27642,13 @@ current version of 'gawk'.
- Ultrix
+ * Support for the following systems was removed from the code for
+ 'gawk' version 4.2:
+
+ - MirBSD
+
+ - GNU/Linux on Alpha
+

File: gawk.info, Node: Feature History, Next: Common Extensions, Prev: POSIX/GNU, Up: Language History
@@ -26984,6 +28040,36 @@ POSIX 'awk', in the order they were added to 'gawk'.
* Support for Ultrix was removed.
+ Version 4.2 introduced the following changes:
+
+ * Changes to 'ENVIRON' are reflected into 'gawk''s environment and
+ that of programs that it runs. *Note Auto-set::.
+
+ * The 'PROCINFO["argv"' array. *Note Auto-set::.
+
+ * The '--pretty-print' option no longer runs the 'awk' program too.
+ *Note Options::.
+
+ * The 'igawk' program and its manual page are no longer installed
+ when 'gawk' is built. *Note Igawk Program::.
+
+ * The 'intdiv()' function. *Note Numeric Functions::.
+
+ * The maximum number of hexadecimal digits in '\x' escapes is now
+ two. *Note Escape Sequences::.
+
+ * Nonfatal output with 'print' and 'printf'. *Note Nonfatal::.
+
+ * For many years, POSIX specified that default field splitting only
+ allowed spaces and tabs to separate fields, and this was how 'gawk'
+ behaved with '--posix'. As of 2013, the standard restored
+ historical behavior, and now default field splitting with '--posix'
+ also allows newlines to separate fields.
+
+ * Support for MirBSD was removed.
+
+ * Support for GNU/Linux on Alpha was removed.
+

File: gawk.info, Node: Common Extensions, Next: Ranges and Locales, Prev: Feature History, Up: Language History
@@ -27098,7 +28184,7 @@ ranges, such that outside the '"C"' and '"POSIX"' locales, the meaning
of range expressions was _undefined_.(3)
By using this lovely technical term, the standard gives license to
-implementors to implement ranges in whatever way they choose. The
+implementers to implement ranges in whatever way they choose. The
'gawk' maintainer chose to apply the pre-POSIX meaning both with the
default regexp matching and when '--traditional' or '--posix' are used.
In all cases 'gawk' remains POSIX-compliant.
@@ -27412,6 +28498,12 @@ to different non-Unix operating systems:
Various '.c', '.y', and '.h' files
These files contain the actual 'gawk' source code.
+'support/*'
+ C header and source files for routines that 'gawk' uses, but that
+ are not part of its core functionality. For example, argument
+ parsing, regular expression matching, and random number generating
+ routines are all kept here.
+
'ABOUT-NLS'
A file containing information about GNU 'gettext' and translations.
@@ -27502,7 +28594,9 @@ Various '.c', '.y', and '.h' files
'doc/igawk.1'
The 'troff' source for a manual page describing the 'igawk' program
- presented in *note Igawk Program::.
+ presented in *note Igawk Program::. (Since 'gawk' can do its own
+ '@include' processing, neither 'igawk' nor 'igawk.1' are
+ installed.)
'doc/Makefile.in'
The input file used during the configuration process to generate
@@ -27544,17 +28638,22 @@ Various '.c', '.y', and '.h' files
contains a 'Makefile.in' file, which 'configure' uses to generate a
'Makefile'. 'Makefile.am' is used by GNU Automake to create
'Makefile.in'. The library functions from *note Library
- Functions::, and the 'igawk' program from *note Igawk Program:: are
- included as ready-to-use files in the 'gawk' distribution. They
- are installed as part of the installation process. The rest of the
- programs in this Info file are available in appropriate
- subdirectories of 'awklib/eg'.
+ Functions::, are included as ready-to-use files in the 'gawk'
+ distribution. They are installed as part of the installation
+ process. The rest of the programs in this Info file are available
+ in appropriate subdirectories of 'awklib/eg'.
'extension/*'
The source code, manual pages, and infrastructure files for the
sample extensions included with 'gawk'. *Note Dynamic
Extensions::, for more information.
+'extras/*'
+ Additional non-essential files. Currently, this directory contains
+ some shell startup files to be installed in '/etc/profile.d' to aid
+ in manipulating the 'AWKPATH' and 'AWKLIBPATH' environment
+ variables. *Note Shell Startup Files::, for more information.
+
'posix/*'
Files needed for building 'gawk' on POSIX-compliant systems.
@@ -27585,11 +28684,12 @@ for your system yourself.
* Menu:
* Quick Installation:: Compiling 'gawk' under Unix.
+* Shell Startup Files:: Shell convenience functions.
* Additional Configuration Options:: Other compile-time options.
* Configuration Philosophy:: How it's all supposed to work.

-File: gawk.info, Node: Quick Installation, Next: Additional Configuration Options, Up: Unix Installation
+File: gawk.info, Node: Quick Installation, Next: Shell Startup Files, Up: Unix Installation
B.2.1 Compiling 'gawk' for Unix-Like Systems
--------------------------------------------
@@ -27644,9 +28744,42 @@ will be asked for your password, and you will have to have been set up
previously as a user who is allowed to run the 'sudo' command.

-File: gawk.info, Node: Additional Configuration Options, Next: Configuration Philosophy, Prev: Quick Installation, Up: Unix Installation
+File: gawk.info, Node: Shell Startup Files, Next: Additional Configuration Options, Prev: Quick Installation, Up: Unix Installation
+
+B.2.2 Shell Startup Files
+-------------------------
+
+The distribution contains shell startup files 'gawk.sh' and 'gawk.csh',
+containing functions to aid in manipulating the 'AWKPATH' and
+'AWKLIBPATH' environment variables. On a Fedora GNU/Linux system, these
+files should be installed in '/etc/profile.d'; on other platforms, the
+appropriate location may be different.
+
+'gawkpath_default'
+ Reset the 'AWKPATH' environment variable to its default value.
+
+'gawkpath_prepend'
+ Add the argument to the front of the 'AWKPATH' environment
+ variable.
+
+'gawkpath_append'
+ Add the argument to the end of the 'AWKPATH' environment variable.
+
+'gawklibpath_default'
+ Reset the 'AWKLIBPATH' environment variable to its default value.
+
+'gawklibpath_prepend'
+ Add the argument to the front of the 'AWKLIBPATH' environment
+ variable.
+
+'gawklibpath_append'
+ Add the argument to the end of the 'AWKLIBPATH' environment
+ variable.
+
+
+File: gawk.info, Node: Additional Configuration Options, Next: Configuration Philosophy, Prev: Shell Startup Files, Up: Unix Installation
-B.2.2 Additional Configuration Options
+B.2.3 Additional Configuration Options
--------------------------------------
There are several additional options you may use on the 'configure'
@@ -27675,6 +28808,11 @@ command line when compiling 'gawk' from scratch, including:
test suite to fail. This option may be removed at a later
date.
+'--disable-mpfr'
+ Skip checking for the MPFR and GMP libraries. This is useful
+ mainly for the developers, to make sure nothing breaks if MPFR
+ support is not available.
+
'--disable-nls'
Disable all message-translation facilities. This is usually not
desirable, but it may bring you some slight performance
@@ -27690,7 +28828,7 @@ supplied by 'configure'.

File: gawk.info, Node: Configuration Philosophy, Prev: Additional Configuration Options, Up: Unix Installation
-B.2.3 The Configuration Process
+B.2.4 The Configuration Process
-------------------------------
This minor node is of interest only if you know something about using
@@ -31529,7 +32667,7 @@ Index
* * (asterisk), * operator, as regexp operator: Regexp Operators.
(line 89)
* * (asterisk), * operator, null strings, matching: String Functions.
- (line 537)
+ (line 539)
* * (asterisk), ** operator: Arithmetic Ops. (line 81)
* * (asterisk), ** operator <1>: Precedence. (line 48)
* * (asterisk), **= operator: Assignment Ops. (line 129)
@@ -31554,7 +32692,7 @@ Index
* - (hyphen), filenames beginning with: Options. (line 60)
* - (hyphen), in bracket expressions: Bracket Expressions. (line 25)
* --assign option: Options. (line 32)
-* --bignum option: Options. (line 203)
+* --bignum option: Options. (line 217)
* --characters-as-bytes option: Options. (line 69)
* --copyright option: Options. (line 89)
* --debug option: Options. (line 108)
@@ -31562,35 +32700,38 @@ Index
(line 9)
* --disable-lint configuration option: Additional Configuration Options.
(line 15)
-* --disable-nls configuration option: Additional Configuration Options.
+* --disable-mpfr configuration option: Additional Configuration Options.
(line 32)
+* --disable-nls configuration option: Additional Configuration Options.
+ (line 37)
* --dump-variables option: Options. (line 94)
* --dump-variables option, using for library functions: Library Names.
(line 45)
-* --exec option: Options. (line 125)
+* --exec option: Options. (line 139)
* --field-separator option: Options. (line 21)
* --file option: Options. (line 25)
-* --gen-pot option: Options. (line 147)
+* --gen-pot option: Options. (line 161)
* --gen-pot option <1>: String Extraction. (line 6)
* --gen-pot option <2>: String Extraction. (line 6)
-* --help option: Options. (line 154)
-* --include option: Options. (line 159)
+* --help option: Options. (line 168)
+* --include option: Options. (line 173)
* --lint option: Command Line. (line 20)
-* --lint option <1>: Options. (line 184)
-* --lint-old option: Options. (line 294)
-* --load option: Options. (line 172)
-* --non-decimal-data option: Options. (line 209)
+* --lint option <1>: Options. (line 198)
+* --lint-old option: Options. (line 313)
+* --load option: Options. (line 186)
+* --no-optimize option: Options. (line 299)
+* --non-decimal-data option: Options. (line 223)
* --non-decimal-data option <1>: Nondecimal Data. (line 6)
* --non-decimal-data option, strtonum() function and: Nondecimal Data.
(line 35)
-* --optimize option: Options. (line 236)
-* --posix option: Options. (line 254)
-* --posix option, --traditional option and: Options. (line 272)
-* --pretty-print option: Options. (line 223)
-* --profile option: Options. (line 242)
+* --optimize option: Options. (line 248)
+* --posix option: Options. (line 271)
+* --posix option, --traditional option and: Options. (line 286)
+* --pretty-print option: Options. (line 237)
+* --profile option: Options. (line 259)
* --profile option <1>: Profiling. (line 12)
-* --re-interval option: Options. (line 278)
-* --sandbox option: Options. (line 285)
+* --re-interval option: Options. (line 292)
+* --sandbox option: Options. (line 304)
* --sandbox option, disabling system() function: I/O Functions.
(line 129)
* --sandbox option, input redirection with getline: Getline. (line 19)
@@ -31598,43 +32739,44 @@ Index
(line 6)
* --source option: Options. (line 117)
* --traditional option: Options. (line 82)
-* --traditional option, --posix option and: Options. (line 272)
-* --use-lc-numeric option: Options. (line 218)
-* --version option: Options. (line 299)
+* --traditional option, --posix option and: Options. (line 286)
+* --use-lc-numeric option: Options. (line 232)
+* --version option: Options. (line 318)
* --with-whiny-user-strftime configuration option: Additional Configuration Options.
- (line 37)
+ (line 42)
* -b option: Options. (line 69)
* -c option: Options. (line 82)
* -C option: Options. (line 89)
* -d option: Options. (line 94)
* -D option: Options. (line 108)
* -e option: Options. (line 117)
-* -E option: Options. (line 125)
-* -e option <1>: Options. (line 335)
+* -E option: Options. (line 139)
+* -e option <1>: Options. (line 354)
* -f option: Long. (line 12)
* -F option: Options. (line 21)
* -f option <1>: Options. (line 25)
-* -F option, -Ft sets FS to TAB: Options. (line 307)
+* -F option, -Ft sets FS to TAB: Options. (line 326)
* -F option, command-line: Command Line Field Separator.
(line 6)
-* -f option, multiple uses: Options. (line 312)
-* -g option: Options. (line 147)
-* -h option: Options. (line 154)
-* -i option: Options. (line 159)
-* -l option: Options. (line 172)
-* -l option <1>: Options. (line 184)
-* -L option: Options. (line 294)
-* -M option: Options. (line 203)
-* -n option: Options. (line 209)
-* -N option: Options. (line 218)
-* -o option: Options. (line 223)
-* -O option: Options. (line 236)
-* -p option: Options. (line 242)
-* -P option: Options. (line 254)
-* -r option: Options. (line 278)
-* -S option: Options. (line 285)
+* -f option, multiple uses: Options. (line 331)
+* -g option: Options. (line 161)
+* -h option: Options. (line 168)
+* -i option: Options. (line 173)
+* -l option: Options. (line 186)
+* -l option <1>: Options. (line 198)
+* -L option: Options. (line 313)
+* -M option: Options. (line 217)
+* -n option: Options. (line 223)
+* -N option: Options. (line 232)
+* -o option: Options. (line 237)
+* -O option: Options. (line 248)
+* -p option: Options. (line 259)
+* -P option: Options. (line 271)
+* -r option: Options. (line 292)
+* -s option: Options. (line 299)
+* -S option: Options. (line 304)
* -v option: Options. (line 32)
-* -V option: Options. (line 299)
+* -V option: Options. (line 318)
* -v option <1>: Assignment Options. (line 12)
* -W option: Options. (line 47)
* . (period), regexp operator: Regexp Operators. (line 44)
@@ -31707,16 +32849,16 @@ Index
(line 6)
* \ (backslash), in bracket expressions: Bracket Expressions. (line 25)
* \ (backslash), in escape sequences: Escape Sequences. (line 6)
-* \ (backslash), in escape sequences <1>: Escape Sequences. (line 100)
+* \ (backslash), in escape sequences <1>: Escape Sequences. (line 103)
* \ (backslash), in escape sequences, POSIX and: Escape Sequences.
- (line 105)
+ (line 108)
* \ (backslash), in regexp constants: Computed Regexps. (line 30)
* \ (backslash), in shell commands: Quoting. (line 48)
* \ (backslash), regexp operator: Regexp Operators. (line 18)
-* \ (backslash), \" escape sequence: Escape Sequences. (line 82)
+* \ (backslash), \" escape sequence: Escape Sequences. (line 85)
* \ (backslash), \' operator (gawk): GNU Regexp Operators.
(line 59)
-* \ (backslash), \/ escape sequence: Escape Sequences. (line 73)
+* \ (backslash), \/ escape sequence: Escape Sequences. (line 76)
* \ (backslash), \< operator (gawk): GNU Regexp Operators.
(line 33)
* \ (backslash), \> operator (gawk): GNU Regexp Operators.
@@ -31893,7 +33035,7 @@ Index
* arrays, unassigned elements: Reference to Elements.
(line 18)
* artificial intelligence, gawk and: Distribution contents.
- (line 52)
+ (line 58)
* ASCII: Ordinal Functions. (line 45)
* ASCII <1>: Glossary. (line 196)
* asort: String Functions. (line 42)
@@ -31921,7 +33063,7 @@ Index
* asterisk (*), * operator, as regexp operator: Regexp Operators.
(line 89)
* asterisk (*), * operator, null strings, matching: String Functions.
- (line 537)
+ (line 539)
* asterisk (*), ** operator: Arithmetic Ops. (line 81)
* asterisk (*), ** operator <1>: Precedence. (line 48)
* asterisk (*), **= operator: Assignment Ops. (line 129)
@@ -31933,7 +33075,7 @@ Index
* awf (amazingly workable formatter) program: Glossary. (line 24)
* awk debugging, enabling: Options. (line 108)
* awk language, POSIX version: Assignment Ops. (line 138)
-* awk profiling, enabling: Options. (line 242)
+* awk profiling, enabling: Options. (line 259)
* awk programs: Getting Started. (line 12)
* awk programs <1>: Executable Scripts. (line 6)
* awk programs <2>: Two Rules. (line 6)
@@ -31947,8 +33089,8 @@ Index
* awk programs, lengthy: Long. (line 6)
* awk programs, lengthy, assertions: Assert Function. (line 6)
* awk programs, location of: Options. (line 25)
-* awk programs, location of <1>: Options. (line 125)
-* awk programs, location of <2>: Options. (line 159)
+* awk programs, location of <1>: Options. (line 139)
+* awk programs, location of <2>: Options. (line 173)
* awk programs, one-line examples: Very Simple. (line 46)
* awk programs, profiling: Profiling. (line 6)
* awk programs, running: Running gawk. (line 6)
@@ -32004,16 +33146,16 @@ Index
(line 6)
* backslash (\), in bracket expressions: Bracket Expressions. (line 25)
* backslash (\), in escape sequences: Escape Sequences. (line 6)
-* backslash (\), in escape sequences <1>: Escape Sequences. (line 100)
+* backslash (\), in escape sequences <1>: Escape Sequences. (line 103)
* backslash (\), in escape sequences, POSIX and: Escape Sequences.
- (line 105)
+ (line 108)
* backslash (\), in regexp constants: Computed Regexps. (line 30)
* backslash (\), in shell commands: Quoting. (line 48)
* backslash (\), regexp operator: Regexp Operators. (line 18)
-* backslash (\), \" escape sequence: Escape Sequences. (line 82)
+* backslash (\), \" escape sequence: Escape Sequences. (line 85)
* backslash (\), \' operator (gawk): GNU Regexp Operators.
(line 59)
-* backslash (\), \/ escape sequence: Escape Sequences. (line 73)
+* backslash (\), \/ escape sequence: Escape Sequences. (line 76)
* backslash (\), \< operator (gawk): GNU Regexp Operators.
(line 33)
* backslash (\), \> operator (gawk): GNU Regexp Operators.
@@ -32083,7 +33225,7 @@ Index
* BINMODE variable: User-modified. (line 15)
* BINMODE variable <1>: PC Using. (line 16)
* bit-manipulation functions: Bitwise Functions. (line 6)
-* bits2str() user-defined function: Bitwise Functions. (line 72)
+* bits2str() user-defined function: Bitwise Functions. (line 69)
* bitwise AND: Bitwise Functions. (line 40)
* bitwise complement: Bitwise Functions. (line 44)
* bitwise OR: Bitwise Functions. (line 50)
@@ -32132,7 +33274,7 @@ Index
* Brennan, Michael <5>: Other Versions. (line 6)
* Brennan, Michael <6>: Other Versions. (line 48)
* Brian Kernighan's awk: When. (line 21)
-* Brian Kernighan's awk <1>: Escape Sequences. (line 109)
+* Brian Kernighan's awk <1>: Escape Sequences. (line 112)
* Brian Kernighan's awk <2>: GNU Regexp Operators.
(line 85)
* Brian Kernighan's awk <3>: Regexp Field Splitting.
@@ -32144,7 +33286,7 @@ Index
* Brian Kernighan's awk <8>: Continue Statement. (line 44)
* Brian Kernighan's awk <9>: Nextfile Statement. (line 47)
* Brian Kernighan's awk <10>: Delete. (line 51)
-* Brian Kernighan's awk <11>: String Functions. (line 493)
+* Brian Kernighan's awk <11>: String Functions. (line 495)
* Brian Kernighan's awk <12>: Gory Details. (line 19)
* Brian Kernighan's awk <13>: I/O Functions. (line 43)
* Brian Kernighan's awk, extensions: BTL. (line 6)
@@ -32184,14 +33326,14 @@ Index
* caret (^), ^= operator: Assignment Ops. (line 129)
* caret (^), ^= operator <1>: Precedence. (line 94)
* 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, and regexps: User-modified. (line 79)
+* case sensitivity, and string comparisons: User-modified. (line 79)
* case sensitivity, array indices and: Array Intro. (line 100)
-* case sensitivity, converting case: String Functions. (line 523)
+* case sensitivity, converting case: String Functions. (line 525)
* case sensitivity, example programs: Library Functions. (line 53)
* case sensitivity, gawk: Case-sensitivity. (line 26)
* case sensitivity, regexps and: Case-sensitivity. (line 6)
-* CGI, awk scripts for: Options. (line 125)
+* CGI, awk scripts for: Options. (line 139)
* character classes, See bracket expressions: Regexp Operators.
(line 56)
* character lists in regular expression: Bracket Expressions. (line 6)
@@ -32207,6 +33349,7 @@ Index
* Chassell, Robert J.: Acknowledgments. (line 33)
* chdir() extension function: Extension Sample File Functions.
(line 12)
+* checking for MPFR: Checking for MPFR. (line 6)
* chem utility: Glossary. (line 206)
* chr() extension function: Extension Sample Ord.
(line 15)
@@ -32236,6 +33379,7 @@ Index
* columns, cutting: Cut Program. (line 6)
* comma (,), in range patterns: Ranges. (line 6)
* command completion, in debugger: Readline Support. (line 6)
+* command line arguments, PROCINFO["argv": Auto-set. (line 154)
* command line, arguments: Other Arguments. (line 6)
* command line, arguments <1>: Auto-set. (line 15)
* command line, arguments <2>: ARGC and ARGV. (line 6)
@@ -32299,10 +33443,12 @@ Index
(line 9)
* configuration option, --disable-lint: Additional Configuration Options.
(line 15)
-* configuration option, --disable-nls: Additional Configuration Options.
+* configuration option, --disable-mpfr: Additional Configuration Options.
(line 32)
-* configuration option, --with-whiny-user-strftime: Additional Configuration Options.
+* configuration option, --disable-nls: Additional Configuration Options.
(line 37)
+* configuration option, --with-whiny-user-strftime: Additional Configuration Options.
+ (line 42)
* configuration options, gawk: Additional Configuration Options.
(line 6)
* constant regexps: Regexp Usage. (line 57)
@@ -32315,16 +33461,16 @@ Index
* control statements: Statements. (line 6)
* controlling array scanning order: Controlling Scanning.
(line 14)
-* convert string to lower case: String Functions. (line 524)
-* convert string to number: String Functions. (line 391)
-* convert string to upper case: String Functions. (line 530)
+* convert string to lower case: String Functions. (line 526)
+* convert string to number: String Functions. (line 393)
+* convert string to upper case: String Functions. (line 532)
* converting integer array subscripts: Numeric Array Subscripts.
(line 31)
-* converting, dates to timestamps: Time Functions. (line 76)
+* converting, dates to timestamps: Time Functions. (line 78)
* converting, numbers to strings: Strings And Numbers. (line 6)
-* converting, numbers to strings <1>: Bitwise Functions. (line 111)
+* converting, numbers to strings <1>: Bitwise Functions. (line 108)
* converting, strings to numbers: Strings And Numbers. (line 6)
-* converting, strings to numbers <1>: Bitwise Functions. (line 111)
+* converting, strings to numbers <1>: Bitwise Functions. (line 108)
* CONVFMT variable: Strings And Numbers. (line 29)
* CONVFMT variable <1>: User-modified. (line 30)
* CONVFMT variable, and array subscripts: Numeric Array Subscripts.
@@ -32339,11 +33485,11 @@ Index
* cosine: Numeric Functions. (line 16)
* counting: Wc Program. (line 6)
* csh utility: Statements/Lines. (line 43)
-* csh utility, POSIXLY_CORRECT environment variable: Options. (line 353)
+* csh utility, POSIXLY_CORRECT environment variable: Options. (line 372)
* csh utility, |& operator, comparison with: Two-way I/O. (line 27)
* ctime() user-defined function: Function Example. (line 74)
* currency symbols, localization: Explaining gettext. (line 104)
-* current system time: Time Functions. (line 66)
+* current system time: Time Functions. (line 68)
* custom.h file: Configuration Philosophy.
(line 30)
* customized input parser: Input Parsers. (line 6)
@@ -32369,12 +33515,12 @@ Index
* dark corner, CONVFMT variable: Strings And Numbers. (line 39)
* dark corner, escape sequences: Other Arguments. (line 38)
* dark corner, escape sequences, for metacharacters: Escape Sequences.
- (line 141)
+ (line 144)
* dark corner, exit statement: Exit Statement. (line 30)
* dark corner, field separators: Full Line Fields. (line 22)
* dark corner, FILENAME variable: Getline Notes. (line 19)
-* dark corner, FILENAME variable <1>: Auto-set. (line 89)
-* dark corner, FNR/NR variables: Auto-set. (line 326)
+* dark corner, FILENAME variable <1>: Auto-set. (line 108)
+* dark corner, FNR/NR variables: Auto-set. (line 377)
* dark corner, format-control characters: Control Letters. (line 18)
* dark corner, format-control characters <1>: Control Letters.
(line 93)
@@ -32390,13 +33536,13 @@ Index
* dark corner, OFMT variable: OFMT. (line 27)
* dark corner, regexp as second argument to index(): String Functions.
(line 164)
-* dark corner, regexp constants: Using Constant Regexps.
+* dark corner, regexp constants: Standard Regexp Constants.
(line 6)
* dark corner, regexp constants, /= operator and: Assignment Ops.
(line 149)
-* dark corner, regexp constants, as arguments to user-defined functions: Using Constant Regexps.
+* dark corner, regexp constants, as arguments to user-defined functions: Standard Regexp Constants.
(line 43)
-* dark corner, split() function: String Functions. (line 361)
+* dark corner, split() function: String Functions. (line 363)
* dark corner, strings, storing: gawk split records. (line 82)
* dark corner, value of ARGV[0]: Auto-set. (line 39)
* dark corner, ^, in FS: Regexp Field Splitting.
@@ -32406,8 +33552,8 @@ Index
* database, group, reading: Group Functions. (line 6)
* database, users, reading: Passwd Functions. (line 6)
* date utility, GNU: Time Functions. (line 17)
-* date utility, POSIX: Time Functions. (line 253)
-* dates, converting to timestamps: Time Functions. (line 76)
+* date utility, POSIX: Time Functions. (line 255)
+* dates, converting to timestamps: Time Functions. (line 78)
* dates, information related to, localization: Explaining gettext.
(line 112)
* Davies, Stephen: Acknowledgments. (line 60)
@@ -32528,7 +33674,7 @@ Index
* debugger, read commands from a file: Debugger Info. (line 97)
* debugging awk programs: Debugger. (line 6)
* debugging gawk, bug reports: Bugs. (line 9)
-* decimal point character, locale specific: Options. (line 269)
+* decimal point character, locale specific: Options. (line 283)
* decrement operators: Increment Ops. (line 35)
* default keyword: Switch Statement. (line 6)
* Deifik, Scott: Acknowledgments. (line 60)
@@ -32569,17 +33715,17 @@ Index
(line 132)
* differences in awk and gawk, command-line directories: Command-line directories.
(line 6)
-* differences in awk and gawk, ERRNO variable: Auto-set. (line 73)
+* differences in awk and gawk, ERRNO variable: Auto-set. (line 87)
* differences in awk and gawk, error messages: Special FD. (line 19)
* differences in awk and gawk, FIELDWIDTHS variable: User-modified.
(line 37)
-* differences in awk and gawk, FPAT variable: User-modified. (line 43)
-* differences in awk and gawk, FUNCTAB variable: Auto-set. (line 115)
+* differences in awk and gawk, FPAT variable: User-modified. (line 46)
+* differences in awk and gawk, FUNCTAB variable: Auto-set. (line 134)
* differences in awk and gawk, function arguments (gawk): Calling Built-in.
(line 16)
* differences in awk and gawk, getline command: Getline. (line 19)
* differences in awk and gawk, IGNORECASE variable: User-modified.
- (line 76)
+ (line 79)
* differences in awk and gawk, implementation limitations: Getline Notes.
(line 14)
* differences in awk and gawk, implementation limitations <1>: Redirection.
@@ -32592,32 +33738,34 @@ Index
(line 96)
* differences in awk and gawk, line continuations: Conditional Exp.
(line 34)
-* differences in awk and gawk, LINT variable: User-modified. (line 87)
+* differences in awk and gawk, LINT variable: User-modified. (line 90)
* differences in awk and gawk, match() function: String Functions.
(line 262)
* differences in awk and gawk, print/printf statements: Format Modifiers.
(line 13)
-* differences in awk and gawk, PROCINFO array: Auto-set. (line 129)
+* differences in awk and gawk, PROCINFO array: Auto-set. (line 148)
* differences in awk and gawk, read timeouts: Read Timeout. (line 6)
* differences in awk and gawk, record separators: awk split records.
(line 124)
-* differences in awk and gawk, regexp constants: Using Constant Regexps.
+* differences in awk and gawk, regexp constants: Standard Regexp Constants.
(line 43)
* differences in awk and gawk, regular expressions: Case-sensitivity.
(line 26)
+* differences in awk and gawk, retrying input: Retrying Input.
+ (line 6)
* differences in awk and gawk, RS/RT variables: gawk split records.
(line 58)
-* differences in awk and gawk, RT variable: Auto-set. (line 264)
+* differences in awk and gawk, RT variable: Auto-set. (line 315)
* differences in awk and gawk, single-character fields: Single Character Fields.
(line 6)
* differences in awk and gawk, split() function: String Functions.
- (line 348)
+ (line 350)
* differences in awk and gawk, strings: Scalar Constants. (line 20)
* differences in awk and gawk, strings, storing: gawk split records.
(line 76)
-* differences in awk and gawk, SYMTAB variable: Auto-set. (line 268)
+* differences in awk and gawk, SYMTAB variable: Auto-set. (line 319)
* differences in awk and gawk, TEXTDOMAIN variable: User-modified.
- (line 152)
+ (line 155)
* differences in awk and gawk, trunc-mod operation: Arithmetic Ops.
(line 66)
* directories, command-line: Command-line directories.
@@ -32651,12 +33799,12 @@ Index
* dump debugger command: Miscellaneous Debugger Commands.
(line 9)
* dupword.awk program: Dupword Program. (line 31)
-* dynamic profiling: Profiling. (line 178)
+* dynamic profiling: Profiling. (line 177)
* 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 134)
-* effective user ID of gawk user: Auto-set. (line 138)
+* effective group ID of gawk user: Auto-set. (line 172)
+* effective user ID of gawk user: Auto-set. (line 180)
* egrep utility: Bracket Expressions. (line 34)
* egrep utility <1>: Egrep Program. (line 6)
* egrep.awk program: Egrep Program. (line 53)
@@ -32711,14 +33859,14 @@ Index
(line 11)
* equals sign (=), == operator <1>: Precedence. (line 64)
* EREs (Extended Regular Expressions): Bracket Expressions. (line 34)
-* ERRNO variable: Auto-set. (line 73)
+* ERRNO variable: Auto-set. (line 87)
* ERRNO variable <1>: TCP/IP Networking. (line 54)
* ERRNO variable, with BEGINFILE pattern: BEGINFILE/ENDFILE. (line 26)
* ERRNO variable, with close() function: Close Files And Pipes.
(line 140)
* ERRNO variable, with getline command: Getline. (line 19)
* error handling: Special FD. (line 19)
-* error handling, ERRNO variable and: Auto-set. (line 73)
+* error handling, ERRNO variable and: Auto-set. (line 87)
* error output: Special FD. (line 6)
* escape processing, gsub()/gensub()/sub() functions: Gory Details.
(line 6)
@@ -32759,7 +33907,7 @@ Index
(line 102)
* exp: Numeric Functions. (line 19)
* expand utility: Very Simple. (line 73)
-* Expat XML parser library: gawkextlib. (line 35)
+* Expat XML parser library: gawkextlib. (line 37)
* exponent: Numeric Functions. (line 19)
* expressions: Expressions. (line 6)
* expressions, as patterns: Expression Patterns. (line 6)
@@ -32778,7 +33926,7 @@ Index
(line 6)
* extension API version: Extension Versioning.
(line 6)
-* extension API, version number: Auto-set. (line 223)
+* extension API, version number: Auto-set. (line 266)
* extension example: Extension Example. (line 6)
* extension registration: Registration Functions.
(line 6)
@@ -32829,12 +33977,11 @@ Index
(line 6)
* field separator, POSIX and: Full Line Fields. (line 16)
* field separators: Field Separators. (line 15)
-* field separators <1>: User-modified. (line 50)
-* field separators <2>: User-modified. (line 113)
+* field separators <1>: User-modified. (line 53)
+* field separators <2>: User-modified. (line 116)
* field separators, choice of: Field Separators. (line 50)
* field separators, FIELDWIDTHS variable and: User-modified. (line 37)
-* field separators, FPAT variable and: User-modified. (line 43)
-* field separators, POSIX and: Fields. (line 6)
+* field separators, FPAT variable and: User-modified. (line 46)
* field separators, regular expressions as: Field Separators. (line 50)
* field separators, regular expressions as <1>: Regexp Field Splitting.
(line 6)
@@ -32854,7 +34001,7 @@ Index
* fields, separating <1>: Field Separators. (line 15)
* fields, single-character: Single Character Fields.
(line 6)
-* FIELDWIDTHS variable: Constant Size. (line 22)
+* FIELDWIDTHS variable: Fixed width data. (line 17)
* FIELDWIDTHS variable <1>: User-modified. (line 37)
* file descriptors: Special FD. (line 6)
* file inclusion, @include directive: Include Files. (line 8)
@@ -32862,7 +34009,7 @@ Index
* file names, in compatibility mode: Special Caveats. (line 9)
* file names, standard streams in gawk: Special FD. (line 48)
* FILENAME variable: Reading Files. (line 6)
-* FILENAME variable <1>: Auto-set. (line 89)
+* FILENAME variable <1>: Auto-set. (line 108)
* FILENAME variable, getline, setting with: Getline Notes. (line 19)
* filenames, assignments as: Ignoring Assigns. (line 6)
* files, .gmo: Explaining gettext. (line 42)
@@ -32906,7 +34053,7 @@ Index
* files, portable object template: Explaining gettext. (line 31)
* files, portable object, converting to message object files: I18N Example.
(line 66)
-* files, portable object, generating: Options. (line 147)
+* files, portable object, generating: Options. (line 161)
* files, processing, ARGIND variable and: Auto-set. (line 50)
* files, reading: Rewind Function. (line 6)
* files, reading, multiline records: Multiple Line. (line 6)
@@ -32930,8 +34077,8 @@ Index
* fnmatch() extension function: Extension Sample Fnmatch.
(line 12)
* FNR variable: Records. (line 6)
-* FNR variable <1>: Auto-set. (line 99)
-* FNR variable, changing: Auto-set. (line 326)
+* FNR variable <1>: Auto-set. (line 118)
+* FNR variable, changing: Auto-set. (line 377)
* for statement: For Statement. (line 6)
* for statement, looping over arrays: Scanning an Array. (line 20)
* fork() extension function: Extension Sample Fork.
@@ -32941,11 +34088,11 @@ Index
(line 57)
* format specifiers, printf statement: Control Letters. (line 6)
* format specifiers, strftime() function (gawk): Time Functions.
- (line 89)
-* format time string: Time Functions. (line 48)
+ (line 91)
+* format time string: Time Functions. (line 50)
* formats, numeric output: OFMT. (line 6)
* formatting output: Printf. (line 6)
-* formatting strings: String Functions. (line 384)
+* formatting strings: String Functions. (line 386)
* forward slash (/) to enclose regular expressions: Regexp. (line 10)
* forward slash (/), / operator: Precedence. (line 54)
* forward slash (/), /= operator: Assignment Ops. (line 129)
@@ -32955,7 +34102,7 @@ Index
* forward slash (/), patterns and: Expression Patterns. (line 24)
* FPAT variable: Splitting By Content.
(line 25)
-* FPAT variable <1>: User-modified. (line 43)
+* FPAT variable <1>: User-modified. (line 46)
* frame debugger command: Execution Stack. (line 27)
* Free Documentation License (FDL): GNU Free Documentation License.
(line 8)
@@ -32965,11 +34112,11 @@ Index
* Free Software Foundation (FSF) <3>: Glossary. (line 405)
* FreeBSD: Glossary. (line 748)
* FS variable: Field Separators. (line 15)
-* FS variable <1>: User-modified. (line 50)
+* FS variable <1>: User-modified. (line 53)
* FS variable, --field-separator option and: Options. (line 21)
* FS variable, as null string: Single Character Fields.
(line 20)
-* FS variable, as TAB character: Options. (line 266)
+* FS variable, as TAB character: Options. (line 280)
* FS variable, changing value of: Field Separators. (line 34)
* FS variable, running awk programs and: Cut Program. (line 63)
* FS variable, setting from command line: Command Line Field Separator.
@@ -32983,7 +34130,7 @@ Index
* FSF (Free Software Foundation) <3>: Glossary. (line 405)
* fts() extension function: Extension Sample File Functions.
(line 60)
-* FUNCTAB array: Auto-set. (line 115)
+* FUNCTAB array: Auto-set. (line 134)
* function calls: Function Calls. (line 6)
* function calls, indirect: Indirect Calls. (line 6)
* function calls, indirect, @-notation for: Indirect Calls. (line 47)
@@ -33034,8 +34181,8 @@ Index
* G., Daniel Richard: Acknowledgments. (line 60)
* G., Daniel Richard <1>: Maintainers. (line 14)
* Garfinkle, Scott: Contributors. (line 35)
-* gawk program, dynamic profiling: Profiling. (line 178)
-* gawk version: Auto-set. (line 198)
+* gawk program, dynamic profiling: Profiling. (line 177)
+* gawk version: Auto-set. (line 241)
* gawk, ARGIND variable in: Other Arguments. (line 15)
* gawk, awk and: Preface. (line 21)
* gawk, awk and <1>: This Manual. (line 14)
@@ -33056,26 +34203,26 @@ Index
* gawk, ERRNO variable in <1>: Close Files And Pipes.
(line 140)
* gawk, ERRNO variable in <2>: BEGINFILE/ENDFILE. (line 26)
-* gawk, ERRNO variable in <3>: Auto-set. (line 73)
+* gawk, ERRNO variable in <3>: Auto-set. (line 87)
* gawk, ERRNO variable in <4>: TCP/IP Networking. (line 54)
-* gawk, escape sequences: Escape Sequences. (line 118)
-* gawk, extensions, disabling: Options. (line 254)
+* gawk, escape sequences: Escape Sequences. (line 121)
+* gawk, extensions, disabling: Options. (line 271)
* gawk, features, adding: Adding Code. (line 6)
* gawk, features, advanced: Advanced Features. (line 6)
-* gawk, field separators and: User-modified. (line 71)
-* gawk, FIELDWIDTHS variable in: Constant Size. (line 22)
+* gawk, field separators and: User-modified. (line 74)
+* gawk, FIELDWIDTHS variable in: Fixed width data. (line 17)
* gawk, FIELDWIDTHS variable in <1>: User-modified. (line 37)
* gawk, file names in: Special Files. (line 6)
* gawk, format-control characters: Control Letters. (line 18)
* gawk, format-control characters <1>: Control Letters. (line 93)
* gawk, FPAT variable in: Splitting By Content.
(line 25)
-* gawk, FPAT variable in <1>: User-modified. (line 43)
-* gawk, FUNCTAB array in: Auto-set. (line 115)
+* gawk, FPAT variable in <1>: User-modified. (line 46)
+* gawk, FUNCTAB array in: Auto-set. (line 134)
* gawk, function arguments and: Calling Built-in. (line 16)
* gawk, hexadecimal numbers and: Nondecimal-numbers. (line 41)
* gawk, IGNORECASE variable in: Case-sensitivity. (line 26)
-* gawk, IGNORECASE variable in <1>: User-modified. (line 76)
+* gawk, IGNORECASE variable in <1>: User-modified. (line 79)
* gawk, IGNORECASE variable in <2>: Array Intro. (line 100)
* gawk, IGNORECASE variable in <3>: String Functions. (line 58)
* gawk, IGNORECASE variable in <4>: Array Sorting Functions.
@@ -33093,16 +34240,16 @@ Index
(line 6)
* gawk, interval expressions and: Regexp Operators. (line 139)
* gawk, line continuation in: Conditional Exp. (line 34)
-* gawk, LINT variable in: User-modified. (line 87)
+* gawk, LINT variable in: User-modified. (line 90)
* gawk, list of contributors to: Contributors. (line 6)
* gawk, MS-Windows version of: PC Using. (line 9)
* gawk, newlines in: Statements/Lines. (line 12)
* gawk, octal numbers and: Nondecimal-numbers. (line 41)
* gawk, predefined variables and: Built-in Variables. (line 14)
-* gawk, PROCINFO array in: Auto-set. (line 129)
-* gawk, PROCINFO array in <1>: Time Functions. (line 47)
-* gawk, PROCINFO array in <2>: Two-way I/O. (line 108)
-* gawk, regexp constants and: Using Constant Regexps.
+* gawk, PROCINFO array in: Auto-set. (line 148)
+* gawk, PROCINFO array in <1>: Time Functions. (line 49)
+* gawk, PROCINFO array in <2>: Two-way I/O. (line 114)
+* gawk, regexp constants and: Standard Regexp Constants.
(line 28)
* gawk, regular expressions, case sensitivity: Case-sensitivity.
(line 26)
@@ -33111,25 +34258,32 @@ Index
* gawk, regular expressions, precedence: Regexp Operators. (line 161)
* gawk, RT variable in: awk split records. (line 124)
* gawk, RT variable in <1>: Multiple Line. (line 130)
-* gawk, RT variable in <2>: Auto-set. (line 264)
+* gawk, RT variable in <2>: Auto-set. (line 315)
* gawk, See Also awk: Preface. (line 34)
* gawk, source code, obtaining: Getting. (line 6)
-* gawk, splitting fields and: Constant Size. (line 86)
+* gawk, splitting fields and: Testing field creation.
+ (line 6)
* gawk, string-translation functions: I18N Functions. (line 6)
-* gawk, SYMTAB array in: Auto-set. (line 268)
-* gawk, TEXTDOMAIN variable in: User-modified. (line 152)
+* gawk, SYMTAB array in: Auto-set. (line 319)
+* gawk, TEXTDOMAIN variable in: User-modified. (line 155)
* gawk, timestamps: Time Functions. (line 6)
* gawk, uses for: Preface. (line 34)
-* gawk, versions of, information about, printing: Options. (line 299)
+* gawk, versions of, information about, printing: Options. (line 318)
* gawk, VMS version of: VMS Installation. (line 6)
* gawk, word-boundary operator: GNU Regexp Operators.
(line 66)
* gawkextlib: gawkextlib. (line 6)
* gawkextlib project: gawkextlib. (line 6)
+* gawklibpath_append shell function: Shell Startup Files. (line 29)
+* gawklibpath_default shell function: Shell Startup Files. (line 22)
+* gawklibpath_prepend shell function: Shell Startup Files. (line 25)
+* gawkpath_append shell function: Shell Startup Files. (line 19)
+* gawkpath_default shell function: Shell Startup Files. (line 12)
+* gawkpath_prepend shell function: Shell Startup Files. (line 15)
* General Public License (GPL): Glossary. (line 396)
* General Public License, See GPL: Manual History. (line 11)
* generate time values: Time Functions. (line 25)
-* gensub: Using Constant Regexps.
+* gensub: Standard Regexp Constants.
(line 43)
* gensub <1>: String Functions. (line 89)
* gensub() function (gawk), escape processing: Gory Details. (line 6)
@@ -33179,7 +34333,7 @@ Index
* gettext() function (C library): Explaining gettext. (line 63)
* gettimeofday() extension function: Extension Sample Time.
(line 12)
-* git utility: gawkextlib. (line 29)
+* git utility: gawkextlib. (line 31)
* git utility <1>: Other Versions. (line 29)
* git utility <2>: Accessing The Source.
(line 10)
@@ -33193,7 +34347,7 @@ Index
* GNU Lesser General Public License: Glossary. (line 491)
* GNU long options: Command Line. (line 13)
* GNU long options <1>: Options. (line 6)
-* GNU long options, printing list of: Options. (line 154)
+* GNU long options, printing list of: Options. (line 168)
* GNU Project: Manual History. (line 11)
* GNU Project <1>: Glossary. (line 405)
* GNU/Linux: Manual History. (line 28)
@@ -33207,12 +34361,12 @@ Index
* Grigera, Juan: Contributors. (line 58)
* group database, reading: Group Functions. (line 6)
* group file: Group Functions. (line 6)
-* group ID of gawk user: Auto-set. (line 147)
+* group ID of gawk user: Auto-set. (line 190)
* groups, information about: Group Functions. (line 6)
-* gsub: Using Constant Regexps.
+* gsub: Standard Regexp Constants.
(line 43)
* gsub <1>: String Functions. (line 139)
-* gsub() function, arguments of: String Functions. (line 463)
+* gsub() function, arguments of: String Functions. (line 465)
* gsub() function, escape processing: Gory Details. (line 6)
* h debugger command (alias for help): Miscellaneous Debugger Commands.
(line 69)
@@ -33225,11 +34379,11 @@ Index
* help debugger command: Miscellaneous Debugger Commands.
(line 69)
* hexadecimal numbers: Nondecimal-numbers. (line 6)
-* hexadecimal values, enabling interpretation of: Options. (line 209)
+* hexadecimal values, enabling interpretation of: Options. (line 223)
* history expansion, in debugger: Readline Support. (line 6)
* histsort.awk program: History Sorting. (line 25)
* Hughes, Phil: Acknowledgments. (line 43)
-* HUP signal, for dynamic profiling: Profiling. (line 210)
+* HUP signal, for dynamic profiling: Profiling. (line 209)
* hyphen (-), - operator: Precedence. (line 51)
* hyphen (-), - operator <1>: Precedence. (line 57)
* hyphen (-), -- operator: Increment Ops. (line 48)
@@ -33247,7 +34401,7 @@ Index
* igawk.sh program: Igawk Program. (line 124)
* ignore breakpoint: Breakpoint Control. (line 87)
* ignore debugger command: Breakpoint Control. (line 87)
-* IGNORECASE variable: User-modified. (line 76)
+* IGNORECASE variable: User-modified. (line 79)
* IGNORECASE variable, and array indices: Array Intro. (line 100)
* IGNORECASE variable, and array sorting functions: Array Sorting Functions.
(line 83)
@@ -33311,7 +34465,9 @@ Index
* installing gawk: Installation. (line 6)
* instruction tracing, in debugger: Debugger Info. (line 90)
* int: Numeric Functions. (line 24)
-* INT signal (MS-Windows): Profiling. (line 213)
+* INT signal (MS-Windows): Profiling. (line 212)
+* intdiv: Numeric Functions. (line 29)
+* intdiv <1>: Numeric Functions. (line 29)
* integer array indices: Numeric Array Subscripts.
(line 31)
* integers, arbitrary precision: Arbitrary Precision Integers.
@@ -33320,7 +34476,7 @@ Index
* interacting with other programs: I/O Functions. (line 107)
* internationalization: I18N Functions. (line 6)
* internationalization <1>: I18N and L10N. (line 6)
-* internationalization, localization: User-modified. (line 152)
+* internationalization, localization: User-modified. (line 155)
* internationalization, localization <1>: Internationalization.
(line 13)
* internationalization, localization, character classes: Bracket Expressions.
@@ -33367,7 +34523,7 @@ Index
* Kernighan, Brian <8>: Other Versions. (line 13)
* Kernighan, Brian <9>: Basic Data Typing. (line 54)
* Kernighan, Brian <10>: Glossary. (line 206)
-* kill command, dynamic profiling: Profiling. (line 187)
+* kill command, dynamic profiling: Profiling. (line 186)
* Knights, jedi: Undocumented. (line 6)
* Kwok, Conrad: Contributors. (line 35)
* l debugger command (alias for list): Miscellaneous Debugger Commands.
@@ -33433,17 +34589,17 @@ Index
* lines, duplicate, removing: History Sorting. (line 6)
* lines, matching ranges of: Ranges. (line 6)
* lines, skipping between markers: Ranges. (line 43)
-* lint checking: User-modified. (line 87)
+* lint checking: User-modified. (line 90)
* lint checking, array elements: Delete. (line 34)
* lint checking, array subscripts: Uninitialized Subscripts.
(line 43)
* lint checking, empty programs: Command Line. (line 16)
-* lint checking, issuing warnings: Options. (line 184)
+* lint checking, issuing warnings: Options. (line 198)
* lint checking, POSIXLY_CORRECT environment variable: Options.
- (line 338)
+ (line 357)
* lint checking, undefined functions: Pass By Value/Reference.
(line 85)
-* LINT variable: User-modified. (line 87)
+* LINT variable: User-modified. (line 90)
* Linux: Manual History. (line 28)
* Linux <1>: I18N Example. (line 57)
* Linux <2>: Glossary. (line 748)
@@ -33453,17 +34609,17 @@ Index
* list function definitions, in debugger: Debugger Info. (line 30)
* loading extensions, @load directive: Loading Shared Libraries.
(line 8)
-* loading, extensions: Options. (line 172)
+* loading, extensions: Options. (line 186)
* local variables, in a function: Variable Scope. (line 6)
* locale categories: Explaining gettext. (line 81)
-* locale decimal point character: Options. (line 269)
+* locale decimal point character: Options. (line 283)
* locale, definition of: Locales. (line 6)
* localization: I18N and L10N. (line 6)
* localization, See internationalization, localization: I18N and L10N.
(line 6)
-* log: Numeric Functions. (line 29)
+* log: Numeric Functions. (line 47)
* log files, timestamps in: Time Functions. (line 6)
-* logarithm: Numeric Functions. (line 29)
+* logarithm: Numeric Functions. (line 47)
* logical false/true: Truth Values. (line 6)
* logical operators, See Boolean expressions: Boolean Ops. (line 6)
* login information: Passwd Functions. (line 16)
@@ -33499,13 +34655,13 @@ Index
* matching, expressions, See comparison expressions: Typing and Comparison.
(line 9)
* matching, leftmost longest: Multiple Line. (line 26)
-* matching, null strings: String Functions. (line 537)
-* mawk utility: Escape Sequences. (line 118)
+* matching, null strings: String Functions. (line 539)
+* mawk utility: Escape Sequences. (line 121)
* mawk utility <1>: Getline/Pipe. (line 62)
* mawk utility <2>: Concatenation. (line 36)
* mawk utility <3>: Nextfile Statement. (line 47)
* mawk utility <4>: Other Versions. (line 48)
-* maximum precision supported by MPFR library: Auto-set. (line 212)
+* maximum precision supported by MPFR library: Auto-set. (line 255)
* McIlroy, Doug: Glossary. (line 257)
* McPhee, Patrick: Contributors. (line 101)
* message object files: Explaining gettext. (line 42)
@@ -33517,12 +34673,13 @@ Index
(line 48)
* messages from extensions: Printing Messages. (line 6)
* metacharacters in regular expressions: Regexp Operators. (line 6)
-* metacharacters, escape sequences for: Escape Sequences. (line 137)
-* minimum precision required by MPFR library: Auto-set. (line 215)
+* metacharacters, escape sequences for: Escape Sequences. (line 140)
+* minimum precision required by MPFR library: Auto-set. (line 258)
* mktime: Time Functions. (line 25)
* modifiers, in format specifiers: Format Modifiers. (line 6)
* monetary information, localization: Explaining gettext. (line 104)
* Moore, Duncan: Getline Notes. (line 40)
+* MPFR, checking availability of: Checking for MPFR. (line 6)
* msgfmt utility: I18N Example. (line 66)
* multiple precision: Arbitrary Precision Arithmetic.
(line 6)
@@ -33538,10 +34695,8 @@ Index
* networks, programming: TCP/IP Networking. (line 6)
* networks, support for: Special Network. (line 6)
* newlines: Statements/Lines. (line 6)
-* newlines <1>: Options. (line 260)
+* newlines <1>: Options. (line 277)
* newlines <2>: Boolean Ops. (line 69)
-* newlines, as field separators: Default Field Splitting.
- (line 6)
* newlines, as record separators: awk split records. (line 12)
* newlines, in dynamic regexps: Computed Regexps. (line 60)
* newlines, in regexp constants: Computed Regexps. (line 70)
@@ -33568,7 +34723,7 @@ Index
* nexti debugger command: Debugger Execution Control.
(line 49)
* NF variable: Fields. (line 33)
-* NF variable <1>: Auto-set. (line 104)
+* NF variable <1>: Auto-set. (line 123)
* NF variable, decrementing: Changing Fields. (line 107)
* ni debugger command (alias for nexti): Debugger Execution Control.
(line 49)
@@ -33577,8 +34732,8 @@ Index
(line 23)
* not Boolean-logic operator: Boolean Ops. (line 6)
* NR variable: Records. (line 6)
-* NR variable <1>: Auto-set. (line 124)
-* NR variable, changing: Auto-set. (line 326)
+* NR variable <1>: Auto-set. (line 143)
+* NR variable, changing: Auto-set. (line 377)
* null strings: awk split records. (line 114)
* null strings <1>: Regexp Field Splitting.
(line 43)
@@ -33590,8 +34745,8 @@ Index
(line 43)
* null strings, converting numbers to strings: Strings And Numbers.
(line 21)
-* null strings, matching: String Functions. (line 537)
-* number as string of bits: Bitwise Functions. (line 111)
+* null strings, matching: String Functions. (line 539)
+* number as string of bits: Bitwise Functions. (line 108)
* number of array elements: String Functions. (line 200)
* number sign (#), #! (executable scripts): Executable Scripts.
(line 6)
@@ -33602,27 +34757,27 @@ Index
* numbers, Cliff random: Cliff Random Function.
(line 6)
* numbers, converting: Strings And Numbers. (line 6)
-* numbers, converting <1>: Bitwise Functions. (line 111)
+* numbers, converting <1>: Bitwise Functions. (line 108)
* numbers, converting, to strings: User-modified. (line 30)
-* numbers, converting, to strings <1>: User-modified. (line 104)
+* numbers, converting, to strings <1>: User-modified. (line 107)
* numbers, hexadecimal: Nondecimal-numbers. (line 6)
* numbers, octal: Nondecimal-numbers. (line 6)
* numbers, rounding: Round Function. (line 6)
* numeric constants: Scalar Constants. (line 6)
* numeric functions: Numeric Functions. (line 6)
* numeric, output format: OFMT. (line 6)
-* numeric, strings: Variable Typing. (line 6)
+* numeric, strings: Variable Typing. (line 67)
* o debugger command (alias for option): Debugger Info. (line 57)
* obsolete features: Obsolete. (line 6)
* octal numbers: Nondecimal-numbers. (line 6)
-* octal values, enabling interpretation of: Options. (line 209)
+* octal values, enabling interpretation of: Options. (line 223)
* OFMT variable: OFMT. (line 15)
* OFMT variable <1>: Strings And Numbers. (line 56)
-* OFMT variable <2>: User-modified. (line 104)
+* OFMT variable <2>: User-modified. (line 107)
* OFMT variable, POSIX awk and: OFMT. (line 27)
* OFS variable: Changing Fields. (line 64)
* OFS variable <1>: Output Separators. (line 6)
-* OFS variable <2>: User-modified. (line 113)
+* OFS variable <2>: User-modified. (line 116)
* OpenBSD: Glossary. (line 748)
* OpenSolaris: Other Versions. (line 100)
* operating systems, BSD-based: Manual History. (line 28)
@@ -33669,7 +34824,7 @@ Index
* options, deprecated: Obsolete. (line 6)
* options, long: Command Line. (line 13)
* options, long <1>: Options. (line 6)
-* options, printing list of: Options. (line 154)
+* options, printing list of: Options. (line 168)
* or: Bitwise Functions. (line 50)
* OR bitwise operation: Bitwise Functions. (line 6)
* or Boolean-logic operator: Boolean Ops. (line 6)
@@ -33678,7 +34833,7 @@ Index
* ord() user-defined function: Ordinal Functions. (line 16)
* order of evaluation, concatenation: Concatenation. (line 41)
* ORS variable: Output Separators. (line 20)
-* ORS variable <1>: User-modified. (line 119)
+* ORS variable <1>: User-modified. (line 122)
* output field separator, See OFS variable: Changing Fields. (line 64)
* output record separator, See ORS variable: Output Separators.
(line 20)
@@ -33698,7 +34853,7 @@ Index
* p debugger command (alias for print): Viewing And Changing Data.
(line 35)
* Papadopoulos, Panos: Contributors. (line 129)
-* parent process ID of gawk process: Auto-set. (line 187)
+* parent process ID of gawk process: Auto-set. (line 230)
* parentheses (), in a profile: Profiling. (line 146)
* parentheses (), regexp operator: Regexp Operators. (line 81)
* password file: Passwd Functions. (line 16)
@@ -33742,14 +34897,14 @@ Index
* plus sign (+), += operator <1>: Precedence. (line 94)
* plus sign (+), regexp operator: Regexp Operators. (line 105)
* pointers to functions: Indirect Calls. (line 6)
-* portability: Escape Sequences. (line 100)
+* portability: Escape Sequences. (line 103)
* portability, #! (executable scripts): Executable Scripts. (line 33)
* portability, ** operator and: Arithmetic Ops. (line 81)
* portability, **= operator and: Assignment Ops. (line 144)
* portability, ARGV variable: Executable Scripts. (line 59)
* portability, backslash continuation and: Statements/Lines. (line 30)
* portability, backslash in escape sequences: Escape Sequences.
- (line 105)
+ (line 108)
* portability, close() function and: Close Files And Pipes.
(line 81)
* portability, data files as single record: gawk split records.
@@ -33767,13 +34922,13 @@ Index
* portability, NF variable, decrementing: Changing Fields. (line 115)
* portability, operators: Increment Ops. (line 60)
* portability, operators, not in POSIX awk: Precedence. (line 97)
-* portability, POSIXLY_CORRECT environment variable: Options. (line 358)
-* portability, substr() function: String Functions. (line 513)
+* portability, POSIXLY_CORRECT environment variable: Options. (line 377)
+* portability, substr() function: String Functions. (line 515)
* portable object files: Explaining gettext. (line 37)
* portable object files <1>: Translator i18n. (line 6)
* portable object files, converting to message object files: I18N Example.
(line 66)
-* portable object files, generating: Options. (line 147)
+* portable object files, generating: Options. (line 161)
* portable object template files: Explaining gettext. (line 31)
* porting gawk: New Ports. (line 6)
* positional specifiers, printf statement: Format Modifiers. (line 13)
@@ -33788,7 +34943,7 @@ Index
* POSIX awk, < operator and: Getline/File. (line 26)
* POSIX awk, arithmetic operators and: Arithmetic Ops. (line 30)
* POSIX awk, backslashes in string constants: Escape Sequences.
- (line 105)
+ (line 108)
* POSIX awk, BEGIN/END patterns: I/O And BEGIN/END. (line 15)
* POSIX awk, bracket expressions and: Bracket Expressions. (line 34)
* POSIX awk, bracket expressions and, character classes: Bracket Expressions.
@@ -33799,17 +34954,15 @@ Index
* POSIX awk, changes in awk versions: POSIX. (line 6)
* 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 253)
-* POSIX awk, field separators and: Fields. (line 6)
-* POSIX awk, field separators and <1>: Full Line Fields. (line 16)
-* POSIX awk, FS variable and: User-modified. (line 60)
+* POSIX awk, date utility and: Time Functions. (line 255)
+* POSIX awk, field separators and: Full Line Fields. (line 16)
* POSIX awk, function keyword in: Definition Syntax. (line 99)
* POSIX awk, functions and, gsub()/sub(): Gory Details. (line 90)
* POSIX awk, functions and, length(): String Functions. (line 179)
* POSIX awk, GNU long options and: Options. (line 15)
* POSIX awk, interval expressions in: Regexp Operators. (line 135)
* POSIX awk, next/nextfile statements and: Next Statement. (line 44)
-* POSIX awk, numeric strings and: Variable Typing. (line 6)
+* POSIX awk, numeric strings and: Variable Typing. (line 67)
* POSIX awk, OFMT variable and: OFMT. (line 27)
* POSIX awk, OFMT variable and <1>: Strings And Numbers. (line 56)
* POSIX awk, period (.), using: Regexp Operators. (line 51)
@@ -33817,13 +34970,13 @@ Index
* POSIX awk, regular expressions and: Regexp Operators. (line 161)
* POSIX awk, timestamps and: Time Functions. (line 6)
* POSIX awk, | I/O operator and: Getline/Pipe. (line 56)
-* POSIX mode: Options. (line 254)
-* POSIX mode <1>: Options. (line 338)
+* POSIX mode: Options. (line 271)
+* POSIX mode <1>: Options. (line 357)
* 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)
-* PREC variable: User-modified. (line 124)
+* POSIXLY_CORRECT environment variable: Options. (line 357)
+* PREC variable: User-modified. (line 127)
* precedence: Increment Ops. (line 60)
* precedence <1>: Precedence. (line 6)
* precedence, regexp operators: Regexp Operators. (line 156)
@@ -33838,7 +34991,7 @@ Index
* print statement, commas, omitting: Print Examples. (line 30)
* print statement, I/O operators in: Precedence. (line 70)
* print statement, line continuations and: Print Examples. (line 75)
-* print statement, OFMT variable and: User-modified. (line 113)
+* print statement, OFMT variable and: User-modified. (line 116)
* print statement, See Also redirection, of output: Redirection.
(line 17)
* print statement, sprintf() function and: Round Function. (line 6)
@@ -33864,19 +35017,19 @@ Index
* printf statement, syntax of: Basic Printf. (line 6)
* printing: Printing. (line 6)
* printing messages from extensions: Printing Messages. (line 6)
-* printing, list of options: Options. (line 154)
+* printing, list of options: Options. (line 168)
* printing, mailing labels: Labels Program. (line 6)
* printing, unduplicated lines of text: Uniq Program. (line 6)
* printing, user information: Id Program. (line 6)
* private variables: Library Names. (line 11)
-* process group ID of gawk process: Auto-set. (line 181)
-* process ID of gawk process: Auto-set. (line 184)
+* process group ID of gawk process: Auto-set. (line 224)
+* process ID of gawk process: Auto-set. (line 227)
* processes, two-way communications with: Two-way I/O. (line 6)
* processing data: Basic High Level. (line 6)
-* PROCINFO array: Auto-set. (line 129)
-* PROCINFO array <1>: Time Functions. (line 47)
+* PROCINFO array: Auto-set. (line 148)
+* PROCINFO array <1>: Time Functions. (line 49)
* PROCINFO array <2>: Passwd Functions. (line 6)
-* PROCINFO array, and communications via ptys: Two-way I/O. (line 108)
+* PROCINFO array, and communications via ptys: Two-way I/O. (line 114)
* 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.
@@ -33884,8 +35037,8 @@ Index
* PROCINFO, values of sorted_in: Controlling Scanning.
(line 26)
* profiling awk programs: Profiling. (line 6)
-* profiling awk programs, dynamically: Profiling. (line 178)
-* program identifiers: Auto-set. (line 150)
+* profiling awk programs, dynamically: Profiling. (line 177)
+* program identifiers: Auto-set. (line 193)
* program, definition of: Getting Started. (line 21)
* programming conventions, --non-decimal-data option: Nondecimal Data.
(line 35)
@@ -33921,7 +35074,7 @@ Index
* QuikTrim Awk: Other Versions. (line 139)
* quit debugger command: Miscellaneous Debugger Commands.
(line 102)
-* QUIT signal (MS-Windows): Profiling. (line 213)
+* QUIT signal (MS-Windows): Profiling. (line 212)
* quoting in gawk command lines: Long. (line 26)
* quoting in gawk command lines, tricks for: Quoting. (line 91)
* quoting, for small awk programs: Comments. (line 27)
@@ -33930,12 +35083,12 @@ Index
* Rakitzis, Byron: History Sorting. (line 25)
* Ramey, Chet: Acknowledgments. (line 60)
* Ramey, Chet <1>: General Data Types. (line 6)
-* rand: Numeric Functions. (line 34)
+* rand: Numeric Functions. (line 52)
* random numbers, Cliff: Cliff Random Function.
(line 6)
* random numbers, rand()/srand() functions: Numeric Functions.
- (line 34)
-* random numbers, seed of: Numeric Functions. (line 64)
+ (line 52)
+* random numbers, seed of: Numeric Functions. (line 82)
* range expressions (regexps): Bracket Expressions. (line 6)
* range patterns: Ranges. (line 6)
* range patterns, line continuation and: Ranges. (line 64)
@@ -33954,7 +35107,7 @@ Index
* reading input files: Reading Files. (line 6)
* recipe for a programming language: History. (line 6)
* record separators: awk split records. (line 6)
-* record separators <1>: User-modified. (line 133)
+* record separators <1>: User-modified. (line 136)
* record separators, changing: awk split records. (line 85)
* record separators, regular expressions as: awk split records.
(line 124)
@@ -33980,7 +35133,7 @@ Index
(line 103)
* regexp constants, /=.../, /= operator and: Assignment Ops. (line 149)
* regexp constants, as patterns: Expression Patterns. (line 34)
-* regexp constants, in gawk: Using Constant Regexps.
+* regexp constants, in gawk: Standard Regexp Constants.
(line 28)
* regexp constants, slashes vs. quotes: Computed Regexps. (line 30)
* regexp constants, vs. string constants: Computed Regexps. (line 40)
@@ -33996,7 +35149,7 @@ Index
* regular expressions, as record separators: awk split records.
(line 124)
* regular expressions, case sensitivity: Case-sensitivity. (line 6)
-* regular expressions, case sensitivity <1>: User-modified. (line 76)
+* regular expressions, case sensitivity <1>: User-modified. (line 79)
* regular expressions, computed: Computed Regexps. (line 6)
* regular expressions, constants, See regexp constants: Regexp Usage.
(line 57)
@@ -34005,7 +35158,7 @@ Index
(line 60)
* regular expressions, gawk, command-line options: GNU Regexp Operators.
(line 73)
-* regular expressions, interval expressions and: Options. (line 278)
+* regular expressions, interval expressions and: Options. (line 292)
* regular expressions, leftmost longest match: Leftmost Longest.
(line 6)
* regular expressions, operators: Regexp Usage. (line 19)
@@ -34021,7 +35174,8 @@ Index
* regular expressions, searching for: Egrep Program. (line 6)
* relational operators, See comparison operators: Typing and Comparison.
(line 9)
-* replace in string: String Functions. (line 409)
+* replace in string: String Functions. (line 411)
+* retrying input: Retrying Input. (line 6)
* return debugger command: Debugger Execution Control.
(line 54)
* return statement, user-defined functions: Return Statement. (line 6)
@@ -34045,7 +35199,7 @@ Index
* right shift: Bitwise Functions. (line 54)
* right shift, bitwise: Bitwise Functions. (line 32)
* Ritchie, Dennis: Basic Data Typing. (line 54)
-* RLENGTH variable: Auto-set. (line 251)
+* RLENGTH variable: Auto-set. (line 302)
* RLENGTH variable, match() function and: String Functions. (line 227)
* Robbins, Arnold: Command Line Field Separator.
(line 71)
@@ -34066,16 +35220,16 @@ Index
* round to nearest integer: Numeric Functions. (line 24)
* round() user-defined function: Round Function. (line 16)
* rounding numbers: Round Function. (line 6)
-* ROUNDMODE variable: User-modified. (line 128)
+* ROUNDMODE variable: User-modified. (line 131)
* RS variable: awk split records. (line 12)
-* RS variable <1>: User-modified. (line 133)
+* RS variable <1>: User-modified. (line 136)
* RS variable, multiline records and: Multiple Line. (line 17)
* rshift: Bitwise Functions. (line 54)
-* RSTART variable: Auto-set. (line 257)
+* RSTART variable: Auto-set. (line 308)
* RSTART variable, match() function and: String Functions. (line 227)
* RT variable: awk split records. (line 124)
* RT variable <1>: Multiple Line. (line 130)
-* RT variable <2>: Auto-set. (line 264)
+* RT variable <2>: Auto-set. (line 315)
* Rubin, Paul: History. (line 30)
* Rubin, Paul <1>: Contributors. (line 16)
* rule, definition of: Getting Started. (line 21)
@@ -34086,14 +35240,14 @@ Index
(line 68)
* sample debugging session: Sample Debugging Session.
(line 6)
-* sandbox mode: Options. (line 285)
+* sandbox mode: Options. (line 304)
* save debugger options: Debugger Info. (line 85)
* scalar or array: Type Functions. (line 11)
* scalar values: Basic Data Typing. (line 13)
* scanning arrays: Scanning an Array. (line 6)
* scanning multidimensional arrays: Multiscanning. (line 11)
* Schorr, Andrew: Acknowledgments. (line 60)
-* Schorr, Andrew <1>: Auto-set. (line 296)
+* Schorr, Andrew <1>: Auto-set. (line 347)
* Schorr, Andrew <2>: Contributors. (line 134)
* Schreiber, Bert: Acknowledgments. (line 38)
* Schreiber, Rita: Acknowledgments. (line 38)
@@ -34112,7 +35266,7 @@ Index
* sed utility: Full Line Fields. (line 22)
* sed utility <1>: Simple Sed. (line 6)
* sed utility <2>: Glossary. (line 16)
-* seeding random number generator: Numeric Functions. (line 64)
+* seeding random number generator: Numeric Functions. (line 82)
* semicolon (;), AWKPATH variable and: PC Using. (line 9)
* semicolon (;), separating statements in actions: Statements/Lines.
(line 90)
@@ -34120,18 +35274,17 @@ Index
(line 19)
* semicolon (;), separating statements in actions <2>: Statements.
(line 10)
-* separators, field: User-modified. (line 50)
-* separators, field <1>: User-modified. (line 113)
+* separators, field: User-modified. (line 53)
+* separators, field <1>: User-modified. (line 116)
* separators, field, FIELDWIDTHS variable and: User-modified. (line 37)
-* separators, field, FPAT variable and: User-modified. (line 43)
-* separators, field, POSIX and: Fields. (line 6)
+* separators, field, FPAT variable and: User-modified. (line 46)
* separators, for records: awk split records. (line 6)
* separators, for records <1>: awk split records. (line 85)
-* separators, for records <2>: User-modified. (line 133)
+* separators, for records <2>: User-modified. (line 136)
* separators, for records, regular expressions as: awk split records.
(line 124)
* separators, for statements in actions: Action Overview. (line 19)
-* separators, subscript: User-modified. (line 146)
+* separators, subscript: User-modified. (line 149)
* set breakpoint: Breakpoint Control. (line 11)
* set debugger command: Viewing And Changing Data.
(line 58)
@@ -34176,19 +35329,20 @@ Index
* sidebar, A Constant's Base Does Not Affect Its Value: Nondecimal-numbers.
(line 63)
* sidebar, Backslash Before Regular Characters: Escape Sequences.
- (line 103)
+ (line 106)
+* sidebar, Beware The Smoke and Mirrors!: Bitwise Functions. (line 126)
* sidebar, Changing FS Does Not Affect the Fields: Full Line Fields.
(line 14)
-* sidebar, Changing NR and FNR: Auto-set. (line 324)
+* sidebar, Changing NR and FNR: Auto-set. (line 375)
* sidebar, Controlling Output Buffering with system(): I/O Functions.
(line 164)
* sidebar, Escape Sequences for Metacharacters: Escape Sequences.
- (line 135)
+ (line 138)
* sidebar, FS and IGNORECASE: Field Splitting Summary.
(line 37)
* sidebar, Interactive Versus Noninteractive Buffering: I/O Functions.
(line 74)
-* sidebar, Matching the Null String: String Functions. (line 535)
+* sidebar, Matching the Null String: String Functions. (line 537)
* sidebar, Operator Evaluation Order: Increment Ops. (line 58)
* sidebar, Piping into sh: Redirection. (line 134)
* sidebar, Pre-POSIX awk Used OFMT for String Conversion: Strings And Numbers.
@@ -34205,19 +35359,19 @@ Index
(line 130)
* sidebar, Using \n in Bracket Expressions of Dynamic Regexps: Computed Regexps.
(line 58)
-* SIGHUP signal, for dynamic profiling: Profiling. (line 210)
-* SIGINT signal (MS-Windows): Profiling. (line 213)
-* signals, HUP/SIGHUP, for profiling: Profiling. (line 210)
-* signals, INT/SIGINT (MS-Windows): Profiling. (line 213)
-* signals, QUIT/SIGQUIT (MS-Windows): Profiling. (line 213)
-* signals, USR1/SIGUSR1, for profiling: Profiling. (line 187)
+* SIGHUP signal, for dynamic profiling: Profiling. (line 209)
+* SIGINT signal (MS-Windows): Profiling. (line 212)
+* signals, HUP/SIGHUP, for profiling: Profiling. (line 209)
+* signals, INT/SIGINT (MS-Windows): Profiling. (line 212)
+* signals, QUIT/SIGQUIT (MS-Windows): Profiling. (line 212)
+* signals, USR1/SIGUSR1, for profiling: Profiling. (line 186)
* signature program: Signature Program. (line 6)
-* SIGQUIT signal (MS-Windows): Profiling. (line 213)
-* SIGUSR1 signal, for dynamic profiling: Profiling. (line 187)
+* SIGQUIT signal (MS-Windows): Profiling. (line 212)
+* SIGUSR1 signal, for dynamic profiling: Profiling. (line 186)
* silent debugger command: Debugger Execution Control.
(line 10)
-* sin: Numeric Functions. (line 75)
-* sine: Numeric Functions. (line 75)
+* sin: Numeric Functions. (line 93)
+* sine: Numeric Functions. (line 93)
* single quote ('): One-shot. (line 15)
* single quote (') in gawk command lines: Long. (line 35)
* single quote ('), in shell commands: Quoting. (line 48)
@@ -34257,20 +35411,20 @@ Index
* source files, search path for: Programs Exercises. (line 70)
* sparse arrays: Array Intro. (line 76)
* Spencer, Henry: Glossary. (line 16)
-* split: String Functions. (line 315)
+* split: String Functions. (line 317)
* split string into array: String Functions. (line 296)
* split utility: Split Program. (line 6)
* split() function, array elements, deleting: Delete. (line 61)
* split.awk program: Split Program. (line 30)
* sprintf: OFMT. (line 15)
-* sprintf <1>: String Functions. (line 384)
-* sprintf() function, OFMT variable and: User-modified. (line 113)
+* sprintf <1>: String Functions. (line 386)
+* sprintf() function, OFMT variable and: User-modified. (line 116)
* sprintf() function, print/printf statements and: Round Function.
(line 6)
-* sqrt: Numeric Functions. (line 78)
+* sqrt: Numeric Functions. (line 96)
* square brackets ([]), regexp operator: Regexp Operators. (line 56)
-* square root: Numeric Functions. (line 78)
-* srand: Numeric Functions. (line 82)
+* square root: Numeric Functions. (line 96)
+* srand: Numeric Functions. (line 100)
* stack frame: Debugging Terms. (line 10)
* Stallman, Richard: Manual History. (line 6)
* Stallman, Richard <1>: Acknowledgments. (line 18)
@@ -34294,7 +35448,7 @@ Index
(line 79)
* stream editors: Full Line Fields. (line 22)
* stream editors <1>: Simple Sed. (line 6)
-* strftime: Time Functions. (line 48)
+* strftime: Time Functions. (line 50)
* string constants: Scalar Constants. (line 15)
* string constants, vs. regexp constants: Computed Regexps. (line 40)
* string extraction (internationalization): String Extraction.
@@ -34305,12 +35459,12 @@ Index
* string-manipulation functions: String Functions. (line 6)
* string-matching operators: Regexp Usage. (line 19)
* string-translation functions: I18N Functions. (line 6)
-* strings splitting, example: String Functions. (line 334)
+* strings splitting, example: String Functions. (line 336)
* strings, converting: Strings And Numbers. (line 6)
-* strings, converting <1>: Bitwise Functions. (line 111)
-* strings, converting letter case: String Functions. (line 523)
+* strings, converting <1>: Bitwise Functions. (line 108)
+* strings, converting letter case: String Functions. (line 525)
* strings, converting, numbers to: User-modified. (line 30)
-* strings, converting, numbers to <1>: User-modified. (line 104)
+* strings, converting, numbers to <1>: User-modified. (line 107)
* strings, empty, See null strings: awk split records. (line 114)
* strings, extracting: String Extraction. (line 6)
* strings, for localization: Programmer i18n. (line 13)
@@ -34318,16 +35472,16 @@ Index
* strings, merging arrays into: Join Function. (line 6)
* strings, null: Regexp Field Splitting.
(line 43)
-* strings, numeric: Variable Typing. (line 6)
-* strtonum: String Functions. (line 391)
+* strings, numeric: Variable Typing. (line 67)
+* strtonum: String Functions. (line 393)
* strtonum() function (gawk), --non-decimal-data option and: Nondecimal Data.
(line 35)
-* sub: Using Constant Regexps.
+* sub: Standard Regexp Constants.
(line 43)
-* sub <1>: String Functions. (line 409)
-* sub() function, arguments of: String Functions. (line 463)
+* sub <1>: String Functions. (line 411)
+* sub() function, arguments of: String Functions. (line 465)
* sub() function, escape processing: Gory Details. (line 6)
-* subscript separators: User-modified. (line 146)
+* subscript separators: User-modified. (line 149)
* subscripts in arrays, multidimensional: Multidimensional. (line 10)
* subscripts in arrays, multidimensional, scanning: Multiscanning.
(line 11)
@@ -34335,20 +35489,20 @@ Index
(line 6)
* subscripts in arrays, uninitialized variables as: Uninitialized Subscripts.
(line 6)
-* SUBSEP variable: User-modified. (line 146)
+* SUBSEP variable: User-modified. (line 149)
* SUBSEP variable, and multidimensional arrays: Multidimensional.
(line 16)
* substitute in string: String Functions. (line 89)
-* substr: String Functions. (line 482)
-* substring: String Functions. (line 482)
+* substr: String Functions. (line 484)
+* substring: String Functions. (line 484)
* Sumner, Andrew: Other Versions. (line 68)
-* supplementary groups of gawk process: Auto-set. (line 228)
+* supplementary groups of gawk process: Auto-set. (line 271)
* switch statement: Switch Statement. (line 6)
-* SYMTAB array: Auto-set. (line 268)
+* SYMTAB array: Auto-set. (line 319)
* syntactic ambiguity: /= operator vs. /=.../ regexp constant: Assignment Ops.
(line 149)
* system: I/O Functions. (line 107)
-* systime: Time Functions. (line 66)
+* systime: Time Functions. (line 68)
* t debugger command (alias for tbreak): Breakpoint Control. (line 90)
* tbreak debugger command: Breakpoint Control. (line 90)
* Tcl: Library Names. (line 58)
@@ -34358,7 +35512,7 @@ Index
* tee.awk program: Tee Program. (line 26)
* temporary breakpoint: Breakpoint Control. (line 90)
* terminating records: awk split records. (line 124)
-* testbits.awk program: Bitwise Functions. (line 72)
+* testbits.awk program: Bitwise Functions. (line 69)
* testext extension: Extension Sample API Tests.
(line 6)
* Texinfo: Conventions. (line 6)
@@ -34366,14 +35520,14 @@ Index
* Texinfo <2>: Dupword Program. (line 17)
* Texinfo <3>: Extract Program. (line 12)
* Texinfo <4>: Distribution contents.
- (line 77)
+ (line 83)
* Texinfo <5>: Adding Code. (line 100)
* Texinfo, chapter beginnings in files: Regexp Operators. (line 22)
* Texinfo, extracting programs from source files: Extract Program.
(line 6)
* text, printing: Print. (line 22)
* text, printing, unduplicated lines of: Uniq Program. (line 6)
-* TEXTDOMAIN variable: User-modified. (line 152)
+* TEXTDOMAIN variable: User-modified. (line 155)
* TEXTDOMAIN variable <1>: Programmer i18n. (line 8)
* TEXTDOMAIN variable, BEGIN pattern and: Programmer i18n. (line 60)
* TEXTDOMAIN variable, portability and: I18N Portability. (line 20)
@@ -34396,12 +35550,12 @@ Index
* time, retrieving: Time Functions. (line 17)
* timeout, reading input: Read Timeout. (line 6)
* timestamps: Time Functions. (line 6)
-* timestamps <1>: Time Functions. (line 66)
-* timestamps, converting dates to: Time Functions. (line 76)
+* timestamps <1>: Time Functions. (line 68)
+* timestamps, converting dates to: Time Functions. (line 78)
* timestamps, formatted: Getlocaltime Function.
(line 6)
-* tolower: String Functions. (line 524)
-* toupper: String Functions. (line 530)
+* tolower: String Functions. (line 526)
+* toupper: String Functions. (line 532)
* tr utility: Translate Program. (line 6)
* trace debugger command: Miscellaneous Debugger Commands.
(line 110)
@@ -34409,15 +35563,15 @@ Index
* translate string: I18N Functions. (line 21)
* translate.awk program: Translate Program. (line 55)
* treating files, as single records: gawk split records. (line 92)
-* troubleshooting, --non-decimal-data option: Options. (line 209)
+* troubleshooting, --non-decimal-data option: Options. (line 223)
* troubleshooting, == operator: Comparison Operators.
(line 37)
* troubleshooting, awk uses FS not IFS: Field Separators. (line 29)
* troubleshooting, backslash before nonspecial character: Escape Sequences.
- (line 105)
+ (line 108)
* troubleshooting, division: Arithmetic Ops. (line 44)
-* troubleshooting, fatal errors, field widths, specifying: Constant Size.
- (line 22)
+* troubleshooting, fatal errors, field widths, specifying: Fixed width data.
+ (line 17)
* troubleshooting, fatal errors, printf format strings: Format Modifiers.
(line 157)
* troubleshooting, fflush() function: I/O Functions. (line 63)
@@ -34427,7 +35581,7 @@ Index
* troubleshooting, gawk, fatal errors, function arguments: Calling Built-in.
(line 16)
* troubleshooting, getline function: File Checking. (line 25)
-* troubleshooting, gsub()/sub() functions: String Functions. (line 473)
+* troubleshooting, gsub()/sub() functions: String Functions. (line 475)
* troubleshooting, match() function: String Functions. (line 291)
* troubleshooting, print statement, omitting commas: Print Examples.
(line 30)
@@ -34437,7 +35591,7 @@ Index
* troubleshooting, regexp constants vs. string constants: Computed Regexps.
(line 40)
* troubleshooting, string concatenation: Concatenation. (line 27)
-* troubleshooting, substr() function: String Functions. (line 500)
+* troubleshooting, substr() function: String Functions. (line 502)
* troubleshooting, system() function: I/O Functions. (line 129)
* troubleshooting, typographical errors, global variables: Options.
(line 99)
@@ -34448,6 +35602,8 @@ Index
* trunc-mod operation: Arithmetic Ops. (line 66)
* truth values: Truth Values. (line 6)
* type conversion: Strings And Numbers. (line 21)
+* type, of variable: Type Functions. (line 14)
+* typeof: Type Functions. (line 14)
* u debugger command (alias for until): Debugger Execution Control.
(line 82)
* unassigned array elements: Reference to Elements.
@@ -34470,7 +35626,7 @@ Index
* uniq.awk program: Uniq Program. (line 65)
* Unix: Glossary. (line 748)
* Unix awk, backslashes in escape sequences: Escape Sequences.
- (line 118)
+ (line 121)
* Unix awk, close() function and: Close Files And Pipes.
(line 132)
* Unix awk, password files, field separators and: Command Line Field Separator.
@@ -34489,10 +35645,11 @@ Index
* user-modifiable variables: User-modified. (line 6)
* users, information about, printing: Id Program. (line 6)
* users, information about, retrieving: Passwd Functions. (line 16)
-* USR1 signal, for dynamic profiling: Profiling. (line 187)
+* USR1 signal, for dynamic profiling: Profiling. (line 186)
* values, numeric: Basic Data Typing. (line 13)
* values, string: Basic Data Typing. (line 13)
* variable assignments and input files: Other Arguments. (line 26)
+* variable type: Type Functions. (line 14)
* variable typing: Typing and Comparison.
(line 9)
* variables: Other Features. (line 6)
@@ -34523,10 +35680,10 @@ Index
* variables, uninitialized, as array subscripts: Uninitialized Subscripts.
(line 6)
* variables, user-defined: Variables. (line 6)
-* version of gawk: Auto-set. (line 198)
-* version of gawk extension API: Auto-set. (line 223)
-* version of GNU MP library: Auto-set. (line 206)
-* version of GNU MPFR library: Auto-set. (line 208)
+* version of gawk: Auto-set. (line 241)
+* version of gawk extension API: Auto-set. (line 266)
+* version of GNU MP library: Auto-set. (line 249)
+* version of GNU MPFR library: Auto-set. (line 251)
* vertical bar (|): Regexp Operators. (line 70)
* vertical bar (|), | operator (I/O): Getline/Pipe. (line 10)
* vertical bar (|), | operator (I/O) <1>: Precedence. (line 64)
@@ -34538,7 +35695,7 @@ Index
* Vinschen, Corinna: Acknowledgments. (line 60)
* w debugger command (alias for watch): Viewing And Changing Data.
(line 66)
-* w utility: Constant Size. (line 22)
+* w utility: Fixed width data. (line 17)
* wait() extension function: Extension Sample Fork.
(line 22)
* waitpid() extension function: Extension Sample Fork.
@@ -34547,7 +35704,7 @@ Index
* Wall, Larry: Array Intro. (line 6)
* Wall, Larry <1>: Future Extensions. (line 6)
* Wallin, Anders: Contributors. (line 104)
-* warnings, issuing: Options. (line 184)
+* warnings, issuing: Options. (line 198)
* watch debugger command: Viewing And Changing Data.
(line 66)
* watchpoint: Debugging Terms. (line 42)
@@ -34563,7 +35720,7 @@ Index
* whitespace, as field separators: Default Field Splitting.
(line 6)
* whitespace, functions, calling: Calling Built-in. (line 10)
-* whitespace, newlines as: Options. (line 260)
+* whitespace, newlines as: Options. (line 277)
* Williams, Kent: Contributors. (line 35)
* Woehlke, Matthew: Contributors. (line 80)
* Woods, John: Contributors. (line 28)
@@ -34593,563 +35750,580 @@ Index

Tag Table:
Node: Top1200
-Node: Foreword342162
-Node: Foreword446604
-Node: Preface48136
-Ref: Preface-Footnote-150995
-Ref: Preface-Footnote-251102
-Ref: Preface-Footnote-351336
-Node: History51478
-Node: Names53830
-Ref: Names-Footnote-154924
-Node: This Manual55071
-Ref: This Manual-Footnote-161556
-Node: Conventions61656
-Node: Manual History64010
-Ref: Manual History-Footnote-167005
-Ref: Manual History-Footnote-267046
-Node: How To Contribute67120
-Node: Acknowledgments67771
-Node: Getting Started72657
-Node: Running gawk75096
-Node: One-shot76286
-Node: Read Terminal77549
-Node: Long79542
-Node: Executable Scripts81055
-Ref: Executable Scripts-Footnote-183850
-Node: Comments83953
-Node: Quoting86437
-Node: DOS Quoting91954
-Node: Sample Data Files92629
-Node: Very Simple95224
-Node: Two Rules100126
-Node: More Complex102011
-Node: Statements/Lines104877
-Ref: Statements/Lines-Footnote-1109336
-Node: Other Features109601
-Node: When110537
-Ref: When-Footnote-1112291
-Node: Intro Summary112356
-Node: Invoking Gawk113240
-Node: Command Line114754
-Node: Options115552
-Ref: Options-Footnote-1131459
-Ref: Options-Footnote-2131689
-Node: Other Arguments131714
-Node: Naming Standard Input134661
-Node: Environment Variables135754
-Node: AWKPATH Variable136312
-Ref: AWKPATH Variable-Footnote-1139613
-Ref: AWKPATH Variable-Footnote-2139647
-Node: AWKLIBPATH Variable139908
-Node: Other Environment Variables141052
-Node: Exit Status145000
-Node: Include Files145677
-Node: Loading Shared Libraries149272
-Node: Obsolete150700
-Node: Undocumented151392
-Node: Invoking Summary151689
-Node: Regexp153349
-Node: Regexp Usage154803
-Node: Escape Sequences156840
-Node: Regexp Operators162854
-Ref: Regexp Operators-Footnote-1170270
-Ref: Regexp Operators-Footnote-2170417
-Node: Bracket Expressions170515
-Ref: table-char-classes172991
-Node: Leftmost Longest176128
-Node: Computed Regexps177431
-Node: GNU Regexp Operators180858
-Node: Case-sensitivity184537
-Ref: Case-sensitivity-Footnote-1187424
-Ref: Case-sensitivity-Footnote-2187659
-Node: Regexp Summary187767
-Node: Reading Files189233
-Node: Records191327
-Node: awk split records192060
-Node: gawk split records196991
-Ref: gawk split records-Footnote-1201531
-Node: Fields201568
-Ref: Fields-Footnote-1204348
-Node: Nonconstant Fields204434
-Ref: Nonconstant Fields-Footnote-1206670
-Node: Changing Fields206874
-Node: Field Separators212802
-Node: Default Field Splitting215500
-Node: Regexp Field Splitting216618
-Node: Single Character Fields219971
-Node: Command Line Field Separator221031
-Node: Full Line Fields224249
-Ref: Full Line Fields-Footnote-1225771
-Ref: Full Line Fields-Footnote-2225817
-Node: Field Splitting Summary225918
-Node: Constant Size227992
-Node: Splitting By Content232570
-Ref: Splitting By Content-Footnote-1236541
-Node: Multiple Line236704
-Ref: Multiple Line-Footnote-1242586
-Node: Getline242765
-Node: Plain Getline244969
-Node: Getline/Variable247608
-Node: Getline/File248757
-Node: Getline/Variable/File250143
-Ref: Getline/Variable/File-Footnote-1251746
-Node: Getline/Pipe251834
-Node: Getline/Variable/Pipe254539
-Node: Getline/Coprocess255672
-Node: Getline/Variable/Coprocess256937
-Node: Getline Notes257677
-Node: Getline Summary260472
-Ref: table-getline-variants260894
-Node: Read Timeout261642
-Ref: Read Timeout-Footnote-1265483
-Node: Command-line directories265541
-Node: Input Summary266445
-Node: Input Exercises269617
-Node: Printing270345
-Node: Print272121
-Node: Print Examples273578
-Node: Output Separators276358
-Node: OFMT278375
-Node: Printf279731
-Node: Basic Printf280516
-Node: Control Letters282090
-Node: Format Modifiers286078
-Node: Printf Examples292093
-Node: Redirection294579
-Node: Special FD301420
-Ref: Special FD-Footnote-1304588
-Node: Special Files304662
-Node: Other Inherited Files305279
-Node: Special Network306280
-Node: Special Caveats307140
-Node: Close Files And Pipes308089
-Ref: Close Files And Pipes-Footnote-1315282
-Ref: Close Files And Pipes-Footnote-2315430
-Node: Output Summary315581
-Node: Output Exercises316579
-Node: Expressions317258
-Node: Values318446
-Node: Constants319124
-Node: Scalar Constants319815
-Ref: Scalar Constants-Footnote-1320679
-Node: Nondecimal-numbers320929
-Node: Regexp Constants323942
-Node: Using Constant Regexps324468
-Node: Variables327631
-Node: Using Variables328288
-Node: Assignment Options330198
-Node: Conversion332071
-Node: Strings And Numbers332595
-Ref: Strings And Numbers-Footnote-1335658
-Node: Locale influences conversions335767
-Ref: table-locale-affects338525
-Node: All Operators339143
-Node: Arithmetic Ops339772
-Node: Concatenation342278
-Ref: Concatenation-Footnote-1345125
-Node: Assignment Ops345232
-Ref: table-assign-ops350223
-Node: Increment Ops351536
-Node: Truth Values and Conditions354996
-Node: Truth Values356070
-Node: Typing and Comparison357118
-Node: Variable Typing357938
-Node: Comparison Operators361562
-Ref: table-relational-ops361981
-Node: POSIX String Comparison365476
-Ref: POSIX String Comparison-Footnote-1366550
-Node: Boolean Ops366689
-Ref: Boolean Ops-Footnote-1371171
-Node: Conditional Exp371263
-Node: Function Calls372999
-Node: Precedence376876
-Node: Locales380535
-Node: Expressions Summary382167
-Node: Patterns and Actions384740
-Node: Pattern Overview385860
-Node: Regexp Patterns387537
-Node: Expression Patterns388079
-Node: Ranges391860
-Node: BEGIN/END394968
-Node: Using BEGIN/END395729
-Ref: Using BEGIN/END-Footnote-1398465
-Node: I/O And BEGIN/END398571
-Node: BEGINFILE/ENDFILE400885
-Node: Empty403792
-Node: Using Shell Variables404109
-Node: Action Overview406383
-Node: Statements408708
-Node: If Statement410556
-Node: While Statement412051
-Node: Do Statement414079
-Node: For Statement415227
-Node: Switch Statement418385
-Node: Break Statement420771
-Node: Continue Statement422863
-Node: Next Statement424690
-Node: Nextfile Statement427073
-Node: Exit Statement429725
-Node: Built-in Variables432128
-Node: User-modified433261
-Ref: User-modified-Footnote-1440886
-Node: Auto-set440948
-Ref: Auto-set-Footnote-1454304
-Ref: Auto-set-Footnote-2454510
-Node: ARGC and ARGV454566
-Node: Pattern Action Summary458779
-Node: Arrays461209
-Node: Array Basics462538
-Node: Array Intro463382
-Ref: figure-array-elements465357
-Ref: Array Intro-Footnote-1468061
-Node: Reference to Elements468189
-Node: Assigning Elements470653
-Node: Array Example471144
-Node: Scanning an Array472903
-Node: Controlling Scanning475925
-Ref: Controlling Scanning-Footnote-1481324
-Node: Numeric Array Subscripts481640
-Node: Uninitialized Subscripts483824
-Node: Delete485443
-Ref: Delete-Footnote-1488195
-Node: Multidimensional488252
-Node: Multiscanning491347
-Node: Arrays of Arrays492938
-Node: Arrays Summary497705
-Node: Functions499798
-Node: Built-in500836
-Node: Calling Built-in501917
-Node: Numeric Functions503913
-Ref: Numeric Functions-Footnote-1507941
-Ref: Numeric Functions-Footnote-2508298
-Ref: Numeric Functions-Footnote-3508346
-Node: String Functions508618
-Ref: String Functions-Footnote-1532122
-Ref: String Functions-Footnote-2532250
-Ref: String Functions-Footnote-3532498
-Node: Gory Details532585
-Ref: table-sub-escapes534376
-Ref: table-sub-proposed535895
-Ref: table-posix-sub537258
-Ref: table-gensub-escapes538799
-Ref: Gory Details-Footnote-1539622
-Node: I/O Functions539776
-Ref: table-system-return-values546358
-Ref: I/O Functions-Footnote-1548338
-Ref: I/O Functions-Footnote-2548486
-Node: Time Functions548606
-Ref: Time Functions-Footnote-1559128
-Ref: Time Functions-Footnote-2559196
-Ref: Time Functions-Footnote-3559354
-Ref: Time Functions-Footnote-4559465
-Ref: Time Functions-Footnote-5559577
-Ref: Time Functions-Footnote-6559804
-Node: Bitwise Functions560070
-Ref: table-bitwise-ops560664
-Ref: Bitwise Functions-Footnote-1564982
-Node: Type Functions565155
-Node: I18N Functions566311
-Node: User-defined567962
-Node: Definition Syntax568767
-Ref: Definition Syntax-Footnote-1574454
-Node: Function Example574525
-Ref: Function Example-Footnote-1577447
-Node: Function Caveats577469
-Node: Calling A Function577987
-Node: Variable Scope578945
-Node: Pass By Value/Reference581939
-Node: Return Statement585438
-Node: Dynamic Typing588417
-Node: Indirect Calls589347
-Ref: Indirect Calls-Footnote-1599598
-Node: Functions Summary599726
-Node: Library Functions602431
-Ref: Library Functions-Footnote-1606038
-Ref: Library Functions-Footnote-2606181
-Node: Library Names606352
-Ref: Library Names-Footnote-1609812
-Ref: Library Names-Footnote-2610035
-Node: General Functions610121
-Node: Strtonum Function611224
-Node: Assert Function614246
-Node: Round Function617572
-Node: Cliff Random Function619113
-Node: Ordinal Functions620129
-Ref: Ordinal Functions-Footnote-1623192
-Ref: Ordinal Functions-Footnote-2623444
-Node: Join Function623654
-Ref: Join Function-Footnote-1625424
-Node: Getlocaltime Function625624
-Node: Readfile Function629366
-Node: Shell Quoting631338
-Node: Data File Management632739
-Node: Filetrans Function633371
-Node: Rewind Function637467
-Node: File Checking639377
-Ref: File Checking-Footnote-1640711
-Node: Empty Files640912
-Node: Ignoring Assigns642891
-Node: Getopt Function644441
-Ref: Getopt Function-Footnote-1655910
-Node: Passwd Functions656110
-Ref: Passwd Functions-Footnote-1664949
-Node: Group Functions665037
-Ref: Group Functions-Footnote-1672935
-Node: Walking Arrays673142
-Node: Library Functions Summary676150
-Node: Library Exercises677556
-Node: Sample Programs678021
-Node: Running Examples678791
-Node: Clones679519
-Node: Cut Program680743
-Node: Egrep Program690672
-Ref: Egrep Program-Footnote-1698184
-Node: Id Program698294
-Node: Split Program701974
-Ref: Split Program-Footnote-1705433
-Node: Tee Program705562
-Node: Uniq Program708352
-Node: Wc Program715778
-Ref: Wc Program-Footnote-1720033
-Node: Miscellaneous Programs720127
-Node: Dupword Program721340
-Node: Alarm Program723370
-Node: Translate Program728225
-Ref: Translate Program-Footnote-1732790
-Node: Labels Program733060
-Ref: Labels Program-Footnote-1736411
-Node: Word Sorting736495
-Node: History Sorting740567
-Node: Extract Program742402
-Node: Simple Sed749931
-Node: Igawk Program753005
-Ref: Igawk Program-Footnote-1767336
-Ref: Igawk Program-Footnote-2767538
-Ref: Igawk Program-Footnote-3767660
-Node: Anagram Program767775
-Node: Signature Program770837
-Node: Programs Summary772084
-Node: Programs Exercises773298
-Ref: Programs Exercises-Footnote-1777427
-Node: Advanced Features777518
-Node: Nondecimal Data779508
-Node: Array Sorting781099
-Node: Controlling Array Traversal781799
-Ref: Controlling Array Traversal-Footnote-1790166
-Node: Array Sorting Functions790284
-Ref: Array Sorting Functions-Footnote-1795375
-Node: Two-way I/O795571
-Ref: Two-way I/O-Footnote-1801865
-Ref: Two-way I/O-Footnote-2802052
-Node: TCP/IP Networking802134
-Node: Profiling805252
-Node: Advanced Features Summary812791
-Node: Internationalization814727
-Node: I18N and L10N816207
-Node: Explaining gettext816894
-Ref: Explaining gettext-Footnote-1822786
-Ref: Explaining gettext-Footnote-2822971
-Node: Programmer i18n823136
-Ref: Programmer i18n-Footnote-1828085
-Node: Translator i18n828134
-Node: String Extraction828928
-Ref: String Extraction-Footnote-1830060
-Node: Printf Ordering830146
-Ref: Printf Ordering-Footnote-1832932
-Node: I18N Portability832996
-Ref: I18N Portability-Footnote-1835452
-Node: I18N Example835515
-Ref: I18N Example-Footnote-1838321
-Node: Gawk I18N838394
-Node: I18N Summary839039
-Node: Debugger840380
-Node: Debugging841402
-Node: Debugging Concepts841843
-Node: Debugging Terms843652
-Node: Awk Debugging846227
-Node: Sample Debugging Session847133
-Node: Debugger Invocation847667
-Node: Finding The Bug849053
-Node: List of Debugger Commands855531
-Node: Breakpoint Control856864
-Node: Debugger Execution Control860558
-Node: Viewing And Changing Data863920
-Node: Execution Stack867294
-Node: Debugger Info868931
-Node: Miscellaneous Debugger Commands873002
-Node: Readline Support878090
-Node: Limitations878986
-Node: Debugging Summary881095
-Node: Arbitrary Precision Arithmetic882268
-Node: Computer Arithmetic883684
-Ref: table-numeric-ranges887275
-Ref: Computer Arithmetic-Footnote-1887997
-Node: Math Definitions888054
-Ref: table-ieee-formats891368
-Ref: Math Definitions-Footnote-1891971
-Node: MPFR features892076
-Node: FP Math Caution893793
-Ref: FP Math Caution-Footnote-1894865
-Node: Inexactness of computations895234
-Node: Inexact representation896194
-Node: Comparing FP Values897554
-Node: Errors accumulate898636
-Node: Getting Accuracy900069
-Node: Try To Round902779
-Node: Setting precision903678
-Ref: table-predefined-precision-strings904375
-Node: Setting the rounding mode906205
-Ref: table-gawk-rounding-modes906579
-Ref: Setting the rounding mode-Footnote-1909987
-Node: Arbitrary Precision Integers910166
-Ref: Arbitrary Precision Integers-Footnote-1913150
-Node: POSIX Floating Point Problems913299
-Ref: POSIX Floating Point Problems-Footnote-1917181
-Node: Floating point summary917219
-Node: Dynamic Extensions919409
-Node: Extension Intro920962
-Node: Plugin License922228
-Node: Extension Mechanism Outline923025
-Ref: figure-load-extension923464
-Ref: figure-register-new-function925029
-Ref: figure-call-new-function926121
-Node: Extension API Description928183
-Node: Extension API Functions Introduction929631
-Node: General Data Types934443
-Ref: General Data Types-Footnote-1940398
-Node: Memory Allocation Functions940697
-Ref: Memory Allocation Functions-Footnote-1943542
-Node: Constructor Functions943641
-Node: Registration Functions945386
-Node: Extension Functions946071
-Node: Exit Callback Functions948370
-Node: Extension Version String949620
-Node: Input Parsers950283
-Node: Output Wrappers960165
-Node: Two-way processors964677
-Node: Printing Messages966942
-Ref: Printing Messages-Footnote-1968016
-Node: Updating ERRNO968169
-Node: Requesting Values968908
-Ref: table-value-types-returned969645
-Node: Accessing Parameters970528
-Node: Symbol Table Access971763
-Node: Symbol table by name972275
-Node: Symbol table by cookie974296
-Ref: Symbol table by cookie-Footnote-1978448
-Node: Cached values978512
-Ref: Cached values-Footnote-1982019
-Node: Array Manipulation982110
-Ref: Array Manipulation-Footnote-1983209
-Node: Array Data Types983246
-Ref: Array Data Types-Footnote-1985904
-Node: Array Functions985996
-Node: Flattening Arrays989854
-Node: Creating Arrays996762
-Node: Extension API Variables1001531
-Node: Extension Versioning1002167
-Ref: gawk-api-version1002604
-Node: Extension API Informational Variables1004360
-Node: Extension API Boilerplate1005424
-Node: Finding Extensions1009238
-Node: Extension Example1009797
-Node: Internal File Description1010595
-Node: Internal File Ops1014675
-Ref: Internal File Ops-Footnote-11026437
-Node: Using Internal File Ops1026577
-Ref: Using Internal File Ops-Footnote-11028960
-Node: Extension Samples1029234
-Node: Extension Sample File Functions1030763
-Node: Extension Sample Fnmatch1038412
-Node: Extension Sample Fork1039899
-Node: Extension Sample Inplace1041117
-Node: Extension Sample Ord1044334
-Node: Extension Sample Readdir1045170
-Ref: table-readdir-file-types1046059
-Node: Extension Sample Revout1046864
-Node: Extension Sample Rev2way1047453
-Node: Extension Sample Read write array1048193
-Node: Extension Sample Readfile1050135
-Node: Extension Sample Time1051230
-Node: Extension Sample API Tests1052578
-Node: gawkextlib1053070
-Node: Extension summary1055494
-Node: Extension Exercises1059186
-Node: Language History1060684
-Node: V7/SVR3.11062340
-Node: SVR41064492
-Node: POSIX1065926
-Node: BTL1067305
-Node: POSIX/GNU1068034
-Node: Feature History1073555
-Node: Common Extensions1086884
-Node: Ranges and Locales1088167
-Ref: Ranges and Locales-Footnote-11092783
-Ref: Ranges and Locales-Footnote-21092810
-Ref: Ranges and Locales-Footnote-31093045
-Node: Contributors1093266
-Node: History summary1098826
-Node: Installation1100206
-Node: Gawk Distribution1101150
-Node: Getting1101634
-Node: Extracting1102595
-Node: Distribution contents1104233
-Node: Unix Installation1109975
-Node: Quick Installation1110591
-Node: Additional Configuration Options1113018
-Node: Configuration Philosophy1114822
-Node: Non-Unix Installation1117191
-Node: PC Installation1117651
-Node: PC Binary Installation1118489
-Node: PC Compiling1118924
-Node: PC Using1120041
-Node: Cygwin1123086
-Node: MSYS1123856
-Node: VMS Installation1124357
-Node: VMS Compilation1125148
-Ref: VMS Compilation-Footnote-11126377
-Node: VMS Dynamic Extensions1126435
-Node: VMS Installation Details1128120
-Node: VMS Running1130373
-Node: VMS GNV1134652
-Node: VMS Old Gawk1135387
-Node: Bugs1135858
-Node: Bug address1136521
-Node: Usenet1138918
-Node: Maintainers1139695
-Node: Other Versions1141071
-Node: Installation summary1147655
-Node: Notes1148690
-Node: Compatibility Mode1149555
-Node: Additions1150337
-Node: Accessing The Source1151262
-Node: Adding Code1152697
-Node: New Ports1158915
-Node: Derived Files1163403
-Ref: Derived Files-Footnote-11168888
-Ref: Derived Files-Footnote-21168923
-Ref: Derived Files-Footnote-31169521
-Node: Future Extensions1169635
-Node: Implementation Limitations1170293
-Node: Extension Design1171476
-Node: Old Extension Problems1172630
-Ref: Old Extension Problems-Footnote-11174148
-Node: Extension New Mechanism Goals1174205
-Ref: Extension New Mechanism Goals-Footnote-11177569
-Node: Extension Other Design Decisions1177758
-Node: Extension Future Growth1179871
-Node: Old Extension Mechanism1180707
-Node: Notes summary1182470
-Node: Basic Concepts1183652
-Node: Basic High Level1184333
-Ref: figure-general-flow1184615
-Ref: figure-process-flow1185300
-Ref: Basic High Level-Footnote-11188601
-Node: Basic Data Typing1188786
-Node: Glossary1192114
-Node: Copying1224061
-Node: GNU Free Documentation License1261600
-Node: Index1286718
+Node: Foreword343279
+Node: Foreword447721
+Node: Preface49253
+Ref: Preface-Footnote-152112
+Ref: Preface-Footnote-252219
+Ref: Preface-Footnote-352453
+Node: History52595
+Node: Names54947
+Ref: Names-Footnote-156041
+Node: This Manual56188
+Ref: This Manual-Footnote-162673
+Node: Conventions62773
+Node: Manual History65127
+Ref: Manual History-Footnote-168122
+Ref: Manual History-Footnote-268163
+Node: How To Contribute68237
+Node: Acknowledgments68888
+Node: Getting Started73774
+Node: Running gawk76213
+Node: One-shot77403
+Node: Read Terminal78666
+Node: Long80659
+Node: Executable Scripts82172
+Ref: Executable Scripts-Footnote-184967
+Node: Comments85070
+Node: Quoting87554
+Node: DOS Quoting93071
+Node: Sample Data Files95126
+Node: Very Simple97721
+Node: Two Rules102623
+Node: More Complex104508
+Node: Statements/Lines107374
+Ref: Statements/Lines-Footnote-1111833
+Node: Other Features112098
+Node: When113034
+Ref: When-Footnote-1114788
+Node: Intro Summary114853
+Node: Invoking Gawk115737
+Node: Command Line117251
+Node: Options118049
+Ref: Options-Footnote-1134668
+Ref: Options-Footnote-2134898
+Node: Other Arguments134923
+Node: Naming Standard Input137870
+Node: Environment Variables138963
+Node: AWKPATH Variable139521
+Ref: AWKPATH Variable-Footnote-1142932
+Ref: AWKPATH Variable-Footnote-2142966
+Node: AWKLIBPATH Variable143227
+Node: Other Environment Variables144484
+Node: Exit Status148305
+Node: Include Files148982
+Node: Loading Shared Libraries152577
+Node: Obsolete154005
+Node: Undocumented154697
+Node: Invoking Summary154994
+Node: Regexp156654
+Node: Regexp Usage158108
+Node: Escape Sequences160145
+Node: Regexp Operators166377
+Ref: Regexp Operators-Footnote-1173793
+Ref: Regexp Operators-Footnote-2173940
+Node: Bracket Expressions174038
+Ref: table-char-classes176514
+Node: Leftmost Longest179651
+Node: Computed Regexps180954
+Node: GNU Regexp Operators184381
+Node: Case-sensitivity188060
+Ref: Case-sensitivity-Footnote-1190947
+Ref: Case-sensitivity-Footnote-2191182
+Node: Regexp Summary191290
+Node: Reading Files192756
+Node: Records195025
+Node: awk split records195758
+Node: gawk split records200689
+Ref: gawk split records-Footnote-1205229
+Node: Fields205266
+Node: Nonconstant Fields208007
+Ref: Nonconstant Fields-Footnote-1210243
+Node: Changing Fields210447
+Node: Field Separators216375
+Node: Default Field Splitting219073
+Node: Regexp Field Splitting220191
+Node: Single Character Fields223544
+Node: Command Line Field Separator224604
+Node: Full Line Fields227822
+Ref: Full Line Fields-Footnote-1229344
+Ref: Full Line Fields-Footnote-2229390
+Node: Field Splitting Summary229491
+Node: Constant Size231565
+Node: Fixed width data232297
+Node: Skipping intervening235764
+Node: Allowing trailing data236562
+Node: Fields with fixed data237599
+Node: Splitting By Content239117
+Ref: Splitting By Content-Footnote-1242767
+Node: Testing field creation242930
+Node: Multiple Line244551
+Ref: Multiple Line-Footnote-1250435
+Node: Getline250614
+Node: Plain Getline253083
+Node: Getline/Variable255724
+Node: Getline/File256875
+Node: Getline/Variable/File258263
+Ref: Getline/Variable/File-Footnote-1259868
+Node: Getline/Pipe259956
+Node: Getline/Variable/Pipe262663
+Node: Getline/Coprocess263798
+Node: Getline/Variable/Coprocess265065
+Node: Getline Notes265807
+Node: Getline Summary268604
+Ref: table-getline-variants269028
+Node: Read Timeout269776
+Ref: Read Timeout-Footnote-1273682
+Node: Retrying Input273740
+Node: Command-line directories274939
+Node: Input Summary275845
+Node: Input Exercises279017
+Node: Printing279745
+Node: Print281579
+Node: Print Examples283036
+Node: Output Separators285816
+Node: OFMT287833
+Node: Printf289189
+Node: Basic Printf289974
+Node: Control Letters291548
+Node: Format Modifiers295536
+Node: Printf Examples301551
+Node: Redirection304037
+Node: Special FD310878
+Ref: Special FD-Footnote-1314046
+Node: Special Files314120
+Node: Other Inherited Files314737
+Node: Special Network315738
+Node: Special Caveats316598
+Node: Close Files And Pipes317547
+Ref: table-close-pipe-return-values324454
+Ref: Close Files And Pipes-Footnote-1325237
+Ref: Close Files And Pipes-Footnote-2325385
+Node: Nonfatal325537
+Node: Output Summary327862
+Node: Output Exercises329084
+Node: Expressions329763
+Node: Values330951
+Node: Constants331629
+Node: Scalar Constants332320
+Ref: Scalar Constants-Footnote-1333184
+Node: Nondecimal-numbers333434
+Node: Regexp Constants336435
+Node: Using Constant Regexps336961
+Node: Standard Regexp Constants337583
+Node: Strong Regexp Constants340771
+Node: Variables343729
+Node: Using Variables344386
+Node: Assignment Options346296
+Node: Conversion348169
+Node: Strings And Numbers348693
+Ref: Strings And Numbers-Footnote-1351756
+Node: Locale influences conversions351865
+Ref: table-locale-affects354623
+Node: All Operators355241
+Node: Arithmetic Ops355870
+Node: Concatenation358376
+Ref: Concatenation-Footnote-1361223
+Node: Assignment Ops361330
+Ref: table-assign-ops366321
+Node: Increment Ops367634
+Node: Truth Values and Conditions371094
+Node: Truth Values372168
+Node: Typing and Comparison373216
+Node: Variable Typing374036
+Ref: Variable Typing-Footnote-1380499
+Ref: Variable Typing-Footnote-2380571
+Node: Comparison Operators380648
+Ref: table-relational-ops381067
+Node: POSIX String Comparison384562
+Ref: POSIX String Comparison-Footnote-1386257
+Ref: POSIX String Comparison-Footnote-2386396
+Node: Boolean Ops386480
+Ref: Boolean Ops-Footnote-1390962
+Node: Conditional Exp391054
+Node: Function Calls392790
+Node: Precedence396667
+Node: Locales400326
+Node: Expressions Summary401958
+Node: Patterns and Actions404531
+Node: Pattern Overview405651
+Node: Regexp Patterns407328
+Node: Expression Patterns407870
+Node: Ranges411651
+Node: BEGIN/END414759
+Node: Using BEGIN/END415520
+Ref: Using BEGIN/END-Footnote-1418256
+Node: I/O And BEGIN/END418362
+Node: BEGINFILE/ENDFILE420676
+Node: Empty423583
+Node: Using Shell Variables423900
+Node: Action Overview426174
+Node: Statements428499
+Node: If Statement430347
+Node: While Statement431842
+Node: Do Statement433870
+Node: For Statement435018
+Node: Switch Statement438176
+Node: Break Statement440562
+Node: Continue Statement442654
+Node: Next Statement444481
+Node: Nextfile Statement446864
+Node: Exit Statement449516
+Node: Built-in Variables451919
+Node: User-modified453052
+Node: Auto-set460819
+Ref: Auto-set-Footnote-1476416
+Ref: Auto-set-Footnote-2476622
+Node: ARGC and ARGV476678
+Node: Pattern Action Summary480891
+Node: Arrays483321
+Node: Array Basics484650
+Node: Array Intro485494
+Ref: figure-array-elements487469
+Ref: Array Intro-Footnote-1490173
+Node: Reference to Elements490301
+Node: Assigning Elements492765
+Node: Array Example493256
+Node: Scanning an Array495015
+Node: Controlling Scanning498037
+Ref: Controlling Scanning-Footnote-1503436
+Node: Numeric Array Subscripts503752
+Node: Uninitialized Subscripts505936
+Node: Delete507555
+Ref: Delete-Footnote-1510307
+Node: Multidimensional510364
+Node: Multiscanning513459
+Node: Arrays of Arrays515050
+Node: Arrays Summary519817
+Node: Functions521910
+Node: Built-in522948
+Node: Calling Built-in524029
+Node: Numeric Functions526025
+Ref: Numeric Functions-Footnote-1530970
+Ref: Numeric Functions-Footnote-2531327
+Ref: Numeric Functions-Footnote-3531375
+Node: String Functions531647
+Ref: String Functions-Footnote-1555305
+Ref: String Functions-Footnote-2555433
+Ref: String Functions-Footnote-3555681
+Node: Gory Details555768
+Ref: table-sub-escapes557559
+Ref: table-sub-proposed559078
+Ref: table-posix-sub560441
+Ref: table-gensub-escapes561982
+Ref: Gory Details-Footnote-1562805
+Node: I/O Functions562959
+Ref: table-system-return-values569541
+Ref: I/O Functions-Footnote-1571521
+Ref: I/O Functions-Footnote-2571669
+Node: Time Functions571789
+Ref: Time Functions-Footnote-1582456
+Ref: Time Functions-Footnote-2582524
+Ref: Time Functions-Footnote-3582682
+Ref: Time Functions-Footnote-4582793
+Ref: Time Functions-Footnote-5582905
+Ref: Time Functions-Footnote-6583132
+Node: Bitwise Functions583398
+Ref: table-bitwise-ops583992
+Ref: Bitwise Functions-Footnote-1590025
+Ref: Bitwise Functions-Footnote-2590198
+Node: Type Functions590389
+Node: I18N Functions593064
+Node: User-defined594715
+Node: Definition Syntax595520
+Ref: Definition Syntax-Footnote-1601207
+Node: Function Example601278
+Ref: Function Example-Footnote-1604200
+Node: Function Caveats604222
+Node: Calling A Function604740
+Node: Variable Scope605698
+Node: Pass By Value/Reference608692
+Node: Return Statement612191
+Node: Dynamic Typing615170
+Node: Indirect Calls616100
+Ref: Indirect Calls-Footnote-1626351
+Node: Functions Summary626479
+Node: Library Functions629184
+Ref: Library Functions-Footnote-1632791
+Ref: Library Functions-Footnote-2632934
+Node: Library Names633105
+Ref: Library Names-Footnote-1636565
+Ref: Library Names-Footnote-2636788
+Node: General Functions636874
+Node: Strtonum Function637977
+Node: Assert Function640999
+Node: Round Function644325
+Node: Cliff Random Function645866
+Node: Ordinal Functions646882
+Ref: Ordinal Functions-Footnote-1649945
+Ref: Ordinal Functions-Footnote-2650197
+Node: Join Function650407
+Ref: Join Function-Footnote-1652177
+Node: Getlocaltime Function652377
+Node: Readfile Function656119
+Node: Shell Quoting658091
+Node: Data File Management659492
+Node: Filetrans Function660124
+Node: Rewind Function664220
+Node: File Checking666130
+Ref: File Checking-Footnote-1667464
+Node: Empty Files667665
+Node: Ignoring Assigns669644
+Node: Getopt Function671194
+Ref: Getopt Function-Footnote-1682663
+Node: Passwd Functions682863
+Ref: Passwd Functions-Footnote-1691702
+Node: Group Functions691790
+Ref: Group Functions-Footnote-1699688
+Node: Walking Arrays699895
+Node: Library Functions Summary702903
+Node: Library Exercises704309
+Node: Sample Programs704774
+Node: Running Examples705544
+Node: Clones706272
+Node: Cut Program707496
+Node: Egrep Program717425
+Ref: Egrep Program-Footnote-1724937
+Node: Id Program725047
+Node: Split Program728727
+Ref: Split Program-Footnote-1732186
+Node: Tee Program732315
+Node: Uniq Program735105
+Node: Wc Program742531
+Ref: Wc Program-Footnote-1746786
+Node: Miscellaneous Programs746880
+Node: Dupword Program748093
+Node: Alarm Program750123
+Node: Translate Program754978
+Ref: Translate Program-Footnote-1759543
+Node: Labels Program759813
+Ref: Labels Program-Footnote-1763164
+Node: Word Sorting763248
+Node: History Sorting767320
+Node: Extract Program769155
+Node: Simple Sed776684
+Node: Igawk Program779758
+Ref: Igawk Program-Footnote-1794089
+Ref: Igawk Program-Footnote-2794291
+Ref: Igawk Program-Footnote-3794413
+Node: Anagram Program794528
+Node: Signature Program797590
+Node: Programs Summary798837
+Node: Programs Exercises800051
+Ref: Programs Exercises-Footnote-1804180
+Node: Advanced Features804271
+Node: Nondecimal Data806261
+Node: Array Sorting807852
+Node: Controlling Array Traversal808552
+Ref: Controlling Array Traversal-Footnote-1816919
+Node: Array Sorting Functions817037
+Ref: Array Sorting Functions-Footnote-1822128
+Node: Two-way I/O822324
+Ref: Two-way I/O-Footnote-1828875
+Ref: Two-way I/O-Footnote-2829062
+Node: TCP/IP Networking829144
+Node: Profiling832262
+Ref: Profiling-Footnote-1840934
+Node: Advanced Features Summary841257
+Node: Internationalization843101
+Node: I18N and L10N844581
+Node: Explaining gettext845268
+Ref: Explaining gettext-Footnote-1851160
+Ref: Explaining gettext-Footnote-2851345
+Node: Programmer i18n851510
+Ref: Programmer i18n-Footnote-1856459
+Node: Translator i18n856508
+Node: String Extraction857302
+Ref: String Extraction-Footnote-1858434
+Node: Printf Ordering858520
+Ref: Printf Ordering-Footnote-1861306
+Node: I18N Portability861370
+Ref: I18N Portability-Footnote-1863826
+Node: I18N Example863889
+Ref: I18N Example-Footnote-1866695
+Node: Gawk I18N866768
+Node: I18N Summary867413
+Node: Debugger868754
+Node: Debugging869776
+Node: Debugging Concepts870217
+Node: Debugging Terms872026
+Node: Awk Debugging874601
+Node: Sample Debugging Session875507
+Node: Debugger Invocation876041
+Node: Finding The Bug877427
+Node: List of Debugger Commands883905
+Node: Breakpoint Control885238
+Node: Debugger Execution Control888932
+Node: Viewing And Changing Data892294
+Node: Execution Stack895668
+Node: Debugger Info897305
+Node: Miscellaneous Debugger Commands901376
+Node: Readline Support906464
+Node: Limitations907360
+Node: Debugging Summary909469
+Node: Arbitrary Precision Arithmetic910748
+Node: Computer Arithmetic912233
+Ref: table-numeric-ranges915824
+Ref: Computer Arithmetic-Footnote-1916546
+Node: Math Definitions916603
+Ref: table-ieee-formats919917
+Ref: Math Definitions-Footnote-1920520
+Node: MPFR features920625
+Node: FP Math Caution922342
+Ref: FP Math Caution-Footnote-1923414
+Node: Inexactness of computations923783
+Node: Inexact representation924743
+Node: Comparing FP Values926103
+Node: Errors accumulate927185
+Node: Getting Accuracy928618
+Node: Try To Round931328
+Node: Setting precision932227
+Ref: table-predefined-precision-strings932924
+Node: Setting the rounding mode934754
+Ref: table-gawk-rounding-modes935128
+Ref: Setting the rounding mode-Footnote-1938536
+Node: Arbitrary Precision Integers938715
+Ref: Arbitrary Precision Integers-Footnote-1943620
+Node: Checking for MPFR943769
+Node: POSIX Floating Point Problems945066
+Ref: POSIX Floating Point Problems-Footnote-1948937
+Node: Floating point summary948975
+Node: Dynamic Extensions951165
+Node: Extension Intro952718
+Node: Plugin License953984
+Node: Extension Mechanism Outline954781
+Ref: figure-load-extension955220
+Ref: figure-register-new-function956785
+Ref: figure-call-new-function957877
+Node: Extension API Description959939
+Node: Extension API Functions Introduction961581
+Node: General Data Types966915
+Ref: General Data Types-Footnote-1974120
+Node: Memory Allocation Functions974419
+Ref: Memory Allocation Functions-Footnote-1977571
+Node: Constructor Functions977670
+Node: Registration Functions980669
+Node: Extension Functions981354
+Node: Exit Callback Functions986567
+Node: Extension Version String987817
+Node: Input Parsers988480
+Node: Output Wrappers1001187
+Node: Two-way processors1005699
+Node: Printing Messages1007964
+Ref: Printing Messages-Footnote-11009135
+Node: Updating ERRNO1009288
+Node: Requesting Values1010027
+Ref: table-value-types-returned1010764
+Node: Accessing Parameters1011700
+Node: Symbol Table Access1012935
+Node: Symbol table by name1013447
+Node: Symbol table by cookie1015236
+Ref: Symbol table by cookie-Footnote-11019421
+Node: Cached values1019485
+Ref: Cached values-Footnote-11023021
+Node: Array Manipulation1023112
+Ref: Array Manipulation-Footnote-11024203
+Node: Array Data Types1024240
+Ref: Array Data Types-Footnote-11026898
+Node: Array Functions1026990
+Node: Flattening Arrays1031389
+Node: Creating Arrays1038330
+Node: Redirection API1043099
+Node: Extension API Variables1045941
+Node: Extension Versioning1046574
+Ref: gawk-api-version1047011
+Node: Extension API Informational Variables1048739
+Node: Extension API Boilerplate1049803
+Node: Changes from API V11053665
+Node: Finding Extensions1054325
+Node: Extension Example1054884
+Node: Internal File Description1055682
+Node: Internal File Ops1059762
+Ref: Internal File Ops-Footnote-11071162
+Node: Using Internal File Ops1071302
+Ref: Using Internal File Ops-Footnote-11073685
+Node: Extension Samples1073959
+Node: Extension Sample File Functions1075488
+Node: Extension Sample Fnmatch1083137
+Node: Extension Sample Fork1084624
+Node: Extension Sample Inplace1085842
+Node: Extension Sample Ord1089059
+Node: Extension Sample Readdir1089895
+Ref: table-readdir-file-types1090784
+Node: Extension Sample Revout1091589
+Node: Extension Sample Rev2way1092178
+Node: Extension Sample Read write array1092918
+Node: Extension Sample Readfile1094860
+Node: Extension Sample Time1095955
+Node: Extension Sample API Tests1097303
+Node: gawkextlib1097795
+Node: Extension summary1100242
+Node: Extension Exercises1103944
+Node: Language History1105442
+Node: V7/SVR3.11107098
+Node: SVR41109250
+Node: POSIX1110684
+Node: BTL1112063
+Node: POSIX/GNU1112792
+Node: Feature History1118684
+Node: Common Extensions1133108
+Node: Ranges and Locales1134391
+Ref: Ranges and Locales-Footnote-11139007
+Ref: Ranges and Locales-Footnote-21139034
+Ref: Ranges and Locales-Footnote-31139269
+Node: Contributors1139490
+Node: History summary1145050
+Node: Installation1146430
+Node: Gawk Distribution1147374
+Node: Getting1147858
+Node: Extracting1148819
+Node: Distribution contents1150457
+Node: Unix Installation1156799
+Node: Quick Installation1157481
+Node: Shell Startup Files1159895
+Node: Additional Configuration Options1160984
+Node: Configuration Philosophy1162973
+Node: Non-Unix Installation1165342
+Node: PC Installation1165802
+Node: PC Binary Installation1166640
+Node: PC Compiling1167075
+Node: PC Using1168192
+Node: Cygwin1171237
+Node: MSYS1172007
+Node: VMS Installation1172508
+Node: VMS Compilation1173299
+Ref: VMS Compilation-Footnote-11174528
+Node: VMS Dynamic Extensions1174586
+Node: VMS Installation Details1176271
+Node: VMS Running1178524
+Node: VMS GNV1182803
+Node: VMS Old Gawk1183538
+Node: Bugs1184009
+Node: Bug address1184672
+Node: Usenet1187069
+Node: Maintainers1187846
+Node: Other Versions1189222
+Node: Installation summary1195806
+Node: Notes1196841
+Node: Compatibility Mode1197706
+Node: Additions1198488
+Node: Accessing The Source1199413
+Node: Adding Code1200848
+Node: New Ports1207066
+Node: Derived Files1211554
+Ref: Derived Files-Footnote-11217039
+Ref: Derived Files-Footnote-21217074
+Ref: Derived Files-Footnote-31217672
+Node: Future Extensions1217786
+Node: Implementation Limitations1218444
+Node: Extension Design1219627
+Node: Old Extension Problems1220781
+Ref: Old Extension Problems-Footnote-11222299
+Node: Extension New Mechanism Goals1222356
+Ref: Extension New Mechanism Goals-Footnote-11225720
+Node: Extension Other Design Decisions1225909
+Node: Extension Future Growth1228022
+Node: Old Extension Mechanism1228858
+Node: Notes summary1230621
+Node: Basic Concepts1231803
+Node: Basic High Level1232484
+Ref: figure-general-flow1232766
+Ref: figure-process-flow1233451
+Ref: Basic High Level-Footnote-11236752
+Node: Basic Data Typing1236937
+Node: Glossary1240265
+Node: Copying1272212
+Node: GNU Free Documentation License1309751
+Node: Index1334869

End Tag Table
diff --git a/doc/gawk.texi b/doc/gawk.texi
index 38731606..afdefff4 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -49,6 +49,14 @@
@set MINUS
@end ifdocbook
+@iftex
+@set TIMES @times
+@end iftex
+@ifnottex
+@set TIMES *
+@end ifnottex
+
+
@set xref-automatic-section-title
@c The following information should be updated here only!
@@ -56,7 +64,7 @@
@c applies to and all the info about who's publishing this edition
@c These apply across the board.
-@set UPDATE-MONTH January, 2017
+@set UPDATE-MONTH May, 2017
@set VERSION 4.1
@set PATCHLEVEL 4
@@ -560,7 +568,13 @@ particular records in a file and perform operations upon them.
field.
* Field Splitting Summary:: Some final points and a summary table.
* Constant Size:: Reading constant width data.
+* Fixed width data:: Processing fixed-width data.
+* Skipping intervening:: Skipping intervening fields.
+* Allowing trailing data:: Capturing optional trailing data.
+* Fields with fixed data:: Field values with fixed-width data.
* Splitting By Content:: Defining Fields By Content
+* Testing field creation:: Checking how @command{gawk} is
+ splitting records.
* Multiple Line:: Reading multiline records.
* Getline:: Reading files under explicit program
control using the @code{getline}
@@ -581,6 +595,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.
+* Retrying Input:: Retrying input after certain errors.
* Command-line directories:: What happens if you put a directory on
the command line.
* Input Summary:: Input summary.
@@ -610,6 +625,7 @@ particular records in a file and perform operations upon them.
* Special Caveats:: Things to watch out for.
* Close Files And Pipes:: Closing Input and Output Files and
Pipes.
+* Nonfatal:: Enabling Nonfatal Output.
* Output Summary:: Output summary.
* Output Exercises:: Exercises.
* Values:: Constants, Variables, and Regular
@@ -619,6 +635,9 @@ particular records in a file and perform operations upon them.
* Nondecimal-numbers:: What are octal and hex numbers.
* Regexp Constants:: Regular Expression constants.
* Using Constant Regexps:: When and how to use a regexp constant.
+* Standard Regexp Constants:: Regexp constants in standard
+ @command{awk}.
+* Strong Regexp Constants:: Strongly typed regexp constants.
* Variables:: Variables give names to values for
later use.
* Using Variables:: Using variables in your programs.
@@ -889,6 +908,7 @@ particular records in a file and perform operations upon them.
* Setting the rounding mode:: How to set the rounding mode.
* Arbitrary Precision Integers:: Arbitrary Precision Integer Arithmetic
with @command{gawk}.
+* Checking for MPFR:: How to check if MPFR is available.
* POSIX Floating Point Problems:: Standards Versus Existing Practice.
* Floating point summary:: Summary of floating point discussion.
* Extension Intro:: What is an extension.
@@ -921,11 +941,14 @@ particular records in a file and perform operations upon them.
* Array Functions:: Functions for working with arrays.
* Flattening Arrays:: How to flatten arrays.
* Creating Arrays:: How to create and populate arrays.
+* Redirection API:: How to access and manipulate
+ redirections.
* Extension API Variables:: Variables provided by the API.
* Extension Versioning:: API Version information.
* Extension API Informational Variables:: Variables providing information about
@command{gawk}'s invocation.
* Extension API Boilerplate:: Boilerplate code for using the API.
+* Changes from API V1:: Changes from V1 of the API.
* Finding Extensions:: How @command{gawk} finds compiled
extensions.
* Extension Example:: Example C code for an extension.
@@ -979,14 +1002,16 @@ particular records in a file and perform operations upon them.
* Unix Installation:: Installing @command{gawk} under
various versions of Unix.
* Quick Installation:: Compiling @command{gawk} under Unix.
+* Shell Startup Files:: Shell convenience functions.
* Additional Configuration Options:: Other compile-time options.
* Configuration Philosophy:: How it's all supposed to work.
* Non-Unix Installation:: Installation on Other Operating
Systems.
-* PC Installation:: Installing and Compiling @command{gawk} on
- Microsoft Windows.
+* PC Installation:: Installing and Compiling
+ @command{gawk} on Microsoft Windows.
* PC Binary Installation:: Installing a prepared distribution.
-* PC Compiling:: Compiling @command{gawk} for Windows32.
+* PC Compiling:: Compiling @command{gawk} for
+ Windows32.
* PC Using:: Running @command{gawk} on Windows32.
* Cygwin:: Building and running @command{gawk}
for Cygwin.
@@ -3022,14 +3047,59 @@ it is worth addressing.
@cindex Brink, Jeroen
The ``shells'' on Microsoft Windows systems use the double-quote
character for quoting, and make it difficult or impossible to include an
-escaped double-quote character in a command-line script.
-The following example, courtesy of Jeroen Brink, shows
-how to print all lines in a file surrounded by double quotes:
+escaped double-quote character in a command-line script. The following
+example, courtesy of Jeroen Brink, shows how to escape the double quotes
+from this one liner script that prints all lines in a file surrounded by
+double quotes:
+
+@example
+@{ print "\"" $0 "\"" @}
+@end example
+
+@noindent
+In an MS-Windows command-line the one-liner script above may be passed as
+follows:
@example
gawk "@{ print \"\042\" $0 \"\042\" @}" @var{file}
@end example
+In this example the @samp{\042} is the octal code for a double-quote;
+@command{gawk} converts it into a real double-quote for output by
+the @code{print} statement.
+
+In MS-Windows escaping double-quotes is a little tricky because you use
+backslashes to escape double-quotes, but backslashes themselves are not
+escaped in the usual way; indeed they are either duplicated or not,
+depending upon whether there is a subsequent double-quote. The MS-Windows
+rule for double-quoting a string is the following:
+
+@enumerate
+@item
+For each double quote in the orginal string, let @var{N} be the number
+of backslash(es) before it, @var{N} might be zero. Replace these @var{N}
+backslash(es) by @math{2@value{TIMES}@var{N}+1} backslash(es)
+
+@item
+Let @var{N} be the number of backslash(es) tailing the original string,
+@var{N} might be zero. Replace these @var{N} backslash(es) by
+@math{2@value{TIMES}@var{N}} backslash(es)
+
+@item
+Surround the resulting string by double-quotes.
+@end enumerate
+
+So to double-quote the one-liner script @samp{@{ print "\"" $0 "\"" @}}
+from the previous example you would do it this way:
+
+@example
+gawk "@{ print \"\\\"\" $0 \"\\\"\" @}" @var{file}
+@end example
+
+@noindent
+However, the use of @samp{\042} instead of @samp{\\\"} is also possible
+and easier to read, because backslashes that are not followed by a
+double-quote don't need duplication.
@node Sample Data Files
@section @value{DDF}s for the Examples
@@ -3898,6 +3968,24 @@ This is particularly useful
when you have library functions that you want to use from your command-line
programs (@pxref{AWKPATH Variable}).
+Note that @command{gawk} treats each string as if it ended with
+a newline character (even if it doesn't). This makes building
+the total program easier.
+
+@quotation CAUTION
+At the moment, there is no requirement that each @var{program-text}
+be a full syntactic unit. I.e., the following currently works:
+
+@example
+$ @kbd{gawk -e 'BEGIN @{ a = 5 ;' -e 'print a @}'}
+@print{} 5
+@end example
+
+@noindent
+However, this could change in the future, so it's not a
+good idea to rely upon this feature.
+@end quotation
+
@item @option{-E} @var{file}
@itemx @option{--exec} @var{file}
@cindex @option{-E} option
@@ -4049,6 +4137,7 @@ when parsing numeric input data (@pxref{Locales}).
@cindex @option{-o} option
@cindex @option{--pretty-print} option
Enable pretty-printing of @command{awk} programs.
+Implies @option{--no-optimize}.
By default, the output program is created in a file named @file{awkprof.out}
(@pxref{Profiling}).
The optional @var{file} argument allows you to specify a different
@@ -4057,18 +4146,22 @@ No space is allowed between the @option{-o} and @var{file}, if
@var{file} is supplied.
@quotation NOTE
-Due to the way @command{gawk} has evolved, with this option
-your program still executes. This will change in the
-next major release, such that @command{gawk} will only
-pretty-print the program and not run it.
+In the past, this option would also execute your program.
+This is no longer the case.
@end quotation
@item @option{-O}
@itemx @option{--optimize}
@cindex @option{--optimize} option
@cindex @option{-O} option
-Enable some optimizations on the internal representation of the program.
-At the moment, this includes just simple constant folding.
+Enable @command{gawk}'s default optimizations on the internal
+representation of the program. At the moment, this includes simple
+constant folding and tail recursion elimination in function calls.
+
+These optimizations are enabled by default.
+This option remains primarily for backwards compatibility. However, it may
+be used to cancel the effect of an earlier @option{-s} option
+(see later in this list).
@item @option{-p}[@var{file}]
@itemx @option{--profile}[@code{=}@var{file}]
@@ -4077,6 +4170,7 @@ At the moment, this includes just simple constant folding.
@cindex @command{awk} profiling, enabling
Enable profiling of @command{awk} programs
(@pxref{Profiling}).
+Implies @option{--no-optimize}.
By default, profiles are created in a file named @file{awkprof.out}.
The optional @var{file} argument allows you to specify a different
@value{FN} for the profile file.
@@ -4106,11 +4200,6 @@ restrictions apply:
@cindex newlines
@cindex whitespace, newlines as
@item
-Newlines do not act as whitespace to separate fields when @code{FS} is
-equal to a single space
-(@pxref{Fields}).
-
-@item
Newlines are not allowed after @samp{?} or @samp{:}
(@pxref{Conditional Exp}).
@@ -4148,6 +4237,13 @@ This is now @command{gawk}'s default behavior.
Nevertheless, this option remains (both for backward compatibility
and for use in combination with @option{--traditional}).
+@item @option{-s}
+@itemx @option{--no-optimize}
+@cindex @option{--no-optimize} option
+@cindex @option{-s} option
+Disable @command{gawk}'s default optimizations on the internal
+representation of the program.
+
@item @option{-S}
@itemx @option{--sandbox}
@cindex @option{-S} option
@@ -4461,6 +4557,9 @@ searches first in the current directory and then in @file{/usr/local/share/awk}.
In practice, this means that you will rarely need to change the
value of @env{AWKPATH}.
+@xref{Shell Startup Files}, for information on functions that help to
+manipulate the @env{AWKPATH} variable.
+
@command{gawk} places the value of the search path that it used into
@code{ENVIRON["AWKPATH"]}. This provides access to the actual search
path value from within an @command{awk} program.
@@ -4492,6 +4591,9 @@ an empty value, @command{gawk} uses a default path; this
is typically @samp{/usr/local/lib/gawk}, although it can vary depending
upon how @command{gawk} was built.
+@xref{Shell Startup Files}, for information on functions that help to
+manipulate the @env{AWKLIBPATH} variable.
+
@command{gawk} places the value of the search path that it used into
@code{ENVIRON["AWKLIBPATH"]}. This provides access to the actual search
path value from within an @command{awk} program.
@@ -4519,6 +4621,8 @@ wait for input before returning with an error.
Controls the number of times @command{gawk} attempts to
retry a two-way TCP/IP (socket) connection before giving up.
@xref{TCP/IP Networking}.
+Note that when nonfatal I/O is enabled (@pxref{Nonfatal}),
+@command{gawk} only tries to open a TCP/IP socket once.
@item POSIXLY_CORRECT
Causes @command{gawk} to switch to POSIX-compatibility
@@ -4573,14 +4677,6 @@ two regexp matchers that @command{gawk} uses internally. (There aren't
supposed to be differences, but occasionally theory and practice don't
coordinate with each other.)
-@item GAWK_NO_PP_RUN
-When @command{gawk} is invoked with the @option{--pretty-print} option,
-it will not run the program if this environment variable exists.
-
-@quotation CAUTION
-This variable will not survive into the next major release.
-@end quotation
-
@item GAWK_STACKSIZE
This specifies the amount by which @command{gawk} should grow its
internal evaluation stack, when needed.
@@ -4878,6 +4974,13 @@ Similarly, you may use @code{print} or @code{printf} statements in the
@var{init} and @var{increment} parts of a @code{for} loop. This is another
long-undocumented ``feature'' of Unix @command{awk}.
+@command{gawk} lets you use the names of built-in functions that are
+@command{gawk} extensions as the names of parameters in user-defined functions.
+This is intended to ``future-proof'' old code that happens to use
+function names added by @command{gawk} after the code was written.
+Standard @command{awk} built-in functions, such as @code{sin()} or
+@code{substr()} are @emph{not} shadowed in this way.
+
@end ignore
@node Invoking Summary
@@ -5160,17 +5263,21 @@ 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}
-However, using more than two hexadecimal digits produces
-undefined results. (The @samp{\x} escape sequence is not allowed in
-POSIX @command{awk}.)
+or @samp{a}--@samp{f}). A maximum of two digts are allowed after
+the @samp{\x}. Any further hexadecimal digits are treated as simple
+letters or numbers. @value{COMMONEXT}
+(The @samp{\x} escape sequence is not allowed in POSIX awk.)
@quotation CAUTION
-The next major release of @command{gawk} will change, such
-that a maximum of two hexadecimal digits following the
-@samp{\x} will be used.
+In ISO C, the escape sequence continues until the first nonhexadecimal
+digit is seen.
+For many years, @command{gawk} would continue incorporating
+hexadecimal digits into the value until a non-hexadecimal digit
+or the end of the string was encountered.
+However, using more than two hexadecimal digits produced
+undefined results.
+As of @value{PVERSION} 4.2, only two digits
+are processed.
@end quotation
@cindex @code{\} (backslash), @code{\/} escape sequence
@@ -6312,10 +6419,13 @@ used with it do not have to be named on the @command{awk} command line
* Field Separators:: The field separator and how to change it.
* Constant Size:: Reading constant width data.
* Splitting By Content:: Defining Fields By Content
+* Testing field creation:: Checking how @command{gawk} is splitting
+ records.
* Multiple Line:: Reading multiline records.
* Getline:: Reading files under explicit program control
using the @code{getline} function.
* Read Timeout:: Reading input with a timeout.
+* Retrying Input:: Retrying input after certain errors.
* Command-line directories:: What happens if you put a directory on the
command line.
* Input Summary:: Input summary.
@@ -6690,16 +6800,12 @@ Readfile} for another option.
@cindex fields
@cindex accessing fields
@cindex fields, examining
-@cindex POSIX @command{awk}, field separators and
-@cindex field separators, POSIX and
-@cindex separators, field, POSIX and
When @command{awk} reads an input record, the record is
automatically @dfn{parsed} or separated by the @command{awk} utility into chunks
called @dfn{fields}. By default, fields are separated by @dfn{whitespace},
like words in a line.
Whitespace in @command{awk} means any string of one or more spaces,
-TABs, or newlines;@footnote{In POSIX @command{awk}, newlines are not
-considered whitespace for separating fields.} other characters
+TABs, or newlines; other characters
that are considered whitespace by other languages
(such as formfeed, vertical tab, etc.) are @emph{not} considered
whitespace by @command{awk}.
@@ -7144,7 +7250,6 @@ can massage it first with a separate @command{awk} program.)
@node Default Field Splitting
@subsection Whitespace Normally Separates Fields
-@cindex newlines, as field separators
@cindex whitespace, as field separators
Fields are normally separated by whitespace sequences
(spaces, TABs, and newlines), not by single spaces. Two spaces in a row do not
@@ -7641,18 +7746,30 @@ feature of @command{gawk}. If you are a novice @command{awk} user,
you might want to skip it on the first reading.
@command{gawk} provides a facility for dealing with fixed-width fields
-with no distinctive field separator. For example, data of this nature
-arises in the input for old Fortran programs where numbers are run
-together, or in the output of programs that did not anticipate the use
-of their output as input for other programs.
-
-An example of the latter is a table where all the columns are lined up by
-the use of a variable number of spaces and @emph{empty fields are just
-spaces}. Clearly, @command{awk}'s normal field splitting based on @code{FS}
-does not work well in this case. Although a portable @command{awk} program
-can use a series of @code{substr()} calls on @code{$0}
-(@pxref{String Functions}),
-this is awkward and inefficient for a large number of fields.
+with no distinctive field separator. We discuss this feature in
+the following @value{SUBSECTION}s.
+
+@menu
+* Fixed width data:: Processing fixed-width data.
+* Skipping intervening:: Skipping intervening fields.
+* Allowing trailing data:: Capturing optional trailing data.
+* Fields with fixed data:: Field values with fixed-width data.
+@end menu
+
+@node Fixed width data
+@subsection Processing Fixed-Width Data
+
+An example of fixed-width data would be the input for old Fortran programs
+where numbers are run together, or the output of programs that did not
+anticipate the use of their output as input for other programs.
+
+An example of the latter is a table where all the columns are lined up
+by the use of a variable number of spaces and @emph{empty fields are
+just spaces}. Clearly, @command{awk}'s normal field splitting based
+on @code{FS} does not work well in this case. Although a portable
+@command{awk} program can use a series of @code{substr()} calls on
+@code{$0} (@pxref{String Functions}), this is awkward and inefficient
+for a large number of fields.
@cindex troubleshooting, fatal errors, field widths@comma{} specifying
@cindex @command{w} utility
@@ -7660,11 +7777,12 @@ this is awkward and inefficient for a large number of fields.
@cindex @command{gawk}, @code{FIELDWIDTHS} variable in
The splitting of an input record into fixed-width fields is specified by
assigning a string containing space-separated numbers to the built-in
-variable @code{FIELDWIDTHS}. Each number specifies the width of the field,
-@emph{including} columns between fields. If you want to ignore the columns
-between fields, you can specify the width as a separate field that is
-subsequently ignored.
-It is a fatal error to supply a field width that has a negative value.
+variable @code{FIELDWIDTHS}. Each number specifies the width of the
+field, @emph{including} columns between fields. If you want to ignore
+the columns between fields, you can specify the width as a separate
+field that is subsequently ignored. It is a fatal error to supply a
+field width that has a negative value.
+
The following data is the output of the Unix @command{w} utility. It is useful
to illustrate the use of @code{FIELDWIDTHS}:
@@ -7694,7 +7812,7 @@ NR > 2 @{
sub(/^ +/, "", idle) # strip leading spaces
if (idle == "")
idle = 0
- if (idle ~ /:/) @{
+ if (idle ~ /:/) @{ # hh:mm
split(idle, t, ":")
idle = t[1] * 60 + t[2]
@}
@@ -7733,30 +7851,90 @@ program for processing such data could use the @code{FIELDWIDTHS} feature
to simplify reading the data. (Of course, getting @command{gawk} to run on
a system with card readers is another story!)
-@cindex @command{gawk}, splitting fields and
-Assigning a value to @code{FS} causes @command{gawk} to use
-@code{FS} for field splitting again. Use @samp{FS = FS} to make this happen,
-without having to know the current value of @code{FS}.
-In order to tell which kind of field splitting is in effect,
-use @code{PROCINFO["FS"]}
-(@pxref{Auto-set}).
-The value is @code{"FS"} if regular field splitting is being used,
-or @code{"FIELDWIDTHS"} if fixed-width field splitting is being used:
+@node Skipping intervening
+@subsection Skipping Intervening Fields
+
+Starting in @value{PVERSION} 4.2, each field width may optionally be
+preceded by a colon-separated value specifying the number of characters
+to skip before the field starts. Thus, the preceding program could be
+rewritten to specify @code{FIELDWIDTHS} like so:
@example
-if (PROCINFO["FS"] == "FS")
- @var{regular field splitting} @dots{}
-else if (PROCINFO["FS"] == "FIELDWIDTHS")
- @var{fixed-width field splitting} @dots{}
-else
- @var{content-based field splitting} @dots{} @ii{(see next @value{SECTION})}
+BEGIN @{ FIELDWIDTHS = "8 1:5 4:7 6 1:6 1:6 2:33" @}
+@end example
+
+This strips away some of the white space separating the fields. With such
+a change, the program produces the following results:
+
+@example
+hzang ttyV3 50
+eklye ttyV5 0
+dportein ttyV6 107
+gierd ttyD3 1
+dave ttyD4 0
+brent ttyp0 286
+dave ttyq4 1296000
@end example
-This information is useful when writing a function
-that needs to temporarily change @code{FS} or @code{FIELDWIDTHS},
-read some records, and then restore the original settings
-(@pxref{Passwd Functions}
-for an example of such a function).
+@node Allowing trailing data
+@subsection Capturing Optional Trailing Data
+
+There are times when fixed-width data may be followed by additional data
+that has no fixed length. Such data may or may not be present, but if
+it is, it should be possible to get at it from an @command{awk} program.
+
+Starting with version 4.2, in order to provide a way to say ``anything
+else in the record after the defined fields,'' @command{gawk}
+allows you to add a final @samp{*} character to the value of
+@code{FIELDWIDTHS}. There can only be one such character, and it must
+be the final non-whitespace character in @code{FIELDWIDTHS}.
+For example:
+
+@example
+$ @kbd{cat fw.awk} @ii{Show the program}
+@print{} BEGIN @{ FIELDWIDTHS = "2 2 *" @}
+@print{} @{ print NF, $1, $2, $3 @}
+$ @kbd{cat fw.in} @ii{Show sample input}
+@print{} 1234abcdefghi
+$ @kbd{gawk -f fw.awk fw.in} @ii{Run the program}
+@print{} 3 12 34 abcdefghi
+@end example
+
+@node Fields with fixed data
+@subsection Field Values With Fixed-Width Data
+
+So far, so good. But what happens if there isn't as much data as there
+should be based on the contents of @code{FIELDWIDTHS}? Or, what happens
+if there is more data than expected?
+
+For many years, what happens in these cases was not well defined. Starting
+with version 4.2, the rules are as follows:
+
+@table @asis
+@item Enough data for some fields
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4"} and the
+input record is @samp{aabbb}. In this case, @code{NF} is set to two.
+
+@item Not enough data for a field
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4"} and the
+input record is @samp{aab}. In this case, @code{NF} is set to two and
+@code{$2} has the value @code{"b"}. The idea is that even though there
+aren't as many characters as were expected, there are some, so the data
+should be made available to the program.
+
+@item Too much data
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4"} and the
+input record is @samp{aabbbccccddd}. In this case, @code{NF} is set to
+three and the extra characters (@samp{ddd}) are ignored. If you want
+@command{gawk} to capture the extra characters, supply a final @samp{*}
+in the value of @code{FIELDWIDTHS}.
+
+@item Too much data, but with @samp{*} supplied
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4 *"} and the
+input record is @samp{aabbbccccddd}. In this case, @code{NF} is set to
+four, and @code{$4} has the value @code{"ddd"}.
+
+@end table
@node Splitting By Content
@section Defining Fields by Content
@@ -7857,8 +8035,6 @@ 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.
@quotation NOTE
Some programs export CSV data that contains embedded newlines between
@@ -7885,11 +8061,44 @@ 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.
-The mechanism used is based on which of the three
-variables---@code{FS}, @code{FIELDWIDTHS}, or @code{FPAT}---was
-last assigned to.
+
+@node Testing field creation
+@section Checking How @command{gawk} Is Splitting Records
+
+@cindex @command{gawk}, splitting fields and
+As we've seen, @command{gawk} provides three independent methods to split
+input records into fields. The mechanism used is based on which of the
+three variables---@code{FS}, @code{FIELDWIDTHS}, or @code{FPAT}---was
+last assigned to. In addition, an API input parser may choose to override
+the record parsing mechanism; please refer to @ref{Input Parsers} for
+further information about this feature.
+
+To restore normal field splitting after using @code{FIELDWIDTHS}
+and/or @code{FPAT}, simply assign a value to @code{FS}.
+You can use @samp{FS = FS} to do this,
+without having to know the current value of @code{FS}.
+
+In order to tell which kind of field splitting is in effect,
+use @code{PROCINFO["FS"]} (@pxref{Auto-set}).
+The value is @code{"FS"} if regular field splitting is being used,
+@code{"FIELDWIDTHS"} if fixed-width field splitting is being used,
+or @code{"FPAT"} if content-based field splitting is being used:
+
+@example
+if (PROCINFO["FS"] == "FS")
+ @var{regular field splitting} @dots{}
+else if (PROCINFO["FS"] == "FIELDWIDTHS")
+ @var{fixed-width field splitting} @dots{}
+else if (PROCINFO["FS"] == "FPAT")
+ @var{content-based field splitting}
+else
+ @var{API input parser field splitting} @dots{} @ii{(advanced feature)}
+@end example
+
+This information is useful when writing a function that needs to
+temporarily change @code{FS} or @code{FIELDWIDTHS}, read some records,
+and then restore the original settings (@pxref{Passwd Functions} for an
+example of such a function).
@node Multiple Line
@section Multiple-Line Records
@@ -8107,6 +8316,13 @@ a record, such as a file that cannot be opened, then @code{getline}
returns @minus{}1. In this case, @command{gawk} sets the variable
@code{ERRNO} to a string describing the error that occurred.
+If @code{ERRNO} indicates that the I/O operation may be
+retried, and @code{PROCINFO["@var{input}", "RETRY"]} is set,
+then @code{getline} returns @minus{}2
+instead of @minus{}1, and further calls to @code{getline}
+may be attempted. @xref{Retrying Input} for further information about
+this feature.
+
In the following examples, @var{command} stands for a string value that
represents a shell command.
@@ -8761,7 +8977,8 @@ on a per-command or per-connection basis.
the attempt to read from the underlying device may
succeed in a later attempt. This is a limitation, and it also
means that you cannot use this to multiplex input from
-two or more sources.
+two or more sources. @xref{Retrying Input} for a way to enable
+later I/O attempts to succeed.
Assigning a timeout value prevents read operations from
blocking indefinitely. But bear in mind that there are other ways
@@ -8771,6 +8988,36 @@ 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 Retrying Input
+@section Retrying Reads After Certain Input Errors
+@cindex retrying input
+
+@cindex differences in @command{awk} and @command{gawk}, retrying input
+This @value{SECTION} describes a feature that is specific to @command{gawk}.
+
+When @command{gawk} encounters an error while reading input, by
+default @code{getline} returns @minus{}1, and subsequent attempts to
+read from that file result in an end-of-file indication. However, you
+may optionally instruct @command{gawk} to allow I/O to be retried when
+certain errors are encountered by setting a special element in
+the @code{PROCINFO} array (@pxref{Auto-set}):
+
+@example
+PROCINFO["@var{input_name}", "RETRY"] = 1
+@end example
+
+When this element exists, @command{gawk} checks the value of the system
+(C language)
+@code{errno} variable when an I/O error occurs. If @code{errno} indicates
+a subsequent I/O attempt may succeed, @code{getline} instead returns
+@minus{}2 and
+further calls to @code{getline} may succeed. This applies to the @code{errno}
+values @code{EAGAIN}, @code{EWOULDBLOCK}, @code{EINTR}, or @code{ETIMEDOUT}.
+
+This feature is useful in conjunction with
+@code{PROCINFO["@var{input_name}", "READ_TIMEOUT"]} or situations where a file
+descriptor has been configured to behave in a non-blocking fashion.
+
@node Command-line directories
@section Directories on the Command Line
@cindex differences in @command{awk} and @command{gawk}, command-line directories
@@ -8932,6 +9179,7 @@ and discusses the @code{close()} built-in function.
@command{gawk} allows access to inherited file
descriptors.
* Close Files And Pipes:: Closing Input and Output Files and Pipes.
+* Nonfatal:: Enabling Nonfatal Output.
* Output Summary:: Output summary.
* Output Exercises:: Exercises.
@end menu
@@ -10358,17 +10606,26 @@ a system problem closing the file or process.
In these cases, @command{gawk} sets the predefined variable
@code{ERRNO} to a string describing the problem.
-In @command{gawk},
-when closing a pipe or coprocess (input or output),
-the return value is the exit status of the command.@footnote{
-This is a full 16-bit value as returned by the @code{wait()}
-system call. See the system manual pages for information on
-how to decode this value.}
-Otherwise, it is the return value from the system's @code{close()} or
-@code{fclose()} C functions when closing input or output
-files, respectively.
-This value is zero if the close succeeds, or @minus{}1 if
-it fails.
+In @command{gawk}, starting with @value{PVERSION} 4.2, when closing a pipe or
+coprocess (input or output), the return value is the exit status of the
+command, as described in @ref{table-close-pipe-return-values}.@footnote{Prior
+to @value{PVERSION} 4.2, the return value from closing a pipe or co-process
+was the full 16-bit exit value as defined by the @code{wait()} system
+call.} Otherwise, it is the return value from the system's @code{close()}
+or @code{fclose()} C functions when closing input or output files,
+respectively. This value is zero if the close succeeds, or @minus{}1
+if it fails.
+
+@float Table,table-close-pipe-return-values
+@caption{Return values from @code{close()} of a pipe}
+@multitable @columnfractions .40 .60
+@headitem Situation @tab Return value from @code{close()}
+@item Normal exit of command @tab Command's exit status
+@item Death by signal of command @tab 256 + number of murderous signal
+@item Death by signal of command with core dump @tab 512 + number of murderous signal
+@item Some kind of error @tab @minus{}1
+@end multitable
+@end float
The POSIX standard is very vague; it says that @code{close()}
returns zero on success and a nonzero value otherwise. In general,
@@ -10415,17 +10672,26 @@ a system problem closing the file or process.
In these cases, @command{gawk} sets the predefined variable
@code{ERRNO} to a string describing the problem.
-In @command{gawk},
-when closing a pipe or coprocess (input or output),
-the return value is the exit status of the command.@footnote{
-This is a full 16-bit value as returned by the @code{wait()}
-system call. See the system manual pages for information on
-how to decode this value.}
-Otherwise, it is the return value from the system's @code{close()} or
-@code{fclose()} C functions when closing input or output
-files, respectively.
-This value is zero if the close succeeds, or @minus{}1 if
-it fails.
+In @command{gawk}, starting with @value{PVERSION} 4.2, when closing a pipe or
+coprocess (input or output), the return value is the exit status of the
+command, as described in @ref{table-close-pipe-return-values}.@footnote{Prior
+to @value{PVERSION} 4.2, the return value from closing a pipe or co-process
+was the full 16-bit exit value as defined by the @code{wait()} system
+call.} Otherwise, it is the return value from the system's @code{close()}
+or @code{fclose()} C functions when closing input or output files,
+respectively. This value is zero if the close succeeds, or @minus{}1
+if it fails.
+
+@float Table,table-close-pipe-return-values
+@caption{Return values from @code{close()} of a pipe}
+@multitable @columnfractions .40 .60
+@headitem Situation @tab Return value from @code{close()}
+@item Normal exit of command @tab Command's exit status
+@item Death by signal of command @tab 256 + number of murderous signal
+@item Death by signal of command with core dump @tab 512 + number of murderous signal
+@item Some kind of error @tab @minus{}1
+@end multitable
+@end float
The POSIX standard is very vague; it says that @code{close()}
returns zero on success and a nonzero value otherwise. In general,
@@ -10437,6 +10703,70 @@ when closing a pipe.
@end cartouche
@end ifnotdocbook
+@node Nonfatal
+@section Enabling Nonfatal Output
+
+This @value{SECTION} describes a @command{gawk}-specific feature.
+
+In standard @command{awk}, output with @code{print} or @code{printf}
+to a nonexistent file, or some other I/O error (such as filling up the
+disk) is a fatal error.
+
+@example
+$ @kbd{gawk 'BEGIN @{ print "hi" > "/no/such/file" @}'}
+@error{} gawk: cmd. line:1: fatal: can't redirect to `/no/such/file' (No such file or directory)
+@end example
+
+@command{gawk} makes it possible to detect that an error has
+occurred, allowing you to possibly recover from the error, or
+at least print an error message of your choosing before exiting.
+You can do this in one of two ways:
+
+@itemize @bullet
+@item
+For all output files, by assigning any value to @code{PROCINFO["NONFATAL"]}.
+
+@item
+On a per-file basis, by assigning any value to
+@code{PROCINFO[@var{filename}, "NONFATAL"]}.
+Here, @var{filename} is the name of the file to which
+you wish output to be nonfatal.
+@end itemize
+
+Once you have enabled nonfatal output, you must check @code{ERRNO}
+after every relevant @code{print} or @code{printf} statement to
+see if something went wrong. It is also a good idea to initialize
+@code{ERRNO} to zero before attempting the output. For example:
+
+@example
+$ @kbd{gawk '}
+> @kbd{BEGIN @{}
+> @kbd{ PROCINFO["NONFATAL"] = 1}
+> @kbd{ ERRNO = 0}
+> @kbd{ print "hi" > "/no/such/file"}
+> @kbd{ if (ERRNO) @{}
+> @kbd{ print("Output failed:", ERRNO) > "/dev/stderr"}
+> @kbd{ exit 1}
+> @kbd{ @}}
+> @kbd{@}'}
+@error{} Output failed: No such file or directory
+@end example
+
+Here, @command{gawk} did not produce a fatal error; instead
+it let the @command{awk} program code detect the problem and handle it.
+
+This mechanism works also for standard output and standard error.
+For standard output, you may use @code{PROCINFO["-", "NONFATAL"]}
+or @code{PROCINFO["/dev/stdout", "NONFATAL"]}. For standard error, use
+@code{PROCINFO["/dev/stderr", "NONFATAL"]}.
+
+When attempting to open a TCP/IP socket (@pxref{TCP/IP Networking}),
+@command{gawk} tries multiple times. The @env{GAWK_SOCK_RETRIES}
+environment variable (@pxref{Other Environment Variables}) allows you to
+override @command{gawk}'s builtin default number of attempts. However,
+once nonfatal I/O is enabled for a given socket, @command{gawk} only
+retries once, relying on @command{awk}-level code to notice that there
+was a problem.
@node Output Summary
@section Summary
@@ -10466,6 +10796,12 @@ Use @code{close()} to close open file, pipe, and coprocess redirections.
For coprocesses, it is possible to close only one direction of the
communications.
+@item
+Normally errors with @code{print} or @code{printf} are fatal.
+@command{gawk} lets you make output errors be nonfatal either for
+all files or on a per-file basis. You must then check for errors
+after every relevant output statement.
+
@end itemize
@c EXCLUDE START
@@ -10613,7 +10949,7 @@ Just as @samp{11} in decimal is 1 times 10 plus 1, so
@samp{11} in octal is 1 times 8 plus 1. This equals 9 in decimal.
In hexadecimal, there are 16 digits. Because the everyday decimal
number system only has ten digits (@samp{0}--@samp{9}), the letters
-@samp{a} through @samp{f} are used to represent the rest.
+@samp{a} through @samp{f} represent the rest.
(Case in the letters is usually irrelevant; hexadecimal @samp{a} and @samp{A}
have the same value.)
Thus, @samp{11} in
@@ -10745,6 +11081,20 @@ but could be more complex expressions).
@node Using Constant Regexps
@subsection Using Regular Expression Constants
+Regular expression constants consist of text describing
+a regular expression enclosed in slashes (such as @code{/the +answer/}).
+This @value{SECTION} describes how such constants work in
+POSIX @command{awk} and @command{gawk}, and then goes on to describe
+@dfn{strongly typed regexp constants}, which are a @command{gawk} extension.
+
+@menu
+* Standard Regexp Constants:: Regexp constants in standard @command{awk}.
+* Strong Regexp Constants:: Strongly typed regexp constants.
+@end menu
+
+@node Standard Regexp Constants
+@subsubsection Standard Regular Expression Constants
+
@cindex dark corner, regexp constants
When used on the righthand side of the @samp{~} or @samp{!~}
operators, a regexp constant merely stands for the regexp that is to be
@@ -10852,6 +11202,90 @@ or not @code{$0} matches @code{/hi/}.
a parameter to a user-defined function, because passing a truth value in
this way is probably not what was intended.
+@node Strong Regexp Constants
+@subsubsection Strongly Typed Regexp Constants
+
+This @value{SECTION} describes a @command{gawk}-specific feature.
+
+As we saw in the previous @value{SECTION},
+regexp constants (@code{/@dots{}/}) hold a strange position in the
+@command{awk} language. In most contexts, they act like an expression:
+@samp{$0 ~ /@dots{}/}. In other contexts, they denote only a regexp to
+be matched. In no case are they really a ``first class citizen'' of the
+language. That is, you cannot define a scalar variable whose type is
+``regexp'' in the same sense that you can define a variable to be a
+number or a string:
+
+@example
+num = 42 @ii{Numeric variable}
+str = "hi" @ii{String variable}
+re = /foo/ @ii{Wrong!} re @ii{is the result of} $0 ~ /foo/
+@end example
+
+For a number of more advanced use cases,
+it would be nice to have regexp constants that
+are @dfn{strongly typed}; in other words, that denote a regexp useful
+for matching, and not an expression.
+
+@command{gawk} provides this feature. A strongly typed regexp constant
+looks almost like a regular regexp constant, except that it is preceded
+by an @samp{@@} sign:
+
+@example
+re = @@/foo/ @ii{Regexp variable}
+@end example
+
+Strongly typed regexp constants @emph{cannot} be used everywhere that a
+regular regexp constant can, because this would make the language even more
+confusing. Instead, you may use them only in certain contexts:
+
+@itemize @bullet
+@item
+On the righthand side of the @samp{~} and @samp{!~} operators: @samp{some_var ~ @@/foo/}
+(@pxref{Regexp Usage}).
+
+@item
+In the @code{case} part of a @code{switch} statement
+(@pxref{Switch Statement}).
+
+@item
+As an argument to one of the built-in functions that accept regexp constants:
+@code{gensub()},
+@code{gsub()},
+@code{match()},
+@code{patsplit()},
+@code{split()},
+and
+@code{sub()}
+(@pxref{String Functions}).
+
+@item
+As a parameter in a call to a user-defined function
+(@pxref{User-defined}).
+
+@item
+On the righthand side of an assignment to a variable: @samp{some_var = @@/foo/}.
+In this case, the type of @code{some_var} is regexp. Additionally, @code{some_var}
+can be used with @samp{~} and @samp{!~}, passed to one of the built-in functions
+listed above, or passed as a parameter to a user-defined function.
+@end itemize
+
+You may use the @code{typeof()} built-in function
+(@pxref{Type Functions})
+to determine if a variable or function parameter is
+a regexp variable.
+
+The true power of this feature comes from the ability to create variables that
+have regexp type. Such variables can be passed on to user-defined functions,
+without the confusing aspects of computed regular expressions created from
+strings or string constants. They may also be passed through indirect function
+calls (@pxref{Indirect Calls})
+and on to the built-in functions that accept regexp constants.
+
+When used in numeric conversions, strongly typed regexp variables convert
+to zero. When used in string conversions, they convert to the string
+value of the original regexp text.
+
@node Variables
@subsection Variables
@@ -12027,17 +12461,94 @@ compares variables.
@node Variable Typing
@subsubsection String Type versus Numeric Type
+Scalar objects in @command{awk} (variables, array elements, and fields)
+are @emph{dynamically} typed. This means their type can change as the
+program runs, from @dfn{untyped} before any use,@footnote{@command{gawk}
+calls this @dfn{unassigned}, as the following example shows.} to string
+or number, and then from string to number or number to string, as the
+program progresses. (@command{gawk} also provides regexp-typed scalars,
+but let's ignore that for now; @pxref{Strong Regexp Constants}.)
+
+You can't do much with untyped variables, other than tell that they
+are untyped. The following program tests @code{a} against @code{""}
+and @code{0}; the test succeeds when @code{a} has never been assigned
+a value. It also uses the built-in @code{typeof()} function
+(not presented yet; @pxref{Type Functions}) to show @code{a}'s type:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print (a == "" && a == 0 ?}
+> @kbd{"a is untyped" : "a has a type!") ; print typeof(a) @}'}
+@print{} a is untyped
+@print{} unassigned
+@end example
+
+A scalar has numeric type when assigned a numeric value,
+such as from a numeric constant, or from another scalar
+with numeric type:
+
+@example
+$ @kbd{gawk 'BEGIN @{ a = 42 ; print typeof(a)}
+> @kbd{b = a ; print typeof(b) @}'}
+number
+number
+@end example
+
+Similarly, a scalar has string type when assigned a string
+value, such as from a string constant, or from another scalar
+with string type:
+
+@example
+$ @kbd{gawk 'BEGIN @{ a = "forty two" ; print typeof(a)}
+> @kbd{b = a ; print typeof(b) @}'}
+string
+string
+@end example
+
+So far, this is all simple and straightforward. What happens, though,
+when @command{awk} has to process data from a user? Let's start with
+field data. What should the following command produce as output?
+
+@example
+echo hello | awk '@{ printf("%s %s < 42\n", $1,
+ ($1 < 42 ? "is" : "is not")) @}'
+@end example
+
+@noindent
+Since @samp{hello} is alphabetic data, @command{awk} can only do a string
+comparison. Internally, it converts @code{42} into @code{"42"} and compares
+the two string values @code{"hello"} and @code{"42"}. Here's the result:
+
+@example
+$ @kbd{echo hello | awk '@{ printf("%s %s < 42\n", $1,}
+> @kbd{ ($1 < 42 ? "is" : "is not")) @}'}
+@print{} hello is not < 42
+@end example
+
+However, what happens when data from a user @emph{looks like} a number?
+On the one hand, in reality, the input data consists of characters, not
+binary numeric
+values. But, on the other hand, the data looks numeric, and @command{awk}
+really ought to treat it as such. And indeed, it does:
+
+@example
+$ @kbd{echo 37 | awk '@{ printf("%s %s < 42\n", $1,}
+> @kbd{ ($1 < 42 ? "is" : "is not")) @}'}
+@print{} 37 is < 42
+@end example
+
+Here are the rules for when @command{awk}
+treats data as a number, and for when it treats data as a string.
+
@cindex numeric, strings
@cindex strings, numeric
@cindex POSIX @command{awk}, numeric strings and
-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 POSIX standard uses the term @dfn{numeric string} for input data that
+looks numeric. The @samp{37} in the previous example is a numeric string.
+So what is the type of a numeric string? Answer: numeric.
+The type of a variable is important because the types of two variables
+determine how they are compared.
+Variable typing follows these definitions and rules:
@itemize @value{BULLET}
@item
@@ -12052,7 +12563,9 @@ attribute.
Fields, @code{getline} input, @code{FILENAME}, @code{ARGV} elements,
@code{ENVIRON} elements, and the elements of an array created by
@code{match()}, @code{split()}, and @code{patsplit()} that are numeric
-strings have the @dfn{strnum} attribute. Otherwise, they have
+strings have the @dfn{strnum} attribute.@footnote{Thus, a POSIX
+numeric string and @command{gawk}'s strnum are the same thing.}
+Otherwise, they have
the @dfn{string} attribute. Uninitialized variables also have the
@dfn{strnum} attribute.
@@ -12126,7 +12639,7 @@ STRNUM &&string &numeric &numeric\cr
@end tex
@ifnottex
@ifnotdocbook
-@display
+@verbatim
+----------------------------------------------
| STRING NUMERIC STRNUM
--------+----------------------------------------------
@@ -12137,7 +12650,7 @@ NUMERIC | string numeric numeric
|
STRNUM | string numeric numeric
--------+----------------------------------------------
-@end display
+@end verbatim
@end ifnotdocbook
@end ifnottex
@docbook
@@ -12196,10 +12709,14 @@ purposes.
In short, when one operand is a ``pure'' string, such as a string
constant, then a string comparison is performed. Otherwise, a
numeric comparison is performed.
+(The primary difference between a number and a strnum is that
+for strnums @command{gawk} preserves the original string value that
+the scalar had when it came in.)
+
+This point bears additional emphasis:
+Input that looks numeric @emph{is} numeric.
+All other input is treated as strings.
-This point bears additional emphasis: All user input is made of characters,
-and so is first and foremost of string type; input strings
-that look numeric are additionally given the strnum attribute.
Thus, the six-character input string @w{@samp{ +3.14}} receives the
strnum attribute. In contrast, the eight characters
@w{@code{" +3.14"}} appearing in program text comprise a string constant.
@@ -12226,6 +12743,14 @@ $ @kbd{echo ' +3.14' | awk '@{ print($1 == 3.14) @}'} @ii{True}
@print{} 1
@end example
+You can see the type of an input field (or other user input)
+using @code{typeof()}:
+
+@example
+$ @kbd{echo hello 37 | gawk '@{ print typeof($1), typeof($2) @}'}
+@print{} string strnum
+@end example
+
@node Comparison Operators
@subsubsection Comparison Operators
@@ -12385,19 +12910,19 @@ One special place where @code{/foo/} is @emph{not} an abbreviation for
where this is discussed in more detail.
@node POSIX String Comparison
-@subsubsection String Comparison with POSIX Rules
+@subsubsection String Comparison Based on Locale Collating Order
-The POSIX standard says that string comparison is performed based
-on the locale's @dfn{collating order}. This is the order in which
-characters sort, as defined by the locale (for more discussion,
-@pxref{Locales}). This order is usually very different
-from the results obtained when doing straight character-by-character
-comparison.@footnote{Technically, string comparison is supposed
-to behave the same way as if the strings were compared with the C
-@code{strcoll()} function.}
+The POSIX standard used to say that all string comparisons are
+performed based on the locale's @dfn{collating order}. This
+is the order in which characters sort, as defined by the locale
+(for more discussion, @pxref{Locales}). This order is usually very
+different from the results obtained when doing straight byte-by-byte
+comparison.@footnote{Technically, string comparison is supposed to behave
+the same way as if the strings were compared with the C @code{strcoll()}
+function.}
Because this behavior differs considerably from existing practice,
-@command{gawk} only implements it when in POSIX mode (@pxref{Options}).
+@command{gawk} only implemented it when in POSIX mode (@pxref{Options}).
Here is an example to illustrate the difference, in an @code{en_US.UTF-8}
locale:
@@ -12410,6 +12935,26 @@ $ @kbd{gawk --posix 'BEGIN @{ printf("ABC < abc = %s\n",}
@print{} ABC < abc = FALSE
@end example
+Fortunately, as of August 2016, comparison based on locale
+collating order is no longer required for the @code{==} and @code{!=}
+operators.@footnote{See @uref{http://austingroupbugs.net/view.php?id=1070,
+the Austin Group website}.} However, comparison based on locales is still
+required for @code{<}, @code{<=}, @code{>}, and @code{>=}. POSIX thus
+recommends as follows:
+
+@quotation
+Since the @code{==} operator checks whether strings are identical,
+not whether they collate equally, applications needing to check whether
+strings collate equally can use:
+
+@example
+a <= b && a >= b
+@end example
+@end quotation
+
+As of @value{PVERSION} 4.2, @command{gawk} continues to use locale
+collating order for @code{<}, @code{<=}, @code{>}, and @code{>=} only
+in POSIX mode.
@node Boolean Ops
@subsection Boolean Expressions
@@ -14539,6 +15084,9 @@ Its default value is @code{"%.6g"}.
@item FIELDWIDTHS #
A space-separated list of columns that tells @command{gawk}
how to split input with fixed columnar boundaries.
+Starting in @value{PVERSION} 4.2, each field width may optionally be
+preceded by a colon-separated value specifying the number of characters to skip
+before the field starts.
Assigning a value to @code{FIELDWIDTHS}
overrides the use of @code{FS} and @code{FPAT} for field splitting.
@xref{Constant Size} for more information.
@@ -14569,12 +15117,11 @@ specify the behavior when @code{FS} is the null string.
Nonetheless, some other versions of @command{awk} also treat
@code{""} specially.)
-@cindex POSIX @command{awk}, @code{FS} variable and
The default value is @w{@code{" "}}, a string consisting of a single
-space. As a special exception, this value means that any
-sequence of spaces, TABs, and/or newlines is a single separator.@footnote{In
-POSIX @command{awk}, newline does not count as whitespace.} It also causes
-spaces, TABs, and newlines at the beginning and end of a record to be ignored.
+space. As a special exception, this value means that any sequence of
+spaces, TABs, and/or newlines is a single separator. It also causes
+spaces, TABs, and newlines at the beginning and end of a record to
+be ignored.
You can set the value of @code{FS} on the command line using the
@option{-F} option:
@@ -14798,10 +15345,24 @@ opens the next file.
An associative array containing the values of the environment. The array
indices are the environment variable names; the elements are the values of
the particular environment variables. For example,
-@code{ENVIRON["HOME"]} might be @code{"/home/arnold"}. Changing this array
-does not affect the environment passed on to any programs that
-@command{awk} may spawn via redirection or the @code{system()} function.
-(In a future version of @command{gawk}, it may do so.)
+@code{ENVIRON["HOME"]} might be @code{/home/arnold}.
+
+For POSIX @command{awk}, changing this array does not affect the
+environment passed on to any programs that @command{awk} may spawn via
+redirection or the @code{system()} function.
+
+However, beginning with @value{PVERSION} 4.2, if not in POSIX
+compatibility mode, @command{gawk} does update its own environment when
+@code{ENVIRON} is changed, thus changing the environment seen by programs
+that it creates. You should therefore be especially careful if you
+modify @code{ENVIRON["PATH"]}, which is the search path for finding
+executable programs.
+
+This can also affect the running @command{gawk} program, since some of the
+built-in functions may pay attention to certain environment variables.
+The most notable instance of this is @code{mktime()} (@pxref{Time
+Functions}), which pays attention the value of the @env{TZ} environment
+variable on many systems.
Some operating systems may not have environment variables.
On such systems, the @code{ENVIRON} array is empty (except for
@@ -14835,6 +15396,11 @@ value to be meaningful when an I/O operation returns a failure value,
such as @code{getline} returning @minus{}1. You are, of course, free
to clear it yourself before doing an I/O operation.
+If the value of @code{ERRNO} corresponds to a system error in the C
+@code{errno} variable, then @code{PROCINFO["errno"]} will be set to the value
+of @code{errno}. For non-system errors, @code{PROCINFO["errno"]} will
+be zero.
+
@cindex @code{FILENAME} variable
@cindex dark corner, @code{FILENAME} variable
@item @code{FILENAME}
@@ -14899,10 +15465,35 @@ The following elements (listed alphabetically)
are guaranteed to be available:
@table @code
+@item PROCINFO["argv"]
+@cindex command line arguments, @code{PROCINFO["argv"}
+The @code{PROCINFO["argv"]} array contains all of the command-line arguments
+(after glob expansion and redirection processing on platforms where that must
+be done manually by the program) with subscripts ranging from 0 through
+@code{argc} @minus{} 1. For example, @code{PROCINFO["argv"][0]} will contain
+the name by which @command{gawk} was invoked. Here is an example of how this
+feature may be used:
+
+@example
+gawk '
+BEGIN @{
+ for (i = 0; i < length(PROCINFO["argv"]); i++)
+ print i, PROCINFO["argv"][i]
+@}'
+@end example
+
+Please note that this differs from the standard @code{ARGV} array which does
+not include command-line arguments that have already been processed by
+@command{gawk} (@pxref{ARGC and ARGV}).
+
@cindex effective group ID of @command{gawk} user
@item PROCINFO["egid"]
The value of the @code{getegid()} system call.
+@item PROCINFO["errno"]
+The value of the C @code{errno} variable when @code{ERRNO} is set to
+the associated error message.
+
@item PROCINFO["euid"]
@cindex effective user ID of @command{gawk} user
The value of the @code{geteuid()} system call.
@@ -14911,7 +15502,8 @@ The value of the @code{geteuid()} system call.
This is
@code{"FS"} if field splitting with @code{FS} is in effect,
@code{"FIELDWIDTHS"} if field splitting with @code{FIELDWIDTHS} is in effect,
-or @code{"FPAT"} if field matching with @code{FPAT} is in effect.
+@code{"FPAT"} if field matching with @code{FPAT} is in effect,
+or @code{"API"} if field splitting is controlled by an API input parser.
@item PROCINFO["gid"]
@cindex group ID of @command{gawk} user
@@ -15026,6 +15618,14 @@ to test for these elements
The following elements allow you to change @command{gawk}'s behavior:
@table @code
+@item PROCINFO["NONFATAL"]
+If this element exists, then I/O errors for all output redirections become nonfatal.
+@xref{Nonfatal}.
+
+@item PROCINFO["@var{output_name}", "NONFATAL"]
+Make output errors for @var{output_name} be nonfatal.
+@xref{Nonfatal}.
+
@item PROCINFO["@var{command}", "pty"]
For two-way communication to @var{command}, use a pseudo-tty instead
of setting up a two-way pipe.
@@ -16966,6 +17566,27 @@ truncated toward zero.
For example, @code{int(3)} is 3, @code{int(3.9)} is 3, @code{int(-3.9)}
is @minus{}3, and @code{int(-3)} is @minus{}3 as well.
+@item @code{intdiv(@var{numerator}, @var{denominator}, @var{result})}
+@cindexawkfunc{intdiv}
+@cindex intdiv
+Perform integer division, similar to the standard C @code{div()} function.
+First, truncate @code{numerator} and @code{denominator}
+towards zero, creating integer values. Clear the @code{result}
+array, and then set @code{result["quotient"]} to the result of
+@samp{numerator / denominator}, truncated towards zero to an integer,
+and set @code{result["remainder"]} to the result of @samp{numerator %
+denominator}, truncated towards zero to an integer.
+Attempting division by zero causes a fatal error.
+The function returns zero upon success, and @minus{}1 upon error.
+
+This function is
+primarily intended for use with arbitrary length integers; it avoids
+creating MPFR arbitrary precision floating-point values (@pxref{Arbitrary
+Precision Integers}).
+
+This function is a @code{gawk} extension. It is not available in
+compatibility mode (@pxref{Options}).
+
@item @code{log(@var{x})}
@cindexawkfunc{log}
@cindex logarithm
@@ -17485,7 +18106,7 @@ using a third argument is a fatal error.
@cindexgawkfunc{patsplit}
@cindex split string into array
Divide
-@var{string} into pieces defined by @var{fieldpat}
+@var{string} into pieces (or ``fields'') defined by @var{fieldpat}
and store the pieces in @var{array} and the separator strings in the
@var{seps} array. The first piece is stored in
@code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so
@@ -17496,9 +18117,11 @@ It may be either a regexp constant or a string.
If @var{fieldpat} is omitted, the value of @code{FPAT} is used.
@code{patsplit()} returns the number of elements created.
@code{@var{seps}[@var{i}]} is
-the separator string
-between @code{@var{array}[@var{i}]} and @code{@var{array}[@var{i}+1]}.
-Any leading separator will be in @code{@var{seps}[0]}.
+the possibly null separator string
+after @code{@var{array}[@var{i}]}.
+The possibly null leading separator will be in @code{@var{seps}[0]}.
+So a non-null @var{string} with @var{n} fields will have @var{n+1} separators.
+A null @var{string} will not have neither fields nor separators.
The @code{patsplit()} function splits strings into pieces in a
manner similar to the way input lines are split into fields using @code{FPAT}
@@ -18612,7 +19235,7 @@ Optional parameters are enclosed in square brackets ([ ]):
@c @asis for docbook
@table @asis
-@item @code{mktime(@var{datespec})}
+@item @code{mktime(@var{datespec}} [@code{, @var{utc-flag}} ]@code{)}
@cindexgawkfunc{mktime}
@cindex generate time values
Turn @var{datespec} into a timestamp in the same form
@@ -18631,7 +19254,9 @@ The values of these numbers need not be within the ranges specified;
for example, an hour of @minus{}1 means 1 hour before midnight.
The origin-zero Gregorian calendar is assumed, with year 0 preceding
year 1 and year @minus{}1 preceding year 0.
-The time is assumed to be in the local time zone.
+If @var{utc-flag} is present and is either nonzero or non-null, the time
+is assumed to be in the UTC time zone; otherwise, the
+time is assumed to be in the local time zone.
If the daylight-savings flag is positive, the time is assumed to be
daylight savings time; if zero, the time is assumed to be standard
time; and if negative (the default), @code{mktime()} attempts to determine
@@ -19131,12 +19756,12 @@ Return the value of @var{val}, shifted right by @var{count} bits.
Return the bitwise XOR of the arguments. There must be at least two.
@end table
-For all of these functions, first the double-precision floating-point value is
-converted to the widest C unsigned integer type, then the bitwise operation is
-performed. If the result cannot be represented exactly as a C @code{double},
-leading nonzero bits are removed one by one until it can be represented
-exactly. The result is then converted back into a C @code{double}. (If
-you don't understand this paragraph, don't worry about it.)
+@quotation CAUTION
+Beginning with @command{gawk} @value{PVERSION} 4.2, negative
+operands are not allowed for any of these functions. A negative
+operand produces a fatal error. See the sidebar
+``Beware The Smoke and Mirrors!'' for more information as to why.
+@end quotation
Here is a user-defined function (@pxref{User-defined})
that illustrates the use of these functions:
@@ -19241,19 +19866,196 @@ decimal and octal values for the same numbers
and then demonstrates the
results of the @code{compl()}, @code{lshift()}, and @code{rshift()} functions.
+@cindex sidebar, Beware The Smoke and Mirrors!
+@ifdocbook
+@docbook
+<sidebar><title>Beware The Smoke and Mirrors!</title>
+@end docbook
+
+
+It other languages, bitwise operations are performed on integer values,
+not floating-point values. As a general statement, such operations work
+best when performed on unsigned integers.
+
+@command{gawk} attempts to treat the arguments to the bitwise functions
+as unsigned integers. For this reason, negative arguments produce a
+fatal error.
+
+In normal operation, for all of these functions, first the
+double-precision floating-point value is converted to the widest C
+unsigned integer type, then the bitwise operation is performed. If the
+result cannot be represented exactly as a C @code{double}, leading
+nonzero bits are removed one by one until it can be represented exactly.
+The result is then converted back into a C @code{double}.@footnote{If you don't
+understand this paragraph, the upshot is that @command{gawk} can only
+store a particular range of integer values; numbers outside that range
+are reduced to fit within the range.}
+
+However, when using arbitrary precision arithmetic with the @option{-M}
+option (@pxref{Arbitrary Precision Arithmetic}), the results may differ.
+This is particularly noticeable with the @code{compl()} function:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print compl(42) @}'}
+@print{} 9007199254740949
+$ @kbd{gawk -M 'BEGIN @{ print compl(42) @}'}
+@print{} -43
+@end example
+
+What's going on becomes clear when printing the results
+in hexadecimal:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0x1fffffffffffd5
+$ @kbd{gawk -M 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0xffffffffffffffd5
+@end example
+
+When using the @option{-M} option, under the hood, @command{gawk} uses
+GNU MP arbitrary precision integers which have at least 64 bits of precision.
+When not using @option{-M}, @command{gawk} stores integral values in
+regular double-precision floating point, which only maintain 53 bits of
+precision. Furthermore, the GNU MP library treats (or at least seems to treat)
+the leading bit as a sign bit; thus the result with @option{-M} in this case is
+a negative number.
+
+In short, using @command{gawk} for any but the simplest kind of bitwise
+operations is probably a bad idea; caveat emptor!
+
+
+@docbook
+</sidebar>
+@end docbook
+@end ifdocbook
+
+@ifnotdocbook
+@cartouche
+@center @b{Beware The Smoke and Mirrors!}
+
+
+
+It other languages, bitwise operations are performed on integer values,
+not floating-point values. As a general statement, such operations work
+best when performed on unsigned integers.
+
+@command{gawk} attempts to treat the arguments to the bitwise functions
+as unsigned integers. For this reason, negative arguments produce a
+fatal error.
+
+In normal operation, for all of these functions, first the
+double-precision floating-point value is converted to the widest C
+unsigned integer type, then the bitwise operation is performed. If the
+result cannot be represented exactly as a C @code{double}, leading
+nonzero bits are removed one by one until it can be represented exactly.
+The result is then converted back into a C @code{double}.@footnote{If you don't
+understand this paragraph, the upshot is that @command{gawk} can only
+store a particular range of integer values; numbers outside that range
+are reduced to fit within the range.}
+
+However, when using arbitrary precision arithmetic with the @option{-M}
+option (@pxref{Arbitrary Precision Arithmetic}), the results may differ.
+This is particularly noticeable with the @code{compl()} function:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print compl(42) @}'}
+@print{} 9007199254740949
+$ @kbd{gawk -M 'BEGIN @{ print compl(42) @}'}
+@print{} -43
+@end example
+
+What's going on becomes clear when printing the results
+in hexadecimal:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0x1fffffffffffd5
+$ @kbd{gawk -M 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0xffffffffffffffd5
+@end example
+
+When using the @option{-M} option, under the hood, @command{gawk} uses
+GNU MP arbitrary precision integers which have at least 64 bits of precision.
+When not using @option{-M}, @command{gawk} stores integral values in
+regular double-precision floating point, which only maintain 53 bits of
+precision. Furthermore, the GNU MP library treats (or at least seems to treat)
+the leading bit as a sign bit; thus the result with @option{-M} in this case is
+a negative number.
+
+In short, using @command{gawk} for any but the simplest kind of bitwise
+operations is probably a bad idea; caveat emptor!
+
+@end cartouche
+@end ifnotdocbook
+
@node Type Functions
@subsection Getting Type Information
-@command{gawk} provides a single function that lets you distinguish
-an array from a scalar variable. This is necessary for writing code
+@command{gawk} provides two functions that let you distinguish
+the type of a variable.
+This is necessary for writing code
that traverses every element of an array of arrays
-(@pxref{Arrays of Arrays}).
+(@pxref{Arrays of Arrays}), and in other contexts.
@table @code
@cindexgawkfunc{isarray}
@cindex scalar or array
@item isarray(@var{x})
Return a true value if @var{x} is an array. Otherwise, return false.
+
+@cindexgawkfunc{typeof}
+@cindex variable type
+@cindex type, of variable
+@item typeof(@var{x})
+Return one of the following strings, depending upon the type of @var{x}:
+
+@c nested table
+@table @code
+@item "array"
+@var{x} is an array.
+
+@item "regexp"
+@var{x} is a strongly typed regexp (@pxref{Strong Regexp Constants}).
+
+@item "number"
+@var{x} is a number.
+
+@item "string"
+@var{x} is a string.
+
+@item "strnum"
+@var{x} is a number that started life as user input, such as a field or
+the result of calling @code{split()}. (I.e., @var{x} has the strnum
+attribute; @pxref{Variable Typing}.)
+
+@item "unassigned"
+@var{x} is a scalar variable that has not been assigned a value yet.
+For example:
+
+@example
+BEGIN @{
+ # creates a[1] but it has no assigned value
+ a[1]
+ print typeof(a[1]) # unassigned
+@}
+@end example
+
+@item "untyped"
+@var{x} has not yet been used yet at all; it can become a scalar or an
+array.
+For example:
+
+@example
+BEGIN @{
+ print typeof(x) # x never used --> untyped
+ mk_arr(x)
+ print typeof(x) # x now an array --> array
+@}
+
+function mk_arr(a) @{ a[1] = 1 @}
+@end example
+
+@end table
@end table
@code{isarray()} is meant for use in two circumstances. The first is when
@@ -19271,6 +20073,14 @@ that has not been previously used to @code{isarray()}, @command{gawk}
ends up turning it into a scalar.
@end quotation
+The @code{typeof()} function is general; it allows you to determine
+if a variable or function parameter is a scalar, an array, or a strongly
+typed regexp.
+
+@code{isarray()} is deprecated; you should use @code{typeof()} instead.
+You should replace any existing uses of @samp{isarray(var)} in your
+code with @samp{typeof(var) == "array"}.
+
@node I18N Functions
@subsection String-Translation Functions
@cindex @command{gawk}, string-translation functions
@@ -27531,9 +28341,16 @@ your program to hang. (Thus, this particular feature is of much less
use in practice than being able to close the @code{"to"} end.)
@quotation CAUTION
-It is a fatal error to write to the @code{"to"} end of a two-way
-pipe which has been closed. It is also a fatal error to read
+Normally,
+it is a fatal error to write to the @code{"to"} end of a two-way
+pipe which has been closed, and it is also a fatal error to read
from the @code{"from"} end of a two-way pipe that has been closed.
+
+You may set @code{PROCINFO["@var{command}", "NONFATAL"]} to
+make such operations become nonfatal. If you do so, you then need
+to check @code{ERRNO} after each @code{print}, @code{printf},
+or @code{getline}.
+@xref{Nonfatal}, for more information.
@end quotation
@cindex @command{gawk}, @code{PROCINFO} array in
@@ -27917,8 +28734,7 @@ The profiled version of your program may not look exactly like what you
typed when you wrote it. This is because @command{gawk} creates the
profiled version by ``pretty-printing'' its internal representation of
the program. The advantage to this is that @command{gawk} can produce
-a standard representation. The disadvantage is that all source code
-comments are lost.
+a standard representation.
Also, things such as:
@example
@@ -28012,10 +28828,39 @@ When called this way, @command{gawk} ``pretty-prints'' the program into
@file{awkprof.out}, without any execution counts.
@quotation NOTE
-The @option{--pretty-print} option still runs your program.
-This will change in the next major release.
+Once upon a time, the @option{--pretty-print} option would also run
+your program. This is is no longer the case.
@end quotation
+There is a significant difference between the output created when
+profiling, and that created when pretty-printing. Pretty-printed output
+preserves the original comments that were in the program, although their
+placement may not correspond exactly to their original locations in the
+source code.@footnote{@command{gawk} does the best it can to preserve
+the distinction between comments at the end of a statement and comments
+on lines by themselves. Due to implementation constraints, it does not
+always do so correctly, particularly for @code{switch} statements. The
+@command{gawk} maintainers hope to improve this in a subsequent
+release.}
+
+However, as a deliberate design decision, profiling output @emph{omits}
+the original program's comments. This allows you to focus on the
+execution count data and helps you avoid the temptation to use the
+profiler for pretty-printing.
+
+Additionally, pretty-printed output does not have the leading indentation
+that the profiling output does. This makes it easy to pretty-print your
+code once development is completed, and then use the result as the final
+version of your program.
+
+Because the internal representation of your program is formatted to
+recreate an @command{awk} program, profiling and pretty-printing
+automatically disable @command{gawk}'s default optimizations.
+
+Pretty printing also preserves the original format of numeric
+constants; if you used an octal or hexadecimal value in your source
+code, it will appear that way in the output.
+
@node Advanced Features Summary
@section Summary
@@ -28056,8 +28901,7 @@ you tune them more easily. Sending the @code{USR1} signal while profiling cause
@command{gawk} to dump the profile and keep going, including a function call stack.
@item
-You can also just ``pretty-print'' the program. This currently also runs
-the program, but that will change in the next major release.
+You can also just ``pretty-print'' the program.
@end itemize
@@ -30250,6 +31094,68 @@ The @command{gawk} debugger only accepts source code supplied with the @option{-
@end itemize
@ignore
+@c 11/2016: This no longer applies after all the type cleanup work that's been done.
+One other point is worth discussing. Conventional debuggers run in a
+separate process (and thus address space) from the programs that they
+debug (the @dfn{debuggee}, if you will).
+
+The @command{gawk} debugger is different; it is an integrated part
+of @command{gawk} itself. This makes it possible, in rare cases,
+for @command{gawk} to become an excellent demonstrator of Heisenberg
+Uncertainty physics, where the mere act of observing something can change
+it. Consider the following:@footnote{Thanks to Hermann Peifer for
+this example.}
+
+@example
+$ @kbd{cat test.awk}
+@print{} @{ print typeof($1), typeof($2) @}
+$ @kbd{cat test.data}
+@print{} abc 123
+$ @kbd{gawk -f test.awk test.data}
+@print{} strnum strnum
+@end example
+
+This is all as expected: field data has the STRNUM attribute
+(@pxref{Variable Typing}). Now watch what happens when we run
+this program under the debugger:
+
+@example
+$ @kbd{gawk -D -f test.awk test.data}
+gawk> @kbd{w $1} @ii{Set watchpoint on} $1
+@print{} Watchpoint 1: $1
+gawk> @kbd{w $2} @ii{Set watchpoint on} $2
+@print{} Watchpoint 2: $2
+gawk> @kbd{r} @ii{Start the program}
+@print{} Starting program:
+@print{} Stopping in Rule ...
+@print{} Watchpoint 1: $1 @ii{Watchpoint fires}
+@print{} Old value: ""
+@print{} New value: "abc"
+@print{} main() at `test.awk':1
+@print{} 1 @{ print typeof($1), typeof($2) @}
+gawk> @kbd{n} @ii{Keep going @dots{}}
+@print{} Watchpoint 2: $2 @ii{Watchpoint fires}
+@print{} Old value: ""
+@print{} New value: "123"
+@print{} main() at `test.awk':1
+@print{} 1 @{ print typeof($1), typeof($2) @}
+gawk> @kbd{n} @ii{Get result from} typeof()
+@print{} strnum number @ii{Result for} $2 @ii{isn't right}
+@print{} Program exited normally with exit value: 0
+gawk> @kbd{quit}
+@end example
+
+In this case, the act of comparing the new value of @code{$2}
+with the old one caused @command{gawk} to evaluate it and determine that it
+is indeed a number, and this is reflected in the result of
+@code{typeof()}.
+
+Cases like this where the debugger is not transparent to the program's
+execution should be rare. If you encounter one, please report it
+(@pxref{Bugs}).
+@end ignore
+
+@ignore
Look forward to a future release when these and other missing features may
be added, and of course feel free to try to add them yourself!
@end ignore
@@ -30285,6 +31191,10 @@ If the GNU Readline library is available when @command{gawk} is
compiled, it is used by the debugger to provide command-line history
and editing.
+@item
+Usually, the debugger does not not affect the
+program being debugged, but occasionally it can.
+
@end itemize
@node Arbitrary Precision Arithmetic
@@ -30317,6 +31227,7 @@ this is the place to be.
* FP Math Caution:: Things to know.
* Arbitrary Precision Integers:: Arbitrary Precision Integer Arithmetic with
@command{gawk}.
+* Checking for MPFR:: How to check if MPFR is available.
* POSIX Floating Point Problems:: Standards Versus Existing Practice.
* Floating point summary:: Summary of floating point discussion.
@end menu
@@ -31102,6 +32013,174 @@ to just use the following:
gawk -M 'BEGIN @{ n = 13; print n % 2 @}'
@end example
+When dividing two arbitrary precision integers with either
+@samp{/} or @samp{%}, the result is typically an arbitrary
+precision floating point value (unless the denominator evenly
+divides into the numerator). In order to do integer division
+or remainder with arbitrary precision integers, use the built-in
+@code{intdiv()} function (@pxref{Numeric Functions}).
+
+You can simulate the @code{intdiv()} function in standard @command{awk}
+using this user-defined function:
+
+@example
+@c file eg/lib/intdiv.awk
+# intdiv --- do integer division
+
+@c endfile
+@ignore
+@c file eg/lib/intdiv.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# July, 2014
+#
+# Name changed from div() to intdiv()
+# April, 2015
+
+@c endfile
+
+@end ignore
+@c file eg/lib/intdiv.awk
+function intdiv(numerator, denominator, result)
+@{
+ split("", result)
+
+ numerator = int(numerator)
+ denominator = int(denominator)
+ result["quotient"] = int(numerator / denominator)
+ result["remainder"] = int(numerator % denominator)
+
+ return 0.0
+@}
+@c endfile
+@end example
+
+The following example program, contributed by Katie Wasserman,
+uses @code{intdiv()} to
+compute the digits of @value{PI} to as many places as you
+choose to set:
+
+@example
+@c file eg/prog/pi.awk
+# pi.awk --- compute the digits of pi
+@c endfile
+@c endfile
+@ignore
+@c file eg/prog/pi.awk
+#
+# Katie Wasserman, katie@@wass.net
+# August 2014
+@c endfile
+@end ignore
+@c file eg/prog/pi.awk
+
+BEGIN @{
+ digits = 100000
+ two = 2 * 10 ^ digits
+ pi = two
+ for (m = digits * 4; m > 0; --m) @{
+ d = m * 2 + 1
+ x = pi * m
+ intdiv(x, d, result)
+ pi = result["quotient"]
+ pi = pi + two
+ @}
+ print pi
+@}
+@c endfile
+@end example
+
+@ignore
+Date: Wed, 20 Aug 2014 10:19:11 -0400
+To: arnold@skeeve.com
+From: Katherine Wasserman <katie@wass.net>
+Subject: Re: computation of digits of pi?
+
+Arnold,
+
+>The program that you sent to compute the digits of pi using div(). Is
+>that some standard algorithm that every math student knows? If so,
+>what's it called?
+
+It's not that well known but it's not that obscure either
+
+It's Euler's modification to Newton's method for calculating pi.
+
+Take a look at lines (23) - (25) here: http://mathworld.wolfram.com/PiFormulas.htm
+
+The algorithm I wrote simply expands the multiply by 2 and works from the innermost expression outwards. I used this to program HP calculators because it's quite easy to modify for tiny memory devices with smallish word sizes.
+
+http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899
+
+-Katie
+@end ignore
+
+When asked about the algorithm used, Katie replied:
+
+@quotation
+It's not that well known but it's not that obscure either.
+It's Euler's modification to Newton's method for calculating pi.
+Take a look at lines (23) - (25) here: @uref{http://mathworld.wolfram.com/PiFormulas.html}.
+
+The algorithm I wrote simply expands the multiply by 2 and works from
+the innermost expression outwards. I used this to program HP calculators
+because it's quite easy to modify for tiny memory devices with smallish
+word sizes. See
+@uref{http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899}.
+@end quotation
+
+@node Checking for MPFR
+@section How To Check If MPFR Is Available
+
+@cindex MPFR, checking availability of
+@cindex checking for MPFR
+Occasionally, you might like to be able to check if @command{gawk}
+was invoked with the @option{-M} option, enabling arbitrary-precision
+arithmetic. You can do so with the following function, contributed
+by Andrew Schorr:
+
+@example
+@c file eg/lib/have_mpfr.awk
+# adequate_math_precision --- return true if we have enough bits
+@c endfile
+@ignore
+@c file eg/lib/have_mpfr.awk
+#
+# Andrew Schorr, aschorr@@telemetry-investments.com, Public Domain
+# May 2017
+@c endfile
+@end ignore
+@c file eg/lib/have_mpfr.awk
+
+function adequate_math_precision(n)
+@{
+ return (1 != (1+(1/(2^(n-1)))))
+@}
+@c endfile
+@end example
+
+Here is code that invokes the function in order to check
+if arbitrary-precision arithmetic is available:
+
+@example
+BEGIN @{
+ # How many bits of mantissa precision are required
+ # for this program to function properly?
+ fpbits = 123
+
+ # We hope that we were invoked with MPFR enabled. If so, the
+ # following statement should configure calculations to our desired
+ # precision.
+ PREC = fpbits
+
+ if (! adequate_math_precision(fpbits)) @{
+ print("Error: insufficient computation precision available.\n" \
+ "Try again with the -M argument?") > "/dev/stderr"
+ exit 1
+ @}
+@}
+@end example
+
@node POSIX Floating Point Problems
@section Standards Versus Existing Practice
@@ -31501,8 +32580,11 @@ This (rather large) @value{SECTION} describes the API in detail.
* Symbol Table Access:: Functions for accessing global
variables.
* Array Manipulation:: Functions for working with arrays.
+* Redirection API:: How to access and manipulate
+ redirections.
* Extension API Variables:: Variables provided by the API.
* Extension API Boilerplate:: Boilerplate code for using the API.
+* Changes from API V1:: Changes from V1 of the API.
@end menu
@node Extension API Functions Introduction
@@ -31576,6 +32658,10 @@ Clearing an array
@item
Flattening an array for easy C-style looping over all its indices and elements
@end itemize
+
+@item
+Accessing and manipulating redirections.
+
@end itemize
Some points about using the API:
@@ -31629,14 +32715,26 @@ and is managed by @command{gawk} from then on.
The API defines several simple @code{struct}s that map values as seen
from @command{awk}. A value can be a @code{double}, a string, or an
array (as in multidimensional arrays, or when creating a new array).
+
String values maintain both pointer and length, because embedded @sc{nul}
characters are allowed.
@quotation NOTE
-By intent, strings are maintained using the current multibyte encoding (as
-defined by @env{LC_@var{xxx}} environment variables) and not using wide
-characters. This matches how @command{gawk} stores strings internally
-and also how characters are likely to be input into and output from files.
+By intent, @command{gawk} maintains strings using the current multibyte
+encoding (as defined by @env{LC_@var{xxx}} environment variables)
+and not using wide characters. This matches how @command{gawk} stores
+strings internally and also how characters are likely to be input into
+and output from files.
+@end quotation
+
+@quotation NOTE
+String values passed to an extension by @command{gawk} are always
+@sc{nul}-terminated. Thus it is safe to pass such string values to
+standard library and system routines. However, because @command{gawk}
+allows embedded @sc{nul} characters in string data, before using the data
+as a regular C string, you should check that the length for that string
+passed to the extension matches the return value of @code{strlen()}
+for it.
@end quotation
@item
@@ -31719,6 +32817,8 @@ multibyte encoding.
@itemx @ @ @ @ AWK_UNDEFINED,
@itemx @ @ @ @ AWK_NUMBER,
@itemx @ @ @ @ AWK_STRING,
+@itemx @ @ @ @ AWK_REGEX,
+@itemx @ @ @ @ AWK_STRNUM,
@itemx @ @ @ @ AWK_ARRAY,
@itemx @ @ @ @ AWK_SCALAR,@ @ @ @ @ @ @ @ @ /* opaque access to a variable */
@itemx @ @ @ @ AWK_VALUE_COOKIE@ @ @ @ /* for updating a previously created value */
@@ -31741,6 +32841,8 @@ The @code{val_type} member indicates what kind of value the
@code{union} holds, and each member is of the appropriate type.
@item #define str_value@ @ @ @ @ @ u.s
+@itemx #define strnum_value@ @ @ str_value
+@itemx #define regex_value@ @ @ @ str_value
@itemx #define num_value@ @ @ @ @ @ u.d
@itemx #define array_cookie@ @ @ u.a
@itemx #define scalar_cookie@ @ u.scl
@@ -31761,7 +32863,7 @@ and in more detail in @ref{Cached values}.
@end table
-Scalar values in @command{awk} are either numbers or strings. The
+Scalar values in @command{awk} are numbers, strings, strnums, or typed regexps. The
@code{awk_value_t} struct represents values. The @code{val_type} member
indicates what is in the @code{union}.
@@ -31770,6 +32872,26 @@ require more work. Because @command{gawk} allows embedded @sc{nul} bytes
in string values, a string must be represented as a pair containing a
data pointer and length. This is the @code{awk_string_t} type.
+A strnum (numeric string) value is represented as a string and consists
+of user input data that appears to be numeric.
+When an extension creates a strnum value, the result is a string flagged
+as user input. Subsequent parsing by @command{gawk} then determines whether it
+looks like a number and should be treated as a strnum, or as a regular string.
+
+This is useful in cases where an extension function would like to do something
+comparable to the @code{split()} function which sets the strnum attribute
+on the array elements it creates. For example, an extension that implements
+CSV splitting would want to use this feature. This is also useful for a
+function that retrieves a data item from a database. The PostgreSQL
+@code{PQgetvalue()} function, for example, returns a string that may be numeric
+or textual depending on the contents.
+
+Typed regexp values (@pxref{Strong Regexp Constants}) are not of
+much use to extension functions. Extension functions can tell that
+they've received them, and create them for scalar values. Otherwise,
+they can examine the text of the regexp through @code{regex_value.str}
+and @code{regex_value.len}.
+
Identifiers (i.e., the names of global variables) can be associated
with either scalar values or with arrays. In addition, @command{gawk}
provides true arrays of arrays, where any given array element can
@@ -31856,8 +32978,8 @@ to use its version of @code{free()} when the memory came from an
unrelated version of @code{malloc()}, unexpected behavior would
likely result.
-Two convenience macros may be used for allocating storage
-from @code{gawk_malloc()} and
+Three convenience macros may be used for allocating storage
+from @code{gawk_malloc()}, @code{gawk_calloc}, and
@code{gawk_realloc()}. If the allocation fails, they cause @command{gawk}
to exit with a fatal error message. They should be used as if they were
procedure calls that do not return a value:
@@ -31896,6 +33018,12 @@ strcpy(message, greet);
make_malloced_string(message, strlen(message), & result);
@end example
+@item #define ezalloc(pointer, type, size, message) @dots{}
+This is like @code{emalloc()}, but it calls @code{gawk_calloc()}
+instead of @code{gawk_malloc()}.
+The arguments are the same as for the @code{emalloc()} macro, but this
+macro guarantees that the memory returned is initialized to zero.
+
@item #define erealloc(pointer, type, size, message) @dots{}
This is like @code{emalloc()}, but it calls @code{gawk_realloc()}
instead of @code{gawk_malloc()}.
@@ -31936,6 +33064,31 @@ It returns @code{result}.
@itemx make_number(double num, awk_value_t *result);
This function simply creates a numeric value in the @code{awk_value_t} variable
pointed to by @code{result}.
+
+@item static inline awk_value_t *
+@itemx make_const_user_input(const char *string, size_t length, awk_value_t *result);
+This function is identical to @code{make_const_string()}, but the string is
+flagged as user input that should be treated as a strnum value if the contents
+of the string are numeric.
+
+@item static inline awk_value_t *
+@itemx make_malloced_user_input(const char *string, size_t length, awk_value_t *result);
+This function is identical to @code{make_malloced_string()}, but the string is
+flagged as user input that should be treated as a strnum value if the contents
+of the string are numeric.
+
+@item static inline awk_value_t *
+@itemx make_const_regex(const char *string, size_t length, awk_value_t *result);
+This function creates a strongly typed regexp value by allocating a copy of the string.
+@code{string} is the regular expression of length @code{len}.
+
+@item static inline awk_value_t *
+@itemx make_malloced_regex(const char *string, size_t length, awk_value_t *result);
+This function creates a strongly typed regexp value. @code{string} is
+the regular expression of length @code{len}. It expects @code{string}
+to be a @samp{char *} value pointing to data previously obtained from
+@code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()}.
+
@end table
@node Registration Functions
@@ -31963,8 +33116,13 @@ Extension functions are described by the following record:
@example
typedef struct awk_ext_func @{
@ @ @ @ const char *name;
-@ @ @ @ awk_value_t *(*function)(int num_actual_args, awk_value_t *result);
-@ @ @ @ size_t num_expected_args;
+@ @ @ @ awk_value_t *(*const function)(int num_actual_args,
+@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result,
+@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo);
+@ @ @ @ const size_t max_expected_args;
+@ @ @ @ const size_t min_required_args;
+@ @ @ @ awk_bool_t suppress_lint;
+@ @ @ @ void *data; /* opaque pointer to any extra state */
@} awk_ext_func_t;
@end example
@@ -31982,36 +33140,94 @@ or an underscore, which may be followed by any number of
letters, digits, and underscores.
Letter case in function names is significant.
-@item awk_value_t *(*function)(int num_actual_args, awk_value_t *result);
+@item awk_value_t *(*const function)(int num_actual_args,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo);
This is a pointer to the C function that provides the extension's
functionality.
-The function must fill in @code{*result} with either a number
-or a string. @command{gawk} takes ownership of any string memory.
+The function must fill in @code{*result} with either a number,
+a string, or a regexp.
+@command{gawk} takes ownership of any string memory.
As mentioned earlier, string memory @emph{must} come from one of
@code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()}.
The @code{num_actual_args} argument tells the C function how many
actual parameters were passed from the calling @command{awk} code.
+The @code{finfo} parameter is a pointer to the @code{awk_ext_func_t} for
+this function. The called function may access data within it as desired, or not.
+
The function must return the value of @code{result}.
This is for the convenience of the calling code inside @command{gawk}.
-@item size_t num_expected_args;
-This is the number of arguments the function expects to receive.
-Each extension function may decide what to do if the number of
-arguments isn't what it expected. As with real @command{awk} functions, it
-is likely OK to ignore extra arguments.
+@item const size_t max_expected_args;
+This is the maximum number of arguments the function expects to receive.
+If called with more arguments than this, and if lint checking has
+been enabled, then @command{gawk} prints a warning message. For more
+information, see the entry for @code{suppress_lint}, later in this list.
+
+@item const size_t min_required_args;
+This is the minimum number of arguments the function expects to receive.
+If called with fewer arguments, @command{gawk} prints a fatal error
+message and exits.
+
+@item awk_bool_t suppress_lint;
+This flag tells @command{gawk} not to print a lint message if lint
+checking has been enabled and if more arguments were supplied in the call
+than expected. An extension function can tell if @command{gawk} already
+printed at least one such message by checking if @samp{num_actual_args >
+finfo->max_expected_args}. If so, and the function does not want more
+lint messages to be printed, it should set @code{finfo->suppress_lint}
+to @code{awk_true}.
+
+@item void *data;
+This is an opaque pointer to any data that an extension function may
+wish to have available when called. Passing the @code{awk_ext_func_t}
+structure to the extension function, and having this pointer available
+in it enable writing a single C or C++ function that implements multiple
+@command{awk}-level extension functions.
@end table
Once you have a record representing your extension function, you register
it with @command{gawk} using this API function:
@table @code
-@item awk_bool_t add_ext_func(const char *namespace, const awk_ext_func_t *func);
+@item awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func);
This function returns true upon success, false otherwise.
The @code{namespace} parameter is currently not used; you should pass in an
empty string (@code{""}). The @code{func} pointer is the address of a
@code{struct} representing your function, as just described.
+
+@command{gawk} does not modify what @code{func} points to, but the
+extension function itself receives this pointer and can modify what it
+points to, thus it is purposely not declared to be @code{const}.
+@end table
+
+The combination of @code{min_required_args}, @code{max_expected_args},
+and @code{suppress_lint} may be confusing. Here is how you should
+set things up.
+
+@table @asis
+@item Any number of arguments is valid
+Set @code{min_required_args} and @code{max_expected_args} to zero and
+set @code{suppress_lint} to @code{awk_true}.
+
+@item A minimum number of arguments is required, no limit on maximum number of arguments
+Set @code{min_required_args} to the minimum required. Set
+@code{max_expected_args} to zero and
+set @code{suppress_lint} to @code{awk_true}.
+
+@item A minimum number of arguments is required, a maximum number is expected
+Set @code{min_required_args} to the minimum required. Set
+@code{max_expected_args} to the maximum expected.
+Set @code{suppress_lint} to @code{awk_false}.
+
+@item A minimum number of arguments is required, and no more than a maximum is allowed
+Set @code{min_required_args} to the minimum required. Set
+@code{max_expected_args} to the maximum expected.
+Set @code{suppress_lint} to @code{awk_false}.
+In your extension function, check that @code{num_actual_args} does not
+exceed @code{f->max_expected_args}. If it does, issue a fatal error message.
@end table
@node Exit Callback Functions
@@ -32151,7 +33367,8 @@ typedef struct awk_input @{
#define INVALID_HANDLE (-1)
void *opaque; /* private data for input parsers */
int (*get_record)(char **out, struct awk_input *iobuf,
- int *errcode, char **rt_start, size_t *rt_len);
+ int *errcode, char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **field_width);
ssize_t (*read_func)();
void (*close_func)(struct awk_input *iobuf);
struct stat sbuf; /* stat buf */
@@ -32203,7 +33420,8 @@ is not required to use this pointer.
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct@ awk_input *iobuf,
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int *errcode,
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ char **rt_start,
-@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t *rt_len);
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t *rt_len,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_fieldwidth_info_t **field_width);
This function pointer should point to a function that creates the input
records. Said function is the core of the input parser. Its behavior
is described in the text following this list.
@@ -32255,6 +33473,21 @@ If the concept of a ``record terminator'' makes sense, then
data. Otherwise, @code{*rt_len} should be set to zero.
@command{gawk} makes its own copy of this data, so the
extension must manage this storage.
+
+@item const awk_fieldwidth_info_t **field_width
+If @code{field_width} is not @code{NULL}, then @code{*field_width} will be initialized
+to @code{NULL}, and the function may set it to point to a structure
+supplying field width information to override the default
+field parsing mechanism. Note that this structure will not
+be copied by @command{gawk}; it must persist at least until the next call
+to @code{get_record} or @code{close_func}. Note also that @code{field_width} is
+@code{NULL} when @code{getline} is assigning the results to a variable, thus
+field parsing is not needed. If the parser does set @code{*field_width},
+then @command{gawk} uses this layout to parse the input record,
+and the @code{PROCINFO["FS"]} value will be @code{"API"} while this record
+is active in @code{$0}.
+The @code{awk_fieldwidth_info_t} data structure
+is described below.
@end table
The return value is the length of the buffer pointed to by
@@ -32313,6 +33546,50 @@ Register the input parser pointed to by @code{input_parser} with
@command{gawk}.
@end table
+If you would like to override the default field parsing mechanism for a given
+record, then you must populate an @code{awk_fieldwidth_info_t} structure,
+which looks like this:
+
+@example
+typedef struct @{
+ awk_bool_t use_chars; /* false ==> use bytes */
+ size_t nf; /* number of fields in record (NF) */
+ struct awk_field_info @{
+ size_t skip; /* amount to skip before field starts */
+ size_t len; /* length of field */
+ @} fields[1]; /* actual dimension should be nf */
+@} awk_fieldwidth_info_t;
+@end example
+
+The fields are:
+
+@table @code
+@item awk_bool_t use_chars;
+Set this to @code{awk_true} if the field lengths are specified in terms
+of potentially multi-byte characters, and set it to @code{awk_false} if
+the lengths are in terms of bytes.
+Performance will be better if the values are supplied in
+terms of bytes.
+
+@item size_t nf;
+Set this to the number of fields in the input record, i.e. @code{NF}.
+
+@item struct awk_field_info fields[nf];
+This is a variable-length array whose actual dimension should be @code{nf}.
+For each field, the @code{skip} element should be set to the number
+of characters or bytes, as controlled by the @code{use_chars} flag,
+to skip before the start of this field. The @code{len} element provides
+the length of the field. The values in @code{fields[0]} provide the information
+for @code{$1}, and so on through the @code{fields[nf-1]} element containing the information for @code{$NF}.
+@end table
+
+A convenience macro @code{awk_fieldwidth_info_size(NF)} is provided to
+calculate the appropriate size of a variable-length
+@code{awk_fieldwidth_info_t} structure containing @code{NF} fields. This can
+be used as an argument to @code{malloc()} or in a union to allocate space
+statically. Please refer to the @code{readdir_test} sample extension for an
+example.
+
@node Output Wrappers
@subsubsection Customized Output Wrappers
@cindex customized output wrapper
@@ -32503,6 +33780,9 @@ that parameter. More's the pity.}
@item void fatal(awk_ext_id_t id, const char *format, ...);
Print a message and then cause @command{gawk} to exit immediately.
+@item void nonfatal(awk_ext_id_t id, const char *format, ...);
+Print a nonfatal error message.
+
@item void warning(awk_ext_id_t id, const char *format, ...);
Print a warning message.
@@ -32555,21 +33835,25 @@ value type, as appropriate. This behavior is summarized in
@caption{API value types returned}
@docbook
<informaltable>
-<tgroup cols="6">
- <colspec colwidth="16.6*"/>
- <colspec colwidth="16.6*"/>
- <colspec colwidth="19.8*" colname="c3"/>
- <colspec colwidth="15*" colname="c4"/>
- <colspec colwidth="15*" colname="c5"/>
- <colspec colwidth="16.6*" colname="c6"/>
- <spanspec spanname="hspan" namest="c3" nameend="c6" align="center"/>
+<tgroup cols="8">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <colspec colname="c3"/>
+ <colspec colname="c4"/>
+ <colspec colname="c5"/>
+ <colspec colname="c6"/>
+ <colspec colname="c7"/>
+ <colspec colname="c8"/>
+ <spanspec spanname="hspan" namest="c3" nameend="c8" align="center"/>
<thead>
<row><entry></entry><entry spanname="hspan"><para>Type of Actual Value</para></entry></row>
<row>
<entry></entry>
<entry></entry>
<entry><para>String</para></entry>
+ <entry><para>Strnum</para></entry>
<entry><para>Number</para></entry>
+ <entry><para>Regex</para></entry>
<entry><para>Array</para></entry>
<entry><para>Undefined</para></entry>
</row>
@@ -32580,48 +33864,80 @@ value type, as appropriate. This behavior is summarized in
<entry><para><emphasis role="bold">String</emphasis></para></entry>
<entry><para>String</para></entry>
<entry><para>String</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>String</para></entry>
+ <entry><para>String</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Strnum</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
<entry></entry>
<entry><para><emphasis role="bold">Number</emphasis></para></entry>
- <entry><para>Number if can be converted, else false</para></entry>
<entry><para>Number</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>Number</para></entry>
+ <entry><para>Number</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
<entry><para><emphasis role="bold">Type</emphasis></para></entry>
+ <entry><para><emphasis role="bold">Regex</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Regex</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry><para><emphasis role="bold">Requested</emphasis></para></entry>
<entry><para><emphasis role="bold">Array</emphasis></para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
<entry><para>Array</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
- <entry><para><emphasis role="bold">Requested</emphasis></para></entry>
+ <entry></entry>
<entry><para><emphasis role="bold">Scalar</emphasis></para></entry>
<entry><para>Scalar</para></entry>
<entry><para>Scalar</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>Scalar</para></entry>
+ <entry><para>Scalar</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
<entry></entry>
<entry><para><emphasis role="bold">Undefined</emphasis></para></entry>
<entry><para>String</para></entry>
+ <entry><para>Strnum</para></entry>
<entry><para>Number</para></entry>
+ <entry><para>Regex</para></entry>
<entry><para>Array</para></entry>
<entry><para>Undefined</para></entry>
</row>
<row>
<entry></entry>
<entry><para><emphasis role="bold">Value cookie</emphasis></para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para>
- </entry><entry><para>False</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
</tbody>
</tgroup>
@@ -32637,41 +33953,45 @@ value type, as appropriate. This behavior is summarized in
@tex
\vglue-1.1\baselineskip
@end tex
-@multitable @columnfractions .166 .166 .198 .15 .15 .166
-@headitem @tab @tab String @tab Number @tab Array @tab Undefined
-@item @tab @b{String} @tab String @tab String @tab False @tab False
-@item @tab @b{Number} @tab Number if can be converted, else false @tab Number @tab False @tab False
-@item @b{Type} @tab @b{Array} @tab False @tab False @tab Array @tab False
-@item @b{Requested} @tab @b{Scalar} @tab Scalar @tab Scalar @tab False @tab False
-@item @tab @b{Undefined} @tab String @tab Number @tab Array @tab Undefined
-@item @tab @b{Value cookie} @tab False @tab False @tab False @tab False
+@c @multitable @columnfractions .166 .166 .198 .15 .15 .166
+@multitable {Requested} {Undefined} {Number} {Number} {Scalar} {Regex} {Array} {Undefined}
+@headitem @tab @tab String @tab Strnum @tab Number @tab Regex @tab Array @tab Undefined
+@item @tab @b{String} @tab String @tab String @tab String @tab String @tab false @tab false
+@item @tab @b{Strnum} @tab false @tab Strnum @tab Strnum @tab false @tab false @tab false
+@item @tab @b{Number} @tab Number @tab Number @tab Number @tab false @tab false @tab false
+@item @b{Type} @tab @b{Regex} @tab false @tab false @tab false @tab Regex @tab false @tab false
+@item @b{Requested} @tab @b{Array} @tab false @tab false @tab false @tab false @tab Array @tab false
+@item @tab @b{Scalar} @tab Scalar @tab Scalar @tab Scalar @tab Scalar @tab false @tab false
+@item @tab @b{Undefined} @tab String @tab Strnum @tab Number @tab Regex @tab Array @tab Undefined
+@item @tab @b{Value cookie} @tab false @tab false @tab false @tab false @tab false @tab false
@end multitable
@end ifnotdocbook
@end ifnotplaintext
@ifplaintext
-@example
- +-------------------------------------------------+
- | Type of Actual Value: |
- +------------+------------+-----------+-----------+
- | String | Number | Array | Undefined |
-+-----------+-----------+------------+------------+-----------+-----------+
-| | String | String | String | False | False |
-| |-----------+------------+------------+-----------+-----------+
-| | Number | Number if | Number | False | False |
-| | | can be | | | |
-| | | converted, | | | |
-| | | else false | | | |
-| |-----------+------------+------------+-----------+-----------+
-| Type | Array | False | False | Array | False |
-| Requested |-----------+------------+------------+-----------+-----------+
-| | Scalar | Scalar | Scalar | False | False |
-| |-----------+------------+------------+-----------+-----------+
-| | Undefined | String | Number | Array | Undefined |
-| |-----------+------------+------------+-----------+-----------+
-| | Value | False | False | False | False |
-| | cookie | | | | |
-+-----------+-----------+------------+------------+-----------+-----------+
-@end example
+@verbatim
+ +-------------------------------------------------------+
+ | Type of Actual Value: |
+ +--------+--------+--------+--------+-------+-----------+
+ | String | Strnum | Number | Regex | Array | Undefined |
++-----------+-----------+--------+--------+--------+--------+-------+-----------+
+| | String | String | String | String | String | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Strnum | false | Strnum | Strnum | false | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Number | Number | Number | Number | false | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Regex | false | false | false | Regex | false | false |
+| Type +-----------+--------+--------+--------+--------+-------+-----------+
+| Requested | Array | false | false | false | false | Array | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Scalar | Scalar | Scalar | Scalar | Scalar | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Undefined | String | Strnum | Number | Regex | Array | Undefined |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Value | false | false | false | false | false | false |
+| | Cookie | | | | | | |
++-----------+-----------+--------+--------+--------+--------+-------+-----------+
+@end verbatim
@end ifplaintext
@end float
@@ -32749,13 +34069,6 @@ An extension can look up the value of @command{gawk}'s special variables.
However, with the exception of the @code{PROCINFO} array, an extension
cannot change any of those variables.
-@quotation CAUTION
-It is possible for the lookup of @code{PROCINFO} to fail. This happens if
-the @command{awk} program being run does not reference @code{PROCINFO};
-in this case, @command{gawk} doesn't bother to create the array and
-populate it.
-@end quotation
-
@node Symbol table by cookie
@subsubsection Variable Access and Update by Cookie
@@ -32777,7 +34090,7 @@ Return false if the value cannot be retrieved.
@item awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *value);
Update the value associated with a scalar cookie. Return false if
-the new value is not of type @code{AWK_STRING} or @code{AWK_NUMBER}.
+the new value is not of type @code{AWK_STRING}, @code{AWK_STRNUM}, @code{AWK_REGEX}, or @code{AWK_NUMBER}.
Here too, the predefined variables may not be updated.
@end table
@@ -32898,7 +34211,7 @@ is what the routines in this @value{SECTION} let you do. The functions are as f
@table @code
@item awk_bool_t create_value(awk_value_t *value, awk_value_cookie_t *result);
Create a cached string or numeric value from @code{value} for
-efficient later assignment. Only values of type @code{AWK_NUMBER}
+efficient later assignment. Only values of type @code{AWK_NUMBER}, @code{AWK_REGEX}, @code{AWK_STRNUM},
and @code{AWK_STRING} are allowed. Any other type is rejected.
@code{AWK_UNDEFINED} could be allowed, but doing so would result in
inferior performance.
@@ -33124,9 +34437,10 @@ The array remains an array, but after calling this function, it
has no elements. This is equivalent to using the @code{delete}
statement (@pxref{Delete}).
-@item awk_bool_t flatten_array(awk_array_t a_cookie, awk_flat_array_t **data);
+@item awk_bool_t flatten_array_typed(awk_array_t a_cookie, awk_flat_array_t **data, awk_valtype_t index_type, awk_valtype_t value_type);
For the array represented by @code{a_cookie}, create an @code{awk_flat_array_t}
-structure and fill it in. Set the pointer whose address is passed as @code{data}
+structure and fill it in with indices and values of the requested types.
+Set the pointer whose address is passed as @code{data}
to point to this structure.
Return true upon success, or false otherwise.
@ifset FOR_PRINT
@@ -33138,6 +34452,14 @@ See the next @value{SECTION}
for a discussion of how to
flatten an array and work with it.
+@item awk_bool_t flatten_array(awk_array_t a_cookie, awk_flat_array_t **data);
+For the array represented by @code{a_cookie}, create an @code{awk_flat_array_t}
+structure and fill it in with @code{AWK_STRING} indices and
+@code{AWK_UNDEFINED} values.
+This is superseded by @code{flatten_array_typed()}.
+It is provided as a macro, and remains for convenience and for source code
+compatibility with the previous version of the API.
+
@item awk_bool_t release_flattened_array(awk_array_t a_cookie,
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_flat_array_t *data);
When done with a flattened array, release the storage using this function.
@@ -33250,7 +34572,7 @@ to double-check that the count in the @code{awk_flat_array_t}
is the same as the count just retrieved:
@example
- if (! flatten_array(value2.array_cookie, & flat_array)) @{
+ if (! flatten_array_typed(value2.array_cookie, & flat_array, AWK_STRING, AWK_UNDEFINED)) @{
printf("dump_array_and_delete: could not flatten array\n");
goto out;
@}
@@ -33546,6 +34868,75 @@ $ @kbd{AWKLIBPATH=$PWD ./gawk -f subarray.awk}
(@xref{Finding Extensions} for more information on the
@env{AWKLIBPATH} environment variable.)
+@node Redirection API
+@subsection Accessing and Manipulating Redirections
+
+The following function allows extensions to access and manipulate redirections.
+
+@table @code
+@item awk_bool_t get_file(const char *name,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t name_len,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *filetype,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int fd,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_input_buf_t **ibufp,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_output_buf_t **obufp);
+Look up file @code{name} in @command{gawk}'s internal redirection table.
+If @code{name} is @code{NULL} or @code{name_len} is zero, return
+data for the currently open input file corresponding to @code{FILENAME}.
+(This does not access the @code{filetype} argument, so that may be undefined).
+If the file is not already open, attempt to open it.
+The @code{filetype} argument must be zero-terminated and should be one of:
+
+@table @code
+@item ">"
+A file opened for output.
+
+@item ">>"
+A file opened for append.
+
+@item "<"
+A file opened for input.
+
+@item "|>"
+A pipe opened for output.
+
+@item "|<"
+A pipe opened for input.
+
+@item "|&"
+A two-way coprocess.
+@end table
+
+On error, return an @code{awk_false} value. Otherwise, return
+@code{awk_true}, and return additional information about the redirection
+in the @code{ibufp} and @code{obufp} pointers. For input
+redirections, the @code{*ibufp} value should be non-@code{NULL},
+and @code{*obufp} should be @code{NULL}. For output redirections,
+the @code{*obufp} value should be non-@code{NULL}, and @code{*ibufp}
+should be @code{NULL}. For two-way coprocesses, both values should
+be non-@code{NULL}.
+
+In the usual case, the extension is interested in @code{(*ibufp)->fd}
+and/or @code{fileno((*obufp)->fp)}. If the file is not already
+open, and the @code{fd} argument is nonnegative, @command{gawk}
+will use that file descriptor instead of opening the file in the
+usual way. If @code{fd} is nonnegative, but the file exists already,
+@command{gawk} ignores @code{fd} and returns the existing file. It is
+the caller's responsibility to notice that neither the @code{fd} in
+the returned @code{awk_input_buf_t} nor the @code{fd} in the returned
+@code{awk_output_buf_t} matches the requested value.
+
+Note that supplying a file descriptor is currently @emph{not} supported
+for pipes. However, supplying a file descriptor should work for input,
+output, append, and two-way (coprocess) sockets. If @code{filetype}
+is two-way, @command{gawk} assumes that it is a socket! Note that in
+the two-way case, the input and output file descriptors may differ.
+To check for success, you must check whether either matches.
+@end table
+
+It is anticipated that this API function will be used to implement I/O
+multiplexing and a socket library.
+
@node Extension API Variables
@subsection API Variables
@@ -33572,10 +34963,10 @@ debugging:
@float Table,gawk-api-version
@caption{gawk API version constants}
-@multitable @columnfractions .33 .33 .33
-@headitem API Version @tab C preprocessor define @tab enum constant
-@item Major @tab gawk_api_major_version @tab GAWK_API_MAJOR_VERSION
-@item Minor @tab gawk_api_minor_version @tab GAWK_API_MINOR_VERSION
+@multitable {@b{API Version}} {@code{gawk_api_major_version}} {@code{GAWK_API_MAJOR_VERSION}}
+@headitem API Version @tab C Preprocessor Define @tab enum constant
+@item Major @tab @code{gawk_api_major_version} @tab @code{GAWK_API_MAJOR_VERSION}
+@item Minor @tab @code{gawk_api_minor_version} @tab @code{GAWK_API_MINOR_VERSION}
@end multitable
@end float
@@ -33594,10 +34985,10 @@ constant integers:
@table @code
@item api->major_version
-The major version of the running @command{gawk}
+The major version of the running @command{gawk}.
@item api->minor_version
-The minor version of the running @command{gawk}
+The minor version of the running @command{gawk}.
@end table
It is up to the extension to decide if there are API incompatibilities.
@@ -33670,7 +35061,7 @@ static awk_ext_id_t ext_id;
static const char *ext_version = NULL; /* or @dots{} = "some string" */
static awk_ext_func_t func_table[] = @{
- @{ "name", do_name, 1 @},
+ @{ "name", do_name, 1, 0, awk_false, NULL @},
/* @dots{} */
@};
@@ -33771,6 +35162,19 @@ If @code{ext_version} is not @code{NULL}, register
the version string with @command{gawk}.
@end enumerate
+
+@node Changes from API V1
+@subsection Changes From Version 1 of the API
+
+The current API is @emph{not} binary compatible with version 1 of the API.
+You will have to recompile your extensions in order to use them with
+the current version of @command{gawk}.
+
+Fortunately, at the possible expense of some compile-time warnings, the API remains
+source-code--compatible with the previous API. The major differences are
+the additional members in the @code{awk_ext_func_t} structure, and the
+addition of the third argument to the C implementation function.
+
@node Finding Extensions
@section How @command{gawk} Finds Extensions
@cindex extension search path
@@ -34011,17 +35415,12 @@ The second is a pointer to an @code{awk_value_t} structure, usually named
/* do_chdir --- provide dynamically loaded chdir() function for gawk */
static awk_value_t *
-do_chdir(int nargs, awk_value_t *result)
+do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused)
@{
awk_value_t newdir;
int ret = -1;
assert(result != NULL);
-
- if (do_lint && nargs != 1)
- lintwarn(ext_id,
- _("chdir: called with incorrect number of arguments, "
- "expecting 1"));
@end example
The @code{newdir}
@@ -34030,8 +35429,8 @@ with @code{get_argument()}. Note that the first argument is
numbered zero.
If the argument is retrieved successfully, the function calls the
-@code{chdir()} system call. If the @code{chdir()} fails, @code{ERRNO}
-is updated:
+@code{chdir()} system call. Otherwise, if the @code{chdir()} fails,
+it updates @code{ERRNO}:
@example
if (get_argument(0, AWK_STRING, & newdir)) @{
@@ -34235,15 +35634,11 @@ is set to point to @code{stat()}, instead.
Here is the @code{do_stat()} function, which starts with
variable declarations and argument checking:
-@ignore
-Changed message for page breaking. Used to be:
- "stat: called with incorrect number of arguments (%d), should be 2",
-@end ignore
@example
/* do_stat --- provide a stat() function for gawk */
static awk_value_t *
-do_stat(int nargs, awk_value_t *result)
+do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused)
@{
awk_value_t file_param, array_param;
char *name;
@@ -34254,13 +35649,6 @@ do_stat(int nargs, awk_value_t *result)
int (*statfunc)(const char *path, struct stat *sbuf) = lstat;
assert(result != NULL);
-
- if (nargs != 2 && nargs != 3) @{
- if (do_lint)
- lintwarn(ext_id,
- _("stat: called with wrong number of arguments"));
- return make_number(-1, result);
- @}
@end example
Then comes the actual work. First, the function gets the arguments.
@@ -34328,11 +35716,9 @@ structures for loading each function into @command{gawk}:
@example
static awk_ext_func_t func_table[] = @{
- @{ "chdir", do_chdir, 1 @},
- @{ "stat", do_stat, 2 @},
-#ifndef __MINGW32__
- @{ "fts", do_fts, 3 @},
-#endif
+ @{ "chdir", do_chdir, 1, 1, awk_false, NULL @},
+ @{ "stat", do_stat, 3, 2, awk_false, NULL @},
+ @dots{}
@};
@end example
@@ -35113,18 +36499,21 @@ As of this writing, there are seven extensions:
GD graphics library extension
@item
+MPFR library extension
+(this provides access to a number of MPFR functions that @command{gawk}'s
+native MPFR support does not)
+
+@item
PDF extension
@item
PostgreSQL extension
@item
-MPFR library extension
-(this provides access to a number of MPFR functions that @command{gawk}'s
-native MPFR support does not)
+Redis extension
@item
-Redis extension
+Select extension
@item
XML parser extension, using the @uref{http://expat.sourceforge.net, Expat}
@@ -35224,7 +36613,7 @@ output wrappers,
and two-way processors)
@item
-Printing fatal, warning, and ``lint'' warning messages
+Printing fatal, nonfatal, warning, and ``lint'' warning messages
@item
Updating @code{ERRNO}, or unsetting it
@@ -35753,6 +37142,10 @@ Indirect function calls
@item
Directories on the command line produce a warning and are skipped
(@pxref{Command-line directories})
+
+@item
+Output with @code{print} and @code{printf} need not be fatal
+(@pxref{Nonfatal})
@end itemize
@item
@@ -35840,6 +37233,11 @@ The @code{isarray()} function to check if a variable is an array or not
The @code{bindtextdomain()}, @code{dcgettext()}, and @code{dcngettext()}
functions for internationalization
(@pxref{Programmer i18n})
+
+@item
+The @code{intdiv()} function for doing integer
+division and remainder
+(@pxref{Numeric Functions})
@end itemize
@item
@@ -35878,6 +37276,7 @@ The
@option{-p},
@option{-P},
@option{-r},
+@option{-s},
@option{-S},
@option{-t},
and
@@ -35902,6 +37301,7 @@ and the
@option{--load},
@option{--non-decimal-data},
@option{--optimize},
+@option{--no-optimize},
@option{--posix},
@option{--pretty-print},
@option{--profile},
@@ -35972,6 +37372,19 @@ for @command{gawk} @value{PVERSION} 4.1:
Ultrix
@end itemize
+@item
+Support for the following systems was removed from the code
+for @command{gawk} @value{PVERSION} 4.2:
+
+@c nested table
+@itemize @value{MINUS}
+@item
+MirBSD
+
+@item
+GNU/Linux on Alpha
+@end itemize
+
@end itemize
@c XXX ADD MORE STUFF HERE
@@ -36598,6 +38011,56 @@ Support for Ultrix was removed.
@end itemize
+Version 4.2 introduced the following changes:
+
+@itemize @bullet
+@item
+Changes to @code{ENVIRON} are reflected into @command{gawk}'s
+environment and that of programs that it runs.
+@xref{Auto-set}.
+
+@item
+The @code{PROCINFO["argv"} array.
+@xref{Auto-set}.
+
+@item
+The @option{--pretty-print} option no longer runs the @command{awk}
+program too.
+@xref{Options}.
+
+@item
+The @command{igawk} program and its manual page are no longer
+installed when @command{gawk} is built.
+@xref{Igawk Program}.
+
+@item
+The @code{intdiv()} function.
+@xref{Numeric Functions}.
+
+@item
+The maximum number of hexadecimal digits in @samp{\x} escapes
+is now two.
+@xref{Escape Sequences}.
+
+@item
+Nonfatal output with @code{print} and @code{printf}.
+@xref{Nonfatal}.
+
+@item
+For many years, POSIX specified that default field splitting
+only allowed spaces and tabs to separate fields, and this was
+how @command{gawk} behaved with @option{--posix}. As of 2013,
+the standard restored historical behavior, and now default
+field splitting with @option{--posix} also allows newlines to
+separate fields.
+
+@item
+Support for MirBSD was removed.
+
+@item
+Support for GNU/Linux on Alpha was removed.
+@end itemize
+
@c XXX ADD MORE STUFF HERE
@end ifclear
@@ -36727,7 +38190,7 @@ and
@uref{http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap09.html#tag_21_09_03_05, its rationale}.}
By using this lovely technical term, the standard gives license
-to implementors to implement ranges in whatever way they choose.
+to implementers to implement ranges in whatever way they choose.
The @command{gawk} maintainer chose to apply the pre-POSIX meaning
both with the default regexp matching and when @option{--traditional} or
@option{--posix} are used.
@@ -37164,6 +38627,12 @@ These files contain the actual @command{gawk} source code.
@end table
@table @file
+@item support/*
+C header and source files for routines that @command{gawk}
+uses, but that are not part of its core functionality.
+For example, argument parsing, regular expression matching,
+and random number generating routines are all kept here.
+
@item ABOUT-NLS
A file containing information about GNU @command{gettext} and translations.
@@ -37264,6 +38733,8 @@ The generated Info file for
The @command{troff} source for a manual page describing the @command{igawk}
program presented in
@ref{Igawk Program}.
+(Since @command{gawk} can do its own @code{@@include} processing,
+neither @command{igawk} nor @file{igawk.1} are installed.)
@item doc/Makefile.in
The input file used during the configuration process to generate the
@@ -37308,8 +38779,6 @@ source file for this @value{DOCUMENT}. It also contains a @file{Makefile.in} fil
@file{Makefile.am} is used by GNU Automake to create @file{Makefile.in}.
The library functions from
@ref{Library Functions},
-and the @command{igawk} program from
-@ref{Igawk Program}
are included as ready-to-use files in the @command{gawk} distribution.
They are installed as part of the installation process.
The rest of the programs in this @value{DOCUMENT} are available in appropriate
@@ -37320,6 +38789,12 @@ The source code, manual pages, and infrastructure files for
the sample extensions included with @command{gawk}.
@xref{Dynamic Extensions}, for more information.
+@item extras/*
+Additional non-essential files. Currently, this directory contains some shell
+startup files to be installed in @file{/etc/profile.d} to aid in manipulating
+the @env{AWKPATH} and @env{AWKLIBPATH} environment variables.
+@xref{Shell Startup Files}, for more information.
+
@item posix/*
Files needed for building @command{gawk} on POSIX-compliant systems.
@@ -37348,6 +38823,7 @@ to configure @command{gawk} for your system yourself.
@menu
* Quick Installation:: Compiling @command{gawk} under Unix.
+* Shell Startup Files:: Shell convenience functions.
* Additional Configuration Options:: Other compile-time options.
* Configuration Philosophy:: How it's all supposed to work.
@end menu
@@ -37428,6 +38904,44 @@ is likely that you will be asked for your password, and you will have
to have been set up previously as a user who is allowed to run the
@command{sudo} command.
+@node Shell Startup Files
+@appendixsubsec Shell Startup Files
+
+The distribution contains shell startup files @file{gawk.sh} and
+@file{gawk.csh}, containing functions to aid in manipulating
+the @env{AWKPATH} and @env{AWKLIBPATH} environment variables.
+On a Fedora GNU/Linux system, these files should be installed in @file{/etc/profile.d};
+on other platforms, the appropriate location may be different.
+
+@table @command
+
+@cindex @command{gawkpath_default} shell function
+@item gawkpath_default
+Reset the @env{AWKPATH} environment variable to its default value.
+
+@cindex @command{gawkpath_prepend} shell function
+@item gawkpath_prepend
+Add the argument to the front of the @env{AWKPATH} environment variable.
+
+@cindex @command{gawkpath_append} shell function
+@item gawkpath_append
+Add the argument to the end of the @env{AWKPATH} environment variable.
+
+@cindex @command{gawklibpath_default} shell function
+@item gawklibpath_default
+Reset the @env{AWKLIBPATH} environment variable to its default value.
+
+@cindex @command{gawklibpath_prepend} shell function
+@item gawklibpath_prepend
+Add the argument to the front of the @env{AWKLIBPATH} environment variable.
+
+@cindex @command{gawklibpath_append} shell function
+@item gawklibpath_append
+Add the argument to the end of the @env{AWKLIBPATH} environment variable.
+
+@end table
+
+
@node Additional Configuration Options
@appendixsubsec Additional Configuration Options
@cindex @command{gawk}, configuring, options
@@ -37469,6 +38983,13 @@ Using this option will cause some of the tests in the test suite
to fail. This option may be removed at a later date.
@end quotation
+@cindex @option{--disable-mpfr} configuration option
+@cindex configuration option, @code{--disable-mpfr}
+@item --disable-mpfr
+Skip checking for the MPFR and GMP libraries. This is useful
+mainly for the developers, to make sure nothing breaks if
+MPFR support is not available.
+
@cindex @option{--disable-nls} configuration option
@cindex configuration option, @code{--disable-nls}
@item --disable-nls
@@ -42011,6 +43532,7 @@ Consistency issues:
Use MS-DOS not MS DOS
Use an empty set of parentheses after built-in and awk function names.
Use "multiFOO" without a hyphen.
+ Use "time zone" as two words, not "timezone".
Date: Wed, 13 Apr 94 15:20:52 -0400
From: rms@gnu.org (Richard Stallman)
diff --git a/doc/gawktexi.in b/doc/gawktexi.in
index 868db437..7d60a2c7 100644
--- a/doc/gawktexi.in
+++ b/doc/gawktexi.in
@@ -44,6 +44,14 @@
@set MINUS
@end ifdocbook
+@iftex
+@set TIMES @times
+@end iftex
+@ifnottex
+@set TIMES *
+@end ifnottex
+
+
@set xref-automatic-section-title
@c The following information should be updated here only!
@@ -51,7 +59,7 @@
@c applies to and all the info about who's publishing this edition
@c These apply across the board.
-@set UPDATE-MONTH January, 2017
+@set UPDATE-MONTH May, 2017
@set VERSION 4.1
@set PATCHLEVEL 4
@@ -555,7 +563,13 @@ particular records in a file and perform operations upon them.
field.
* Field Splitting Summary:: Some final points and a summary table.
* Constant Size:: Reading constant width data.
+* Fixed width data:: Processing fixed-width data.
+* Skipping intervening:: Skipping intervening fields.
+* Allowing trailing data:: Capturing optional trailing data.
+* Fields with fixed data:: Field values with fixed-width data.
* Splitting By Content:: Defining Fields By Content
+* Testing field creation:: Checking how @command{gawk} is
+ splitting records.
* Multiple Line:: Reading multiline records.
* Getline:: Reading files under explicit program
control using the @code{getline}
@@ -576,6 +590,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.
+* Retrying Input:: Retrying input after certain errors.
* Command-line directories:: What happens if you put a directory on
the command line.
* Input Summary:: Input summary.
@@ -605,6 +620,7 @@ particular records in a file and perform operations upon them.
* Special Caveats:: Things to watch out for.
* Close Files And Pipes:: Closing Input and Output Files and
Pipes.
+* Nonfatal:: Enabling Nonfatal Output.
* Output Summary:: Output summary.
* Output Exercises:: Exercises.
* Values:: Constants, Variables, and Regular
@@ -614,6 +630,9 @@ particular records in a file and perform operations upon them.
* Nondecimal-numbers:: What are octal and hex numbers.
* Regexp Constants:: Regular Expression constants.
* Using Constant Regexps:: When and how to use a regexp constant.
+* Standard Regexp Constants:: Regexp constants in standard
+ @command{awk}.
+* Strong Regexp Constants:: Strongly typed regexp constants.
* Variables:: Variables give names to values for
later use.
* Using Variables:: Using variables in your programs.
@@ -884,6 +903,7 @@ particular records in a file and perform operations upon them.
* Setting the rounding mode:: How to set the rounding mode.
* Arbitrary Precision Integers:: Arbitrary Precision Integer Arithmetic
with @command{gawk}.
+* Checking for MPFR:: How to check if MPFR is available.
* POSIX Floating Point Problems:: Standards Versus Existing Practice.
* Floating point summary:: Summary of floating point discussion.
* Extension Intro:: What is an extension.
@@ -916,11 +936,14 @@ particular records in a file and perform operations upon them.
* Array Functions:: Functions for working with arrays.
* Flattening Arrays:: How to flatten arrays.
* Creating Arrays:: How to create and populate arrays.
+* Redirection API:: How to access and manipulate
+ redirections.
* Extension API Variables:: Variables provided by the API.
* Extension Versioning:: API Version information.
* Extension API Informational Variables:: Variables providing information about
@command{gawk}'s invocation.
* Extension API Boilerplate:: Boilerplate code for using the API.
+* Changes from API V1:: Changes from V1 of the API.
* Finding Extensions:: How @command{gawk} finds compiled
extensions.
* Extension Example:: Example C code for an extension.
@@ -974,14 +997,16 @@ particular records in a file and perform operations upon them.
* Unix Installation:: Installing @command{gawk} under
various versions of Unix.
* Quick Installation:: Compiling @command{gawk} under Unix.
+* Shell Startup Files:: Shell convenience functions.
* Additional Configuration Options:: Other compile-time options.
* Configuration Philosophy:: How it's all supposed to work.
* Non-Unix Installation:: Installation on Other Operating
Systems.
-* PC Installation:: Installing and Compiling @command{gawk} on
- Microsoft Windows.
+* PC Installation:: Installing and Compiling
+ @command{gawk} on Microsoft Windows.
* PC Binary Installation:: Installing a prepared distribution.
-* PC Compiling:: Compiling @command{gawk} for Windows32.
+* PC Compiling:: Compiling @command{gawk} for
+ Windows32.
* PC Using:: Running @command{gawk} on Windows32.
* Cygwin:: Building and running @command{gawk}
for Cygwin.
@@ -2933,14 +2958,59 @@ it is worth addressing.
@cindex Brink, Jeroen
The ``shells'' on Microsoft Windows systems use the double-quote
character for quoting, and make it difficult or impossible to include an
-escaped double-quote character in a command-line script.
-The following example, courtesy of Jeroen Brink, shows
-how to print all lines in a file surrounded by double quotes:
+escaped double-quote character in a command-line script. The following
+example, courtesy of Jeroen Brink, shows how to escape the double quotes
+from this one liner script that prints all lines in a file surrounded by
+double quotes:
+
+@example
+@{ print "\"" $0 "\"" @}
+@end example
+
+@noindent
+In an MS-Windows command-line the one-liner script above may be passed as
+follows:
@example
gawk "@{ print \"\042\" $0 \"\042\" @}" @var{file}
@end example
+In this example the @samp{\042} is the octal code for a double-quote;
+@command{gawk} converts it into a real double-quote for output by
+the @code{print} statement.
+
+In MS-Windows escaping double-quotes is a little tricky because you use
+backslashes to escape double-quotes, but backslashes themselves are not
+escaped in the usual way; indeed they are either duplicated or not,
+depending upon whether there is a subsequent double-quote. The MS-Windows
+rule for double-quoting a string is the following:
+
+@enumerate
+@item
+For each double quote in the orginal string, let @var{N} be the number
+of backslash(es) before it, @var{N} might be zero. Replace these @var{N}
+backslash(es) by @math{2@value{TIMES}@var{N}+1} backslash(es)
+
+@item
+Let @var{N} be the number of backslash(es) tailing the original string,
+@var{N} might be zero. Replace these @var{N} backslash(es) by
+@math{2@value{TIMES}@var{N}} backslash(es)
+
+@item
+Surround the resulting string by double-quotes.
+@end enumerate
+
+So to double-quote the one-liner script @samp{@{ print "\"" $0 "\"" @}}
+from the previous example you would do it this way:
+
+@example
+gawk "@{ print \"\\\"\" $0 \"\\\"\" @}" @var{file}
+@end example
+
+@noindent
+However, the use of @samp{\042} instead of @samp{\\\"} is also possible
+and easier to read, because backslashes that are not followed by a
+double-quote don't need duplication.
@node Sample Data Files
@section @value{DDF}s for the Examples
@@ -3809,6 +3879,24 @@ This is particularly useful
when you have library functions that you want to use from your command-line
programs (@pxref{AWKPATH Variable}).
+Note that @command{gawk} treats each string as if it ended with
+a newline character (even if it doesn't). This makes building
+the total program easier.
+
+@quotation CAUTION
+At the moment, there is no requirement that each @var{program-text}
+be a full syntactic unit. I.e., the following currently works:
+
+@example
+$ @kbd{gawk -e 'BEGIN @{ a = 5 ;' -e 'print a @}'}
+@print{} 5
+@end example
+
+@noindent
+However, this could change in the future, so it's not a
+good idea to rely upon this feature.
+@end quotation
+
@item @option{-E} @var{file}
@itemx @option{--exec} @var{file}
@cindex @option{-E} option
@@ -3960,6 +4048,7 @@ when parsing numeric input data (@pxref{Locales}).
@cindex @option{-o} option
@cindex @option{--pretty-print} option
Enable pretty-printing of @command{awk} programs.
+Implies @option{--no-optimize}.
By default, the output program is created in a file named @file{awkprof.out}
(@pxref{Profiling}).
The optional @var{file} argument allows you to specify a different
@@ -3968,18 +4057,22 @@ No space is allowed between the @option{-o} and @var{file}, if
@var{file} is supplied.
@quotation NOTE
-Due to the way @command{gawk} has evolved, with this option
-your program still executes. This will change in the
-next major release, such that @command{gawk} will only
-pretty-print the program and not run it.
+In the past, this option would also execute your program.
+This is no longer the case.
@end quotation
@item @option{-O}
@itemx @option{--optimize}
@cindex @option{--optimize} option
@cindex @option{-O} option
-Enable some optimizations on the internal representation of the program.
-At the moment, this includes just simple constant folding.
+Enable @command{gawk}'s default optimizations on the internal
+representation of the program. At the moment, this includes simple
+constant folding and tail recursion elimination in function calls.
+
+These optimizations are enabled by default.
+This option remains primarily for backwards compatibility. However, it may
+be used to cancel the effect of an earlier @option{-s} option
+(see later in this list).
@item @option{-p}[@var{file}]
@itemx @option{--profile}[@code{=}@var{file}]
@@ -3988,6 +4081,7 @@ At the moment, this includes just simple constant folding.
@cindex @command{awk} profiling, enabling
Enable profiling of @command{awk} programs
(@pxref{Profiling}).
+Implies @option{--no-optimize}.
By default, profiles are created in a file named @file{awkprof.out}.
The optional @var{file} argument allows you to specify a different
@value{FN} for the profile file.
@@ -4017,11 +4111,6 @@ restrictions apply:
@cindex newlines
@cindex whitespace, newlines as
@item
-Newlines do not act as whitespace to separate fields when @code{FS} is
-equal to a single space
-(@pxref{Fields}).
-
-@item
Newlines are not allowed after @samp{?} or @samp{:}
(@pxref{Conditional Exp}).
@@ -4059,6 +4148,13 @@ This is now @command{gawk}'s default behavior.
Nevertheless, this option remains (both for backward compatibility
and for use in combination with @option{--traditional}).
+@item @option{-s}
+@itemx @option{--no-optimize}
+@cindex @option{--no-optimize} option
+@cindex @option{-s} option
+Disable @command{gawk}'s default optimizations on the internal
+representation of the program.
+
@item @option{-S}
@itemx @option{--sandbox}
@cindex @option{-S} option
@@ -4372,6 +4468,9 @@ searches first in the current directory and then in @file{/usr/local/share/awk}.
In practice, this means that you will rarely need to change the
value of @env{AWKPATH}.
+@xref{Shell Startup Files}, for information on functions that help to
+manipulate the @env{AWKPATH} variable.
+
@command{gawk} places the value of the search path that it used into
@code{ENVIRON["AWKPATH"]}. This provides access to the actual search
path value from within an @command{awk} program.
@@ -4403,6 +4502,9 @@ an empty value, @command{gawk} uses a default path; this
is typically @samp{/usr/local/lib/gawk}, although it can vary depending
upon how @command{gawk} was built.
+@xref{Shell Startup Files}, for information on functions that help to
+manipulate the @env{AWKLIBPATH} variable.
+
@command{gawk} places the value of the search path that it used into
@code{ENVIRON["AWKLIBPATH"]}. This provides access to the actual search
path value from within an @command{awk} program.
@@ -4430,6 +4532,8 @@ wait for input before returning with an error.
Controls the number of times @command{gawk} attempts to
retry a two-way TCP/IP (socket) connection before giving up.
@xref{TCP/IP Networking}.
+Note that when nonfatal I/O is enabled (@pxref{Nonfatal}),
+@command{gawk} only tries to open a TCP/IP socket once.
@item POSIXLY_CORRECT
Causes @command{gawk} to switch to POSIX-compatibility
@@ -4484,14 +4588,6 @@ two regexp matchers that @command{gawk} uses internally. (There aren't
supposed to be differences, but occasionally theory and practice don't
coordinate with each other.)
-@item GAWK_NO_PP_RUN
-When @command{gawk} is invoked with the @option{--pretty-print} option,
-it will not run the program if this environment variable exists.
-
-@quotation CAUTION
-This variable will not survive into the next major release.
-@end quotation
-
@item GAWK_STACKSIZE
This specifies the amount by which @command{gawk} should grow its
internal evaluation stack, when needed.
@@ -4789,6 +4885,13 @@ Similarly, you may use @code{print} or @code{printf} statements in the
@var{init} and @var{increment} parts of a @code{for} loop. This is another
long-undocumented ``feature'' of Unix @command{awk}.
+@command{gawk} lets you use the names of built-in functions that are
+@command{gawk} extensions as the names of parameters in user-defined functions.
+This is intended to ``future-proof'' old code that happens to use
+function names added by @command{gawk} after the code was written.
+Standard @command{awk} built-in functions, such as @code{sin()} or
+@code{substr()} are @emph{not} shadowed in this way.
+
@end ignore
@node Invoking Summary
@@ -5071,17 +5174,21 @@ 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}
-However, using more than two hexadecimal digits produces
-undefined results. (The @samp{\x} escape sequence is not allowed in
-POSIX @command{awk}.)
+or @samp{a}--@samp{f}). A maximum of two digts are allowed after
+the @samp{\x}. Any further hexadecimal digits are treated as simple
+letters or numbers. @value{COMMONEXT}
+(The @samp{\x} escape sequence is not allowed in POSIX awk.)
@quotation CAUTION
-The next major release of @command{gawk} will change, such
-that a maximum of two hexadecimal digits following the
-@samp{\x} will be used.
+In ISO C, the escape sequence continues until the first nonhexadecimal
+digit is seen.
+For many years, @command{gawk} would continue incorporating
+hexadecimal digits into the value until a non-hexadecimal digit
+or the end of the string was encountered.
+However, using more than two hexadecimal digits produced
+undefined results.
+As of @value{PVERSION} 4.2, only two digits
+are processed.
@end quotation
@cindex @code{\} (backslash), @code{\/} escape sequence
@@ -6096,10 +6203,13 @@ used with it do not have to be named on the @command{awk} command line
* Field Separators:: The field separator and how to change it.
* Constant Size:: Reading constant width data.
* Splitting By Content:: Defining Fields By Content
+* Testing field creation:: Checking how @command{gawk} is splitting
+ records.
* Multiple Line:: Reading multiline records.
* Getline:: Reading files under explicit program control
using the @code{getline} function.
* Read Timeout:: Reading input with a timeout.
+* Retrying Input:: Retrying input after certain errors.
* Command-line directories:: What happens if you put a directory on the
command line.
* Input Summary:: Input summary.
@@ -6417,16 +6527,12 @@ Readfile} for another option.
@cindex fields
@cindex accessing fields
@cindex fields, examining
-@cindex POSIX @command{awk}, field separators and
-@cindex field separators, POSIX and
-@cindex separators, field, POSIX and
When @command{awk} reads an input record, the record is
automatically @dfn{parsed} or separated by the @command{awk} utility into chunks
called @dfn{fields}. By default, fields are separated by @dfn{whitespace},
like words in a line.
Whitespace in @command{awk} means any string of one or more spaces,
-TABs, or newlines;@footnote{In POSIX @command{awk}, newlines are not
-considered whitespace for separating fields.} other characters
+TABs, or newlines; other characters
that are considered whitespace by other languages
(such as formfeed, vertical tab, etc.) are @emph{not} considered
whitespace by @command{awk}.
@@ -6840,7 +6946,6 @@ can massage it first with a separate @command{awk} program.)
@node Default Field Splitting
@subsection Whitespace Normally Separates Fields
-@cindex newlines, as field separators
@cindex whitespace, as field separators
Fields are normally separated by whitespace sequences
(spaces, TABs, and newlines), not by single spaces. Two spaces in a row do not
@@ -7241,18 +7346,30 @@ feature of @command{gawk}. If you are a novice @command{awk} user,
you might want to skip it on the first reading.
@command{gawk} provides a facility for dealing with fixed-width fields
-with no distinctive field separator. For example, data of this nature
-arises in the input for old Fortran programs where numbers are run
-together, or in the output of programs that did not anticipate the use
-of their output as input for other programs.
-
-An example of the latter is a table where all the columns are lined up by
-the use of a variable number of spaces and @emph{empty fields are just
-spaces}. Clearly, @command{awk}'s normal field splitting based on @code{FS}
-does not work well in this case. Although a portable @command{awk} program
-can use a series of @code{substr()} calls on @code{$0}
-(@pxref{String Functions}),
-this is awkward and inefficient for a large number of fields.
+with no distinctive field separator. We discuss this feature in
+the following @value{SUBSECTION}s.
+
+@menu
+* Fixed width data:: Processing fixed-width data.
+* Skipping intervening:: Skipping intervening fields.
+* Allowing trailing data:: Capturing optional trailing data.
+* Fields with fixed data:: Field values with fixed-width data.
+@end menu
+
+@node Fixed width data
+@subsection Processing Fixed-Width Data
+
+An example of fixed-width data would be the input for old Fortran programs
+where numbers are run together, or the output of programs that did not
+anticipate the use of their output as input for other programs.
+
+An example of the latter is a table where all the columns are lined up
+by the use of a variable number of spaces and @emph{empty fields are
+just spaces}. Clearly, @command{awk}'s normal field splitting based
+on @code{FS} does not work well in this case. Although a portable
+@command{awk} program can use a series of @code{substr()} calls on
+@code{$0} (@pxref{String Functions}), this is awkward and inefficient
+for a large number of fields.
@cindex troubleshooting, fatal errors, field widths@comma{} specifying
@cindex @command{w} utility
@@ -7260,11 +7377,12 @@ this is awkward and inefficient for a large number of fields.
@cindex @command{gawk}, @code{FIELDWIDTHS} variable in
The splitting of an input record into fixed-width fields is specified by
assigning a string containing space-separated numbers to the built-in
-variable @code{FIELDWIDTHS}. Each number specifies the width of the field,
-@emph{including} columns between fields. If you want to ignore the columns
-between fields, you can specify the width as a separate field that is
-subsequently ignored.
-It is a fatal error to supply a field width that has a negative value.
+variable @code{FIELDWIDTHS}. Each number specifies the width of the
+field, @emph{including} columns between fields. If you want to ignore
+the columns between fields, you can specify the width as a separate
+field that is subsequently ignored. It is a fatal error to supply a
+field width that has a negative value.
+
The following data is the output of the Unix @command{w} utility. It is useful
to illustrate the use of @code{FIELDWIDTHS}:
@@ -7294,7 +7412,7 @@ NR > 2 @{
sub(/^ +/, "", idle) # strip leading spaces
if (idle == "")
idle = 0
- if (idle ~ /:/) @{
+ if (idle ~ /:/) @{ # hh:mm
split(idle, t, ":")
idle = t[1] * 60 + t[2]
@}
@@ -7333,30 +7451,90 @@ program for processing such data could use the @code{FIELDWIDTHS} feature
to simplify reading the data. (Of course, getting @command{gawk} to run on
a system with card readers is another story!)
-@cindex @command{gawk}, splitting fields and
-Assigning a value to @code{FS} causes @command{gawk} to use
-@code{FS} for field splitting again. Use @samp{FS = FS} to make this happen,
-without having to know the current value of @code{FS}.
-In order to tell which kind of field splitting is in effect,
-use @code{PROCINFO["FS"]}
-(@pxref{Auto-set}).
-The value is @code{"FS"} if regular field splitting is being used,
-or @code{"FIELDWIDTHS"} if fixed-width field splitting is being used:
+@node Skipping intervening
+@subsection Skipping Intervening Fields
+
+Starting in @value{PVERSION} 4.2, each field width may optionally be
+preceded by a colon-separated value specifying the number of characters
+to skip before the field starts. Thus, the preceding program could be
+rewritten to specify @code{FIELDWIDTHS} like so:
@example
-if (PROCINFO["FS"] == "FS")
- @var{regular field splitting} @dots{}
-else if (PROCINFO["FS"] == "FIELDWIDTHS")
- @var{fixed-width field splitting} @dots{}
-else
- @var{content-based field splitting} @dots{} @ii{(see next @value{SECTION})}
+BEGIN @{ FIELDWIDTHS = "8 1:5 4:7 6 1:6 1:6 2:33" @}
+@end example
+
+This strips away some of the white space separating the fields. With such
+a change, the program produces the following results:
+
+@example
+hzang ttyV3 50
+eklye ttyV5 0
+dportein ttyV6 107
+gierd ttyD3 1
+dave ttyD4 0
+brent ttyp0 286
+dave ttyq4 1296000
@end example
-This information is useful when writing a function
-that needs to temporarily change @code{FS} or @code{FIELDWIDTHS},
-read some records, and then restore the original settings
-(@pxref{Passwd Functions}
-for an example of such a function).
+@node Allowing trailing data
+@subsection Capturing Optional Trailing Data
+
+There are times when fixed-width data may be followed by additional data
+that has no fixed length. Such data may or may not be present, but if
+it is, it should be possible to get at it from an @command{awk} program.
+
+Starting with version 4.2, in order to provide a way to say ``anything
+else in the record after the defined fields,'' @command{gawk}
+allows you to add a final @samp{*} character to the value of
+@code{FIELDWIDTHS}. There can only be one such character, and it must
+be the final non-whitespace character in @code{FIELDWIDTHS}.
+For example:
+
+@example
+$ @kbd{cat fw.awk} @ii{Show the program}
+@print{} BEGIN @{ FIELDWIDTHS = "2 2 *" @}
+@print{} @{ print NF, $1, $2, $3 @}
+$ @kbd{cat fw.in} @ii{Show sample input}
+@print{} 1234abcdefghi
+$ @kbd{gawk -f fw.awk fw.in} @ii{Run the program}
+@print{} 3 12 34 abcdefghi
+@end example
+
+@node Fields with fixed data
+@subsection Field Values With Fixed-Width Data
+
+So far, so good. But what happens if there isn't as much data as there
+should be based on the contents of @code{FIELDWIDTHS}? Or, what happens
+if there is more data than expected?
+
+For many years, what happens in these cases was not well defined. Starting
+with version 4.2, the rules are as follows:
+
+@table @asis
+@item Enough data for some fields
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4"} and the
+input record is @samp{aabbb}. In this case, @code{NF} is set to two.
+
+@item Not enough data for a field
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4"} and the
+input record is @samp{aab}. In this case, @code{NF} is set to two and
+@code{$2} has the value @code{"b"}. The idea is that even though there
+aren't as many characters as were expected, there are some, so the data
+should be made available to the program.
+
+@item Too much data
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4"} and the
+input record is @samp{aabbbccccddd}. In this case, @code{NF} is set to
+three and the extra characters (@samp{ddd}) are ignored. If you want
+@command{gawk} to capture the extra characters, supply a final @samp{*}
+in the value of @code{FIELDWIDTHS}.
+
+@item Too much data, but with @samp{*} supplied
+For example, if @code{FIELDWIDTHS} is set to @code{"2 3 4 *"} and the
+input record is @samp{aabbbccccddd}. In this case, @code{NF} is set to
+four, and @code{$4} has the value @code{"ddd"}.
+
+@end table
@node Splitting By Content
@section Defining Fields by Content
@@ -7457,8 +7635,6 @@ 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.
@quotation NOTE
Some programs export CSV data that contains embedded newlines between
@@ -7485,11 +7661,44 @@ 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.
-The mechanism used is based on which of the three
-variables---@code{FS}, @code{FIELDWIDTHS}, or @code{FPAT}---was
-last assigned to.
+
+@node Testing field creation
+@section Checking How @command{gawk} Is Splitting Records
+
+@cindex @command{gawk}, splitting fields and
+As we've seen, @command{gawk} provides three independent methods to split
+input records into fields. The mechanism used is based on which of the
+three variables---@code{FS}, @code{FIELDWIDTHS}, or @code{FPAT}---was
+last assigned to. In addition, an API input parser may choose to override
+the record parsing mechanism; please refer to @ref{Input Parsers} for
+further information about this feature.
+
+To restore normal field splitting after using @code{FIELDWIDTHS}
+and/or @code{FPAT}, simply assign a value to @code{FS}.
+You can use @samp{FS = FS} to do this,
+without having to know the current value of @code{FS}.
+
+In order to tell which kind of field splitting is in effect,
+use @code{PROCINFO["FS"]} (@pxref{Auto-set}).
+The value is @code{"FS"} if regular field splitting is being used,
+@code{"FIELDWIDTHS"} if fixed-width field splitting is being used,
+or @code{"FPAT"} if content-based field splitting is being used:
+
+@example
+if (PROCINFO["FS"] == "FS")
+ @var{regular field splitting} @dots{}
+else if (PROCINFO["FS"] == "FIELDWIDTHS")
+ @var{fixed-width field splitting} @dots{}
+else if (PROCINFO["FS"] == "FPAT")
+ @var{content-based field splitting}
+else
+ @var{API input parser field splitting} @dots{} @ii{(advanced feature)}
+@end example
+
+This information is useful when writing a function that needs to
+temporarily change @code{FS} or @code{FIELDWIDTHS}, read some records,
+and then restore the original settings (@pxref{Passwd Functions} for an
+example of such a function).
@node Multiple Line
@section Multiple-Line Records
@@ -7707,6 +7916,13 @@ a record, such as a file that cannot be opened, then @code{getline}
returns @minus{}1. In this case, @command{gawk} sets the variable
@code{ERRNO} to a string describing the error that occurred.
+If @code{ERRNO} indicates that the I/O operation may be
+retried, and @code{PROCINFO["@var{input}", "RETRY"]} is set,
+then @code{getline} returns @minus{}2
+instead of @minus{}1, and further calls to @code{getline}
+may be attempted. @xref{Retrying Input} for further information about
+this feature.
+
In the following examples, @var{command} stands for a string value that
represents a shell command.
@@ -8361,7 +8577,8 @@ on a per-command or per-connection basis.
the attempt to read from the underlying device may
succeed in a later attempt. This is a limitation, and it also
means that you cannot use this to multiplex input from
-two or more sources.
+two or more sources. @xref{Retrying Input} for a way to enable
+later I/O attempts to succeed.
Assigning a timeout value prevents read operations from
blocking indefinitely. But bear in mind that there are other ways
@@ -8371,6 +8588,36 @@ 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 Retrying Input
+@section Retrying Reads After Certain Input Errors
+@cindex retrying input
+
+@cindex differences in @command{awk} and @command{gawk}, retrying input
+This @value{SECTION} describes a feature that is specific to @command{gawk}.
+
+When @command{gawk} encounters an error while reading input, by
+default @code{getline} returns @minus{}1, and subsequent attempts to
+read from that file result in an end-of-file indication. However, you
+may optionally instruct @command{gawk} to allow I/O to be retried when
+certain errors are encountered by setting a special element in
+the @code{PROCINFO} array (@pxref{Auto-set}):
+
+@example
+PROCINFO["@var{input_name}", "RETRY"] = 1
+@end example
+
+When this element exists, @command{gawk} checks the value of the system
+(C language)
+@code{errno} variable when an I/O error occurs. If @code{errno} indicates
+a subsequent I/O attempt may succeed, @code{getline} instead returns
+@minus{}2 and
+further calls to @code{getline} may succeed. This applies to the @code{errno}
+values @code{EAGAIN}, @code{EWOULDBLOCK}, @code{EINTR}, or @code{ETIMEDOUT}.
+
+This feature is useful in conjunction with
+@code{PROCINFO["@var{input_name}", "READ_TIMEOUT"]} or situations where a file
+descriptor has been configured to behave in a non-blocking fashion.
+
@node Command-line directories
@section Directories on the Command Line
@cindex differences in @command{awk} and @command{gawk}, command-line directories
@@ -8532,6 +8779,7 @@ and discusses the @code{close()} built-in function.
@command{gawk} allows access to inherited file
descriptors.
* Close Files And Pipes:: Closing Input and Output Files and Pipes.
+* Nonfatal:: Enabling Nonfatal Output.
* Output Summary:: Output summary.
* Output Exercises:: Exercises.
@end menu
@@ -9912,17 +10160,26 @@ a system problem closing the file or process.
In these cases, @command{gawk} sets the predefined variable
@code{ERRNO} to a string describing the problem.
-In @command{gawk},
-when closing a pipe or coprocess (input or output),
-the return value is the exit status of the command.@footnote{
-This is a full 16-bit value as returned by the @code{wait()}
-system call. See the system manual pages for information on
-how to decode this value.}
-Otherwise, it is the return value from the system's @code{close()} or
-@code{fclose()} C functions when closing input or output
-files, respectively.
-This value is zero if the close succeeds, or @minus{}1 if
-it fails.
+In @command{gawk}, starting with @value{PVERSION} 4.2, when closing a pipe or
+coprocess (input or output), the return value is the exit status of the
+command, as described in @ref{table-close-pipe-return-values}.@footnote{Prior
+to @value{PVERSION} 4.2, the return value from closing a pipe or co-process
+was the full 16-bit exit value as defined by the @code{wait()} system
+call.} Otherwise, it is the return value from the system's @code{close()}
+or @code{fclose()} C functions when closing input or output files,
+respectively. This value is zero if the close succeeds, or @minus{}1
+if it fails.
+
+@float Table,table-close-pipe-return-values
+@caption{Return values from @code{close()} of a pipe}
+@multitable @columnfractions .40 .60
+@headitem Situation @tab Return value from @code{close()}
+@item Normal exit of command @tab Command's exit status
+@item Death by signal of command @tab 256 + number of murderous signal
+@item Death by signal of command with core dump @tab 512 + number of murderous signal
+@item Some kind of error @tab @minus{}1
+@end multitable
+@end float
The POSIX standard is very vague; it says that @code{close()}
returns zero on success and a nonzero value otherwise. In general,
@@ -9933,6 +10190,70 @@ In POSIX mode (@pxref{Options}), @command{gawk} just returns zero
when closing a pipe.
@end sidebar
+@node Nonfatal
+@section Enabling Nonfatal Output
+
+This @value{SECTION} describes a @command{gawk}-specific feature.
+
+In standard @command{awk}, output with @code{print} or @code{printf}
+to a nonexistent file, or some other I/O error (such as filling up the
+disk) is a fatal error.
+
+@example
+$ @kbd{gawk 'BEGIN @{ print "hi" > "/no/such/file" @}'}
+@error{} gawk: cmd. line:1: fatal: can't redirect to `/no/such/file' (No such file or directory)
+@end example
+
+@command{gawk} makes it possible to detect that an error has
+occurred, allowing you to possibly recover from the error, or
+at least print an error message of your choosing before exiting.
+You can do this in one of two ways:
+
+@itemize @bullet
+@item
+For all output files, by assigning any value to @code{PROCINFO["NONFATAL"]}.
+
+@item
+On a per-file basis, by assigning any value to
+@code{PROCINFO[@var{filename}, "NONFATAL"]}.
+Here, @var{filename} is the name of the file to which
+you wish output to be nonfatal.
+@end itemize
+
+Once you have enabled nonfatal output, you must check @code{ERRNO}
+after every relevant @code{print} or @code{printf} statement to
+see if something went wrong. It is also a good idea to initialize
+@code{ERRNO} to zero before attempting the output. For example:
+
+@example
+$ @kbd{gawk '}
+> @kbd{BEGIN @{}
+> @kbd{ PROCINFO["NONFATAL"] = 1}
+> @kbd{ ERRNO = 0}
+> @kbd{ print "hi" > "/no/such/file"}
+> @kbd{ if (ERRNO) @{}
+> @kbd{ print("Output failed:", ERRNO) > "/dev/stderr"}
+> @kbd{ exit 1}
+> @kbd{ @}}
+> @kbd{@}'}
+@error{} Output failed: No such file or directory
+@end example
+
+Here, @command{gawk} did not produce a fatal error; instead
+it let the @command{awk} program code detect the problem and handle it.
+
+This mechanism works also for standard output and standard error.
+For standard output, you may use @code{PROCINFO["-", "NONFATAL"]}
+or @code{PROCINFO["/dev/stdout", "NONFATAL"]}. For standard error, use
+@code{PROCINFO["/dev/stderr", "NONFATAL"]}.
+
+When attempting to open a TCP/IP socket (@pxref{TCP/IP Networking}),
+@command{gawk} tries multiple times. The @env{GAWK_SOCK_RETRIES}
+environment variable (@pxref{Other Environment Variables}) allows you to
+override @command{gawk}'s builtin default number of attempts. However,
+once nonfatal I/O is enabled for a given socket, @command{gawk} only
+retries once, relying on @command{awk}-level code to notice that there
+was a problem.
@node Output Summary
@section Summary
@@ -9962,6 +10283,12 @@ Use @code{close()} to close open file, pipe, and coprocess redirections.
For coprocesses, it is possible to close only one direction of the
communications.
+@item
+Normally errors with @code{print} or @code{printf} are fatal.
+@command{gawk} lets you make output errors be nonfatal either for
+all files or on a per-file basis. You must then check for errors
+after every relevant output statement.
+
@end itemize
@c EXCLUDE START
@@ -10109,7 +10436,7 @@ Just as @samp{11} in decimal is 1 times 10 plus 1, so
@samp{11} in octal is 1 times 8 plus 1. This equals 9 in decimal.
In hexadecimal, there are 16 digits. Because the everyday decimal
number system only has ten digits (@samp{0}--@samp{9}), the letters
-@samp{a} through @samp{f} are used to represent the rest.
+@samp{a} through @samp{f} represent the rest.
(Case in the letters is usually irrelevant; hexadecimal @samp{a} and @samp{A}
have the same value.)
Thus, @samp{11} in
@@ -10212,6 +10539,20 @@ but could be more complex expressions).
@node Using Constant Regexps
@subsection Using Regular Expression Constants
+Regular expression constants consist of text describing
+a regular expression enclosed in slashes (such as @code{/the +answer/}).
+This @value{SECTION} describes how such constants work in
+POSIX @command{awk} and @command{gawk}, and then goes on to describe
+@dfn{strongly typed regexp constants}, which are a @command{gawk} extension.
+
+@menu
+* Standard Regexp Constants:: Regexp constants in standard @command{awk}.
+* Strong Regexp Constants:: Strongly typed regexp constants.
+@end menu
+
+@node Standard Regexp Constants
+@subsubsection Standard Regular Expression Constants
+
@cindex dark corner, regexp constants
When used on the righthand side of the @samp{~} or @samp{!~}
operators, a regexp constant merely stands for the regexp that is to be
@@ -10319,6 +10660,90 @@ or not @code{$0} matches @code{/hi/}.
a parameter to a user-defined function, because passing a truth value in
this way is probably not what was intended.
+@node Strong Regexp Constants
+@subsubsection Strongly Typed Regexp Constants
+
+This @value{SECTION} describes a @command{gawk}-specific feature.
+
+As we saw in the previous @value{SECTION},
+regexp constants (@code{/@dots{}/}) hold a strange position in the
+@command{awk} language. In most contexts, they act like an expression:
+@samp{$0 ~ /@dots{}/}. In other contexts, they denote only a regexp to
+be matched. In no case are they really a ``first class citizen'' of the
+language. That is, you cannot define a scalar variable whose type is
+``regexp'' in the same sense that you can define a variable to be a
+number or a string:
+
+@example
+num = 42 @ii{Numeric variable}
+str = "hi" @ii{String variable}
+re = /foo/ @ii{Wrong!} re @ii{is the result of} $0 ~ /foo/
+@end example
+
+For a number of more advanced use cases,
+it would be nice to have regexp constants that
+are @dfn{strongly typed}; in other words, that denote a regexp useful
+for matching, and not an expression.
+
+@command{gawk} provides this feature. A strongly typed regexp constant
+looks almost like a regular regexp constant, except that it is preceded
+by an @samp{@@} sign:
+
+@example
+re = @@/foo/ @ii{Regexp variable}
+@end example
+
+Strongly typed regexp constants @emph{cannot} be used everywhere that a
+regular regexp constant can, because this would make the language even more
+confusing. Instead, you may use them only in certain contexts:
+
+@itemize @bullet
+@item
+On the righthand side of the @samp{~} and @samp{!~} operators: @samp{some_var ~ @@/foo/}
+(@pxref{Regexp Usage}).
+
+@item
+In the @code{case} part of a @code{switch} statement
+(@pxref{Switch Statement}).
+
+@item
+As an argument to one of the built-in functions that accept regexp constants:
+@code{gensub()},
+@code{gsub()},
+@code{match()},
+@code{patsplit()},
+@code{split()},
+and
+@code{sub()}
+(@pxref{String Functions}).
+
+@item
+As a parameter in a call to a user-defined function
+(@pxref{User-defined}).
+
+@item
+On the righthand side of an assignment to a variable: @samp{some_var = @@/foo/}.
+In this case, the type of @code{some_var} is regexp. Additionally, @code{some_var}
+can be used with @samp{~} and @samp{!~}, passed to one of the built-in functions
+listed above, or passed as a parameter to a user-defined function.
+@end itemize
+
+You may use the @code{typeof()} built-in function
+(@pxref{Type Functions})
+to determine if a variable or function parameter is
+a regexp variable.
+
+The true power of this feature comes from the ability to create variables that
+have regexp type. Such variables can be passed on to user-defined functions,
+without the confusing aspects of computed regular expressions created from
+strings or string constants. They may also be passed through indirect function
+calls (@pxref{Indirect Calls})
+and on to the built-in functions that accept regexp constants.
+
+When used in numeric conversions, strongly typed regexp variables convert
+to zero. When used in string conversions, they convert to the string
+value of the original regexp text.
+
@node Variables
@subsection Variables
@@ -11355,17 +11780,94 @@ compares variables.
@node Variable Typing
@subsubsection String Type versus Numeric Type
+Scalar objects in @command{awk} (variables, array elements, and fields)
+are @emph{dynamically} typed. This means their type can change as the
+program runs, from @dfn{untyped} before any use,@footnote{@command{gawk}
+calls this @dfn{unassigned}, as the following example shows.} to string
+or number, and then from string to number or number to string, as the
+program progresses. (@command{gawk} also provides regexp-typed scalars,
+but let's ignore that for now; @pxref{Strong Regexp Constants}.)
+
+You can't do much with untyped variables, other than tell that they
+are untyped. The following program tests @code{a} against @code{""}
+and @code{0}; the test succeeds when @code{a} has never been assigned
+a value. It also uses the built-in @code{typeof()} function
+(not presented yet; @pxref{Type Functions}) to show @code{a}'s type:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print (a == "" && a == 0 ?}
+> @kbd{"a is untyped" : "a has a type!") ; print typeof(a) @}'}
+@print{} a is untyped
+@print{} unassigned
+@end example
+
+A scalar has numeric type when assigned a numeric value,
+such as from a numeric constant, or from another scalar
+with numeric type:
+
+@example
+$ @kbd{gawk 'BEGIN @{ a = 42 ; print typeof(a)}
+> @kbd{b = a ; print typeof(b) @}'}
+number
+number
+@end example
+
+Similarly, a scalar has string type when assigned a string
+value, such as from a string constant, or from another scalar
+with string type:
+
+@example
+$ @kbd{gawk 'BEGIN @{ a = "forty two" ; print typeof(a)}
+> @kbd{b = a ; print typeof(b) @}'}
+string
+string
+@end example
+
+So far, this is all simple and straightforward. What happens, though,
+when @command{awk} has to process data from a user? Let's start with
+field data. What should the following command produce as output?
+
+@example
+echo hello | awk '@{ printf("%s %s < 42\n", $1,
+ ($1 < 42 ? "is" : "is not")) @}'
+@end example
+
+@noindent
+Since @samp{hello} is alphabetic data, @command{awk} can only do a string
+comparison. Internally, it converts @code{42} into @code{"42"} and compares
+the two string values @code{"hello"} and @code{"42"}. Here's the result:
+
+@example
+$ @kbd{echo hello | awk '@{ printf("%s %s < 42\n", $1,}
+> @kbd{ ($1 < 42 ? "is" : "is not")) @}'}
+@print{} hello is not < 42
+@end example
+
+However, what happens when data from a user @emph{looks like} a number?
+On the one hand, in reality, the input data consists of characters, not
+binary numeric
+values. But, on the other hand, the data looks numeric, and @command{awk}
+really ought to treat it as such. And indeed, it does:
+
+@example
+$ @kbd{echo 37 | awk '@{ printf("%s %s < 42\n", $1,}
+> @kbd{ ($1 < 42 ? "is" : "is not")) @}'}
+@print{} 37 is < 42
+@end example
+
+Here are the rules for when @command{awk}
+treats data as a number, and for when it treats data as a string.
+
@cindex numeric, strings
@cindex strings, numeric
@cindex POSIX @command{awk}, numeric strings and
-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 POSIX standard uses the term @dfn{numeric string} for input data that
+looks numeric. The @samp{37} in the previous example is a numeric string.
+So what is the type of a numeric string? Answer: numeric.
+The type of a variable is important because the types of two variables
+determine how they are compared.
+Variable typing follows these definitions and rules:
@itemize @value{BULLET}
@item
@@ -11380,7 +11882,9 @@ attribute.
Fields, @code{getline} input, @code{FILENAME}, @code{ARGV} elements,
@code{ENVIRON} elements, and the elements of an array created by
@code{match()}, @code{split()}, and @code{patsplit()} that are numeric
-strings have the @dfn{strnum} attribute. Otherwise, they have
+strings have the @dfn{strnum} attribute.@footnote{Thus, a POSIX
+numeric string and @command{gawk}'s strnum are the same thing.}
+Otherwise, they have
the @dfn{string} attribute. Uninitialized variables also have the
@dfn{strnum} attribute.
@@ -11454,7 +11958,7 @@ STRNUM &&string &numeric &numeric\cr
@end tex
@ifnottex
@ifnotdocbook
-@display
+@verbatim
+----------------------------------------------
| STRING NUMERIC STRNUM
--------+----------------------------------------------
@@ -11465,7 +11969,7 @@ NUMERIC | string numeric numeric
|
STRNUM | string numeric numeric
--------+----------------------------------------------
-@end display
+@end verbatim
@end ifnotdocbook
@end ifnottex
@docbook
@@ -11524,10 +12028,14 @@ purposes.
In short, when one operand is a ``pure'' string, such as a string
constant, then a string comparison is performed. Otherwise, a
numeric comparison is performed.
+(The primary difference between a number and a strnum is that
+for strnums @command{gawk} preserves the original string value that
+the scalar had when it came in.)
+
+This point bears additional emphasis:
+Input that looks numeric @emph{is} numeric.
+All other input is treated as strings.
-This point bears additional emphasis: All user input is made of characters,
-and so is first and foremost of string type; input strings
-that look numeric are additionally given the strnum attribute.
Thus, the six-character input string @w{@samp{ +3.14}} receives the
strnum attribute. In contrast, the eight characters
@w{@code{" +3.14"}} appearing in program text comprise a string constant.
@@ -11554,6 +12062,14 @@ $ @kbd{echo ' +3.14' | awk '@{ print($1 == 3.14) @}'} @ii{True}
@print{} 1
@end example
+You can see the type of an input field (or other user input)
+using @code{typeof()}:
+
+@example
+$ @kbd{echo hello 37 | gawk '@{ print typeof($1), typeof($2) @}'}
+@print{} string strnum
+@end example
+
@node Comparison Operators
@subsubsection Comparison Operators
@@ -11713,19 +12229,19 @@ One special place where @code{/foo/} is @emph{not} an abbreviation for
where this is discussed in more detail.
@node POSIX String Comparison
-@subsubsection String Comparison with POSIX Rules
+@subsubsection String Comparison Based on Locale Collating Order
-The POSIX standard says that string comparison is performed based
-on the locale's @dfn{collating order}. This is the order in which
-characters sort, as defined by the locale (for more discussion,
-@pxref{Locales}). This order is usually very different
-from the results obtained when doing straight character-by-character
-comparison.@footnote{Technically, string comparison is supposed
-to behave the same way as if the strings were compared with the C
-@code{strcoll()} function.}
+The POSIX standard used to say that all string comparisons are
+performed based on the locale's @dfn{collating order}. This
+is the order in which characters sort, as defined by the locale
+(for more discussion, @pxref{Locales}). This order is usually very
+different from the results obtained when doing straight byte-by-byte
+comparison.@footnote{Technically, string comparison is supposed to behave
+the same way as if the strings were compared with the C @code{strcoll()}
+function.}
Because this behavior differs considerably from existing practice,
-@command{gawk} only implements it when in POSIX mode (@pxref{Options}).
+@command{gawk} only implemented it when in POSIX mode (@pxref{Options}).
Here is an example to illustrate the difference, in an @code{en_US.UTF-8}
locale:
@@ -11738,6 +12254,26 @@ $ @kbd{gawk --posix 'BEGIN @{ printf("ABC < abc = %s\n",}
@print{} ABC < abc = FALSE
@end example
+Fortunately, as of August 2016, comparison based on locale
+collating order is no longer required for the @code{==} and @code{!=}
+operators.@footnote{See @uref{http://austingroupbugs.net/view.php?id=1070,
+the Austin Group website}.} However, comparison based on locales is still
+required for @code{<}, @code{<=}, @code{>}, and @code{>=}. POSIX thus
+recommends as follows:
+
+@quotation
+Since the @code{==} operator checks whether strings are identical,
+not whether they collate equally, applications needing to check whether
+strings collate equally can use:
+
+@example
+a <= b && a >= b
+@end example
+@end quotation
+
+As of @value{PVERSION} 4.2, @command{gawk} continues to use locale
+collating order for @code{<}, @code{<=}, @code{>}, and @code{>=} only
+in POSIX mode.
@node Boolean Ops
@subsection Boolean Expressions
@@ -13867,6 +14403,9 @@ Its default value is @code{"%.6g"}.
@item FIELDWIDTHS #
A space-separated list of columns that tells @command{gawk}
how to split input with fixed columnar boundaries.
+Starting in @value{PVERSION} 4.2, each field width may optionally be
+preceded by a colon-separated value specifying the number of characters to skip
+before the field starts.
Assigning a value to @code{FIELDWIDTHS}
overrides the use of @code{FS} and @code{FPAT} for field splitting.
@xref{Constant Size} for more information.
@@ -13897,12 +14436,11 @@ specify the behavior when @code{FS} is the null string.
Nonetheless, some other versions of @command{awk} also treat
@code{""} specially.)
-@cindex POSIX @command{awk}, @code{FS} variable and
The default value is @w{@code{" "}}, a string consisting of a single
-space. As a special exception, this value means that any
-sequence of spaces, TABs, and/or newlines is a single separator.@footnote{In
-POSIX @command{awk}, newline does not count as whitespace.} It also causes
-spaces, TABs, and newlines at the beginning and end of a record to be ignored.
+space. As a special exception, this value means that any sequence of
+spaces, TABs, and/or newlines is a single separator. It also causes
+spaces, TABs, and newlines at the beginning and end of a record to
+be ignored.
You can set the value of @code{FS} on the command line using the
@option{-F} option:
@@ -14126,10 +14664,24 @@ opens the next file.
An associative array containing the values of the environment. The array
indices are the environment variable names; the elements are the values of
the particular environment variables. For example,
-@code{ENVIRON["HOME"]} might be @code{"/home/arnold"}. Changing this array
-does not affect the environment passed on to any programs that
-@command{awk} may spawn via redirection or the @code{system()} function.
-(In a future version of @command{gawk}, it may do so.)
+@code{ENVIRON["HOME"]} might be @code{/home/arnold}.
+
+For POSIX @command{awk}, changing this array does not affect the
+environment passed on to any programs that @command{awk} may spawn via
+redirection or the @code{system()} function.
+
+However, beginning with @value{PVERSION} 4.2, if not in POSIX
+compatibility mode, @command{gawk} does update its own environment when
+@code{ENVIRON} is changed, thus changing the environment seen by programs
+that it creates. You should therefore be especially careful if you
+modify @code{ENVIRON["PATH"]}, which is the search path for finding
+executable programs.
+
+This can also affect the running @command{gawk} program, since some of the
+built-in functions may pay attention to certain environment variables.
+The most notable instance of this is @code{mktime()} (@pxref{Time
+Functions}), which pays attention the value of the @env{TZ} environment
+variable on many systems.
Some operating systems may not have environment variables.
On such systems, the @code{ENVIRON} array is empty (except for
@@ -14163,6 +14715,11 @@ value to be meaningful when an I/O operation returns a failure value,
such as @code{getline} returning @minus{}1. You are, of course, free
to clear it yourself before doing an I/O operation.
+If the value of @code{ERRNO} corresponds to a system error in the C
+@code{errno} variable, then @code{PROCINFO["errno"]} will be set to the value
+of @code{errno}. For non-system errors, @code{PROCINFO["errno"]} will
+be zero.
+
@cindex @code{FILENAME} variable
@cindex dark corner, @code{FILENAME} variable
@item @code{FILENAME}
@@ -14227,10 +14784,35 @@ The following elements (listed alphabetically)
are guaranteed to be available:
@table @code
+@item PROCINFO["argv"]
+@cindex command line arguments, @code{PROCINFO["argv"}
+The @code{PROCINFO["argv"]} array contains all of the command-line arguments
+(after glob expansion and redirection processing on platforms where that must
+be done manually by the program) with subscripts ranging from 0 through
+@code{argc} @minus{} 1. For example, @code{PROCINFO["argv"][0]} will contain
+the name by which @command{gawk} was invoked. Here is an example of how this
+feature may be used:
+
+@example
+gawk '
+BEGIN @{
+ for (i = 0; i < length(PROCINFO["argv"]); i++)
+ print i, PROCINFO["argv"][i]
+@}'
+@end example
+
+Please note that this differs from the standard @code{ARGV} array which does
+not include command-line arguments that have already been processed by
+@command{gawk} (@pxref{ARGC and ARGV}).
+
@cindex effective group ID of @command{gawk} user
@item PROCINFO["egid"]
The value of the @code{getegid()} system call.
+@item PROCINFO["errno"]
+The value of the C @code{errno} variable when @code{ERRNO} is set to
+the associated error message.
+
@item PROCINFO["euid"]
@cindex effective user ID of @command{gawk} user
The value of the @code{geteuid()} system call.
@@ -14239,7 +14821,8 @@ The value of the @code{geteuid()} system call.
This is
@code{"FS"} if field splitting with @code{FS} is in effect,
@code{"FIELDWIDTHS"} if field splitting with @code{FIELDWIDTHS} is in effect,
-or @code{"FPAT"} if field matching with @code{FPAT} is in effect.
+@code{"FPAT"} if field matching with @code{FPAT} is in effect,
+or @code{"API"} if field splitting is controlled by an API input parser.
@item PROCINFO["gid"]
@cindex group ID of @command{gawk} user
@@ -14354,6 +14937,14 @@ to test for these elements
The following elements allow you to change @command{gawk}'s behavior:
@table @code
+@item PROCINFO["NONFATAL"]
+If this element exists, then I/O errors for all output redirections become nonfatal.
+@xref{Nonfatal}.
+
+@item PROCINFO["@var{output_name}", "NONFATAL"]
+Make output errors for @var{output_name} be nonfatal.
+@xref{Nonfatal}.
+
@item PROCINFO["@var{command}", "pty"]
For two-way communication to @var{command}, use a pseudo-tty instead
of setting up a two-way pipe.
@@ -16248,6 +16839,27 @@ truncated toward zero.
For example, @code{int(3)} is 3, @code{int(3.9)} is 3, @code{int(-3.9)}
is @minus{}3, and @code{int(-3)} is @minus{}3 as well.
+@item @code{intdiv(@var{numerator}, @var{denominator}, @var{result})}
+@cindexawkfunc{intdiv}
+@cindex intdiv
+Perform integer division, similar to the standard C @code{div()} function.
+First, truncate @code{numerator} and @code{denominator}
+towards zero, creating integer values. Clear the @code{result}
+array, and then set @code{result["quotient"]} to the result of
+@samp{numerator / denominator}, truncated towards zero to an integer,
+and set @code{result["remainder"]} to the result of @samp{numerator %
+denominator}, truncated towards zero to an integer.
+Attempting division by zero causes a fatal error.
+The function returns zero upon success, and @minus{}1 upon error.
+
+This function is
+primarily intended for use with arbitrary length integers; it avoids
+creating MPFR arbitrary precision floating-point values (@pxref{Arbitrary
+Precision Integers}).
+
+This function is a @code{gawk} extension. It is not available in
+compatibility mode (@pxref{Options}).
+
@item @code{log(@var{x})}
@cindexawkfunc{log}
@cindex logarithm
@@ -16767,7 +17379,7 @@ using a third argument is a fatal error.
@cindexgawkfunc{patsplit}
@cindex split string into array
Divide
-@var{string} into pieces defined by @var{fieldpat}
+@var{string} into pieces (or ``fields'') defined by @var{fieldpat}
and store the pieces in @var{array} and the separator strings in the
@var{seps} array. The first piece is stored in
@code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so
@@ -16778,9 +17390,11 @@ It may be either a regexp constant or a string.
If @var{fieldpat} is omitted, the value of @code{FPAT} is used.
@code{patsplit()} returns the number of elements created.
@code{@var{seps}[@var{i}]} is
-the separator string
-between @code{@var{array}[@var{i}]} and @code{@var{array}[@var{i}+1]}.
-Any leading separator will be in @code{@var{seps}[0]}.
+the possibly null separator string
+after @code{@var{array}[@var{i}]}.
+The possibly null leading separator will be in @code{@var{seps}[0]}.
+So a non-null @var{string} with @var{n} fields will have @var{n+1} separators.
+A null @var{string} will not have neither fields nor separators.
The @code{patsplit()} function splits strings into pieces in a
manner similar to the way input lines are split into fields using @code{FPAT}
@@ -17733,7 +18347,7 @@ Optional parameters are enclosed in square brackets ([ ]):
@c @asis for docbook
@table @asis
-@item @code{mktime(@var{datespec})}
+@item @code{mktime(@var{datespec}} [@code{, @var{utc-flag}} ]@code{)}
@cindexgawkfunc{mktime}
@cindex generate time values
Turn @var{datespec} into a timestamp in the same form
@@ -17752,7 +18366,9 @@ The values of these numbers need not be within the ranges specified;
for example, an hour of @minus{}1 means 1 hour before midnight.
The origin-zero Gregorian calendar is assumed, with year 0 preceding
year 1 and year @minus{}1 preceding year 0.
-The time is assumed to be in the local time zone.
+If @var{utc-flag} is present and is either nonzero or non-null, the time
+is assumed to be in the UTC time zone; otherwise, the
+time is assumed to be in the local time zone.
If the daylight-savings flag is positive, the time is assumed to be
daylight savings time; if zero, the time is assumed to be standard
time; and if negative (the default), @code{mktime()} attempts to determine
@@ -18252,12 +18868,12 @@ Return the value of @var{val}, shifted right by @var{count} bits.
Return the bitwise XOR of the arguments. There must be at least two.
@end table
-For all of these functions, first the double-precision floating-point value is
-converted to the widest C unsigned integer type, then the bitwise operation is
-performed. If the result cannot be represented exactly as a C @code{double},
-leading nonzero bits are removed one by one until it can be represented
-exactly. The result is then converted back into a C @code{double}. (If
-you don't understand this paragraph, don't worry about it.)
+@quotation CAUTION
+Beginning with @command{gawk} @value{PVERSION} 4.2, negative
+operands are not allowed for any of these functions. A negative
+operand produces a fatal error. See the sidebar
+``Beware The Smoke and Mirrors!'' for more information as to why.
+@end quotation
Here is a user-defined function (@pxref{User-defined})
that illustrates the use of these functions:
@@ -18362,19 +18978,128 @@ decimal and octal values for the same numbers
and then demonstrates the
results of the @code{compl()}, @code{lshift()}, and @code{rshift()} functions.
+@sidebar Beware The Smoke and Mirrors!
+
+It other languages, bitwise operations are performed on integer values,
+not floating-point values. As a general statement, such operations work
+best when performed on unsigned integers.
+
+@command{gawk} attempts to treat the arguments to the bitwise functions
+as unsigned integers. For this reason, negative arguments produce a
+fatal error.
+
+In normal operation, for all of these functions, first the
+double-precision floating-point value is converted to the widest C
+unsigned integer type, then the bitwise operation is performed. If the
+result cannot be represented exactly as a C @code{double}, leading
+nonzero bits are removed one by one until it can be represented exactly.
+The result is then converted back into a C @code{double}.@footnote{If you don't
+understand this paragraph, the upshot is that @command{gawk} can only
+store a particular range of integer values; numbers outside that range
+are reduced to fit within the range.}
+
+However, when using arbitrary precision arithmetic with the @option{-M}
+option (@pxref{Arbitrary Precision Arithmetic}), the results may differ.
+This is particularly noticeable with the @code{compl()} function:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print compl(42) @}'}
+@print{} 9007199254740949
+$ @kbd{gawk -M 'BEGIN @{ print compl(42) @}'}
+@print{} -43
+@end example
+
+What's going on becomes clear when printing the results
+in hexadecimal:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0x1fffffffffffd5
+$ @kbd{gawk -M 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0xffffffffffffffd5
+@end example
+
+When using the @option{-M} option, under the hood, @command{gawk} uses
+GNU MP arbitrary precision integers which have at least 64 bits of precision.
+When not using @option{-M}, @command{gawk} stores integral values in
+regular double-precision floating point, which only maintain 53 bits of
+precision. Furthermore, the GNU MP library treats (or at least seems to treat)
+the leading bit as a sign bit; thus the result with @option{-M} in this case is
+a negative number.
+
+In short, using @command{gawk} for any but the simplest kind of bitwise
+operations is probably a bad idea; caveat emptor!
+
+@end sidebar
+
@node Type Functions
@subsection Getting Type Information
-@command{gawk} provides a single function that lets you distinguish
-an array from a scalar variable. This is necessary for writing code
+@command{gawk} provides two functions that let you distinguish
+the type of a variable.
+This is necessary for writing code
that traverses every element of an array of arrays
-(@pxref{Arrays of Arrays}).
+(@pxref{Arrays of Arrays}), and in other contexts.
@table @code
@cindexgawkfunc{isarray}
@cindex scalar or array
@item isarray(@var{x})
Return a true value if @var{x} is an array. Otherwise, return false.
+
+@cindexgawkfunc{typeof}
+@cindex variable type
+@cindex type, of variable
+@item typeof(@var{x})
+Return one of the following strings, depending upon the type of @var{x}:
+
+@c nested table
+@table @code
+@item "array"
+@var{x} is an array.
+
+@item "regexp"
+@var{x} is a strongly typed regexp (@pxref{Strong Regexp Constants}).
+
+@item "number"
+@var{x} is a number.
+
+@item "string"
+@var{x} is a string.
+
+@item "strnum"
+@var{x} is a number that started life as user input, such as a field or
+the result of calling @code{split()}. (I.e., @var{x} has the strnum
+attribute; @pxref{Variable Typing}.)
+
+@item "unassigned"
+@var{x} is a scalar variable that has not been assigned a value yet.
+For example:
+
+@example
+BEGIN @{
+ # creates a[1] but it has no assigned value
+ a[1]
+ print typeof(a[1]) # unassigned
+@}
+@end example
+
+@item "untyped"
+@var{x} has not yet been used yet at all; it can become a scalar or an
+array.
+For example:
+
+@example
+BEGIN @{
+ print typeof(x) # x never used --> untyped
+ mk_arr(x)
+ print typeof(x) # x now an array --> array
+@}
+
+function mk_arr(a) @{ a[1] = 1 @}
+@end example
+
+@end table
@end table
@code{isarray()} is meant for use in two circumstances. The first is when
@@ -18392,6 +19117,14 @@ that has not been previously used to @code{isarray()}, @command{gawk}
ends up turning it into a scalar.
@end quotation
+The @code{typeof()} function is general; it allows you to determine
+if a variable or function parameter is a scalar, an array, or a strongly
+typed regexp.
+
+@code{isarray()} is deprecated; you should use @code{typeof()} instead.
+You should replace any existing uses of @samp{isarray(var)} in your
+code with @samp{typeof(var) == "array"}.
+
@node I18N Functions
@subsection String-Translation Functions
@cindex @command{gawk}, string-translation functions
@@ -26622,9 +27355,16 @@ your program to hang. (Thus, this particular feature is of much less
use in practice than being able to close the @code{"to"} end.)
@quotation CAUTION
-It is a fatal error to write to the @code{"to"} end of a two-way
-pipe which has been closed. It is also a fatal error to read
+Normally,
+it is a fatal error to write to the @code{"to"} end of a two-way
+pipe which has been closed, and it is also a fatal error to read
from the @code{"from"} end of a two-way pipe that has been closed.
+
+You may set @code{PROCINFO["@var{command}", "NONFATAL"]} to
+make such operations become nonfatal. If you do so, you then need
+to check @code{ERRNO} after each @code{print}, @code{printf},
+or @code{getline}.
+@xref{Nonfatal}, for more information.
@end quotation
@cindex @command{gawk}, @code{PROCINFO} array in
@@ -27008,8 +27748,7 @@ The profiled version of your program may not look exactly like what you
typed when you wrote it. This is because @command{gawk} creates the
profiled version by ``pretty-printing'' its internal representation of
the program. The advantage to this is that @command{gawk} can produce
-a standard representation. The disadvantage is that all source code
-comments are lost.
+a standard representation.
Also, things such as:
@example
@@ -27103,10 +27842,39 @@ When called this way, @command{gawk} ``pretty-prints'' the program into
@file{awkprof.out}, without any execution counts.
@quotation NOTE
-The @option{--pretty-print} option still runs your program.
-This will change in the next major release.
+Once upon a time, the @option{--pretty-print} option would also run
+your program. This is is no longer the case.
@end quotation
+There is a significant difference between the output created when
+profiling, and that created when pretty-printing. Pretty-printed output
+preserves the original comments that were in the program, although their
+placement may not correspond exactly to their original locations in the
+source code.@footnote{@command{gawk} does the best it can to preserve
+the distinction between comments at the end of a statement and comments
+on lines by themselves. Due to implementation constraints, it does not
+always do so correctly, particularly for @code{switch} statements. The
+@command{gawk} maintainers hope to improve this in a subsequent
+release.}
+
+However, as a deliberate design decision, profiling output @emph{omits}
+the original program's comments. This allows you to focus on the
+execution count data and helps you avoid the temptation to use the
+profiler for pretty-printing.
+
+Additionally, pretty-printed output does not have the leading indentation
+that the profiling output does. This makes it easy to pretty-print your
+code once development is completed, and then use the result as the final
+version of your program.
+
+Because the internal representation of your program is formatted to
+recreate an @command{awk} program, profiling and pretty-printing
+automatically disable @command{gawk}'s default optimizations.
+
+Pretty printing also preserves the original format of numeric
+constants; if you used an octal or hexadecimal value in your source
+code, it will appear that way in the output.
+
@node Advanced Features Summary
@section Summary
@@ -27147,8 +27915,7 @@ you tune them more easily. Sending the @code{USR1} signal while profiling cause
@command{gawk} to dump the profile and keep going, including a function call stack.
@item
-You can also just ``pretty-print'' the program. This currently also runs
-the program, but that will change in the next major release.
+You can also just ``pretty-print'' the program.
@end itemize
@@ -29341,6 +30108,68 @@ The @command{gawk} debugger only accepts source code supplied with the @option{-
@end itemize
@ignore
+@c 11/2016: This no longer applies after all the type cleanup work that's been done.
+One other point is worth discussing. Conventional debuggers run in a
+separate process (and thus address space) from the programs that they
+debug (the @dfn{debuggee}, if you will).
+
+The @command{gawk} debugger is different; it is an integrated part
+of @command{gawk} itself. This makes it possible, in rare cases,
+for @command{gawk} to become an excellent demonstrator of Heisenberg
+Uncertainty physics, where the mere act of observing something can change
+it. Consider the following:@footnote{Thanks to Hermann Peifer for
+this example.}
+
+@example
+$ @kbd{cat test.awk}
+@print{} @{ print typeof($1), typeof($2) @}
+$ @kbd{cat test.data}
+@print{} abc 123
+$ @kbd{gawk -f test.awk test.data}
+@print{} strnum strnum
+@end example
+
+This is all as expected: field data has the STRNUM attribute
+(@pxref{Variable Typing}). Now watch what happens when we run
+this program under the debugger:
+
+@example
+$ @kbd{gawk -D -f test.awk test.data}
+gawk> @kbd{w $1} @ii{Set watchpoint on} $1
+@print{} Watchpoint 1: $1
+gawk> @kbd{w $2} @ii{Set watchpoint on} $2
+@print{} Watchpoint 2: $2
+gawk> @kbd{r} @ii{Start the program}
+@print{} Starting program:
+@print{} Stopping in Rule ...
+@print{} Watchpoint 1: $1 @ii{Watchpoint fires}
+@print{} Old value: ""
+@print{} New value: "abc"
+@print{} main() at `test.awk':1
+@print{} 1 @{ print typeof($1), typeof($2) @}
+gawk> @kbd{n} @ii{Keep going @dots{}}
+@print{} Watchpoint 2: $2 @ii{Watchpoint fires}
+@print{} Old value: ""
+@print{} New value: "123"
+@print{} main() at `test.awk':1
+@print{} 1 @{ print typeof($1), typeof($2) @}
+gawk> @kbd{n} @ii{Get result from} typeof()
+@print{} strnum number @ii{Result for} $2 @ii{isn't right}
+@print{} Program exited normally with exit value: 0
+gawk> @kbd{quit}
+@end example
+
+In this case, the act of comparing the new value of @code{$2}
+with the old one caused @command{gawk} to evaluate it and determine that it
+is indeed a number, and this is reflected in the result of
+@code{typeof()}.
+
+Cases like this where the debugger is not transparent to the program's
+execution should be rare. If you encounter one, please report it
+(@pxref{Bugs}).
+@end ignore
+
+@ignore
Look forward to a future release when these and other missing features may
be added, and of course feel free to try to add them yourself!
@end ignore
@@ -29376,6 +30205,10 @@ If the GNU Readline library is available when @command{gawk} is
compiled, it is used by the debugger to provide command-line history
and editing.
+@item
+Usually, the debugger does not not affect the
+program being debugged, but occasionally it can.
+
@end itemize
@node Arbitrary Precision Arithmetic
@@ -29408,6 +30241,7 @@ this is the place to be.
* FP Math Caution:: Things to know.
* Arbitrary Precision Integers:: Arbitrary Precision Integer Arithmetic with
@command{gawk}.
+* Checking for MPFR:: How to check if MPFR is available.
* POSIX Floating Point Problems:: Standards Versus Existing Practice.
* Floating point summary:: Summary of floating point discussion.
@end menu
@@ -30193,6 +31027,174 @@ to just use the following:
gawk -M 'BEGIN @{ n = 13; print n % 2 @}'
@end example
+When dividing two arbitrary precision integers with either
+@samp{/} or @samp{%}, the result is typically an arbitrary
+precision floating point value (unless the denominator evenly
+divides into the numerator). In order to do integer division
+or remainder with arbitrary precision integers, use the built-in
+@code{intdiv()} function (@pxref{Numeric Functions}).
+
+You can simulate the @code{intdiv()} function in standard @command{awk}
+using this user-defined function:
+
+@example
+@c file eg/lib/intdiv.awk
+# intdiv --- do integer division
+
+@c endfile
+@ignore
+@c file eg/lib/intdiv.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# July, 2014
+#
+# Name changed from div() to intdiv()
+# April, 2015
+
+@c endfile
+
+@end ignore
+@c file eg/lib/intdiv.awk
+function intdiv(numerator, denominator, result)
+@{
+ split("", result)
+
+ numerator = int(numerator)
+ denominator = int(denominator)
+ result["quotient"] = int(numerator / denominator)
+ result["remainder"] = int(numerator % denominator)
+
+ return 0.0
+@}
+@c endfile
+@end example
+
+The following example program, contributed by Katie Wasserman,
+uses @code{intdiv()} to
+compute the digits of @value{PI} to as many places as you
+choose to set:
+
+@example
+@c file eg/prog/pi.awk
+# pi.awk --- compute the digits of pi
+@c endfile
+@c endfile
+@ignore
+@c file eg/prog/pi.awk
+#
+# Katie Wasserman, katie@@wass.net
+# August 2014
+@c endfile
+@end ignore
+@c file eg/prog/pi.awk
+
+BEGIN @{
+ digits = 100000
+ two = 2 * 10 ^ digits
+ pi = two
+ for (m = digits * 4; m > 0; --m) @{
+ d = m * 2 + 1
+ x = pi * m
+ intdiv(x, d, result)
+ pi = result["quotient"]
+ pi = pi + two
+ @}
+ print pi
+@}
+@c endfile
+@end example
+
+@ignore
+Date: Wed, 20 Aug 2014 10:19:11 -0400
+To: arnold@skeeve.com
+From: Katherine Wasserman <katie@wass.net>
+Subject: Re: computation of digits of pi?
+
+Arnold,
+
+>The program that you sent to compute the digits of pi using div(). Is
+>that some standard algorithm that every math student knows? If so,
+>what's it called?
+
+It's not that well known but it's not that obscure either
+
+It's Euler's modification to Newton's method for calculating pi.
+
+Take a look at lines (23) - (25) here: http://mathworld.wolfram.com/PiFormulas.htm
+
+The algorithm I wrote simply expands the multiply by 2 and works from the innermost expression outwards. I used this to program HP calculators because it's quite easy to modify for tiny memory devices with smallish word sizes.
+
+http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899
+
+-Katie
+@end ignore
+
+When asked about the algorithm used, Katie replied:
+
+@quotation
+It's not that well known but it's not that obscure either.
+It's Euler's modification to Newton's method for calculating pi.
+Take a look at lines (23) - (25) here: @uref{http://mathworld.wolfram.com/PiFormulas.html}.
+
+The algorithm I wrote simply expands the multiply by 2 and works from
+the innermost expression outwards. I used this to program HP calculators
+because it's quite easy to modify for tiny memory devices with smallish
+word sizes. See
+@uref{http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899}.
+@end quotation
+
+@node Checking for MPFR
+@section How To Check If MPFR Is Available
+
+@cindex MPFR, checking availability of
+@cindex checking for MPFR
+Occasionally, you might like to be able to check if @command{gawk}
+was invoked with the @option{-M} option, enabling arbitrary-precision
+arithmetic. You can do so with the following function, contributed
+by Andrew Schorr:
+
+@example
+@c file eg/lib/have_mpfr.awk
+# adequate_math_precision --- return true if we have enough bits
+@c endfile
+@ignore
+@c file eg/lib/have_mpfr.awk
+#
+# Andrew Schorr, aschorr@@telemetry-investments.com, Public Domain
+# May 2017
+@c endfile
+@end ignore
+@c file eg/lib/have_mpfr.awk
+
+function adequate_math_precision(n)
+@{
+ return (1 != (1+(1/(2^(n-1)))))
+@}
+@c endfile
+@end example
+
+Here is code that invokes the function in order to check
+if arbitrary-precision arithmetic is available:
+
+@example
+BEGIN @{
+ # How many bits of mantissa precision are required
+ # for this program to function properly?
+ fpbits = 123
+
+ # We hope that we were invoked with MPFR enabled. If so, the
+ # following statement should configure calculations to our desired
+ # precision.
+ PREC = fpbits
+
+ if (! adequate_math_precision(fpbits)) @{
+ print("Error: insufficient computation precision available.\n" \
+ "Try again with the -M argument?") > "/dev/stderr"
+ exit 1
+ @}
+@}
+@end example
+
@node POSIX Floating Point Problems
@section Standards Versus Existing Practice
@@ -30592,8 +31594,11 @@ This (rather large) @value{SECTION} describes the API in detail.
* Symbol Table Access:: Functions for accessing global
variables.
* Array Manipulation:: Functions for working with arrays.
+* Redirection API:: How to access and manipulate
+ redirections.
* Extension API Variables:: Variables provided by the API.
* Extension API Boilerplate:: Boilerplate code for using the API.
+* Changes from API V1:: Changes from V1 of the API.
@end menu
@node Extension API Functions Introduction
@@ -30667,6 +31672,10 @@ Clearing an array
@item
Flattening an array for easy C-style looping over all its indices and elements
@end itemize
+
+@item
+Accessing and manipulating redirections.
+
@end itemize
Some points about using the API:
@@ -30720,14 +31729,26 @@ and is managed by @command{gawk} from then on.
The API defines several simple @code{struct}s that map values as seen
from @command{awk}. A value can be a @code{double}, a string, or an
array (as in multidimensional arrays, or when creating a new array).
+
String values maintain both pointer and length, because embedded @sc{nul}
characters are allowed.
@quotation NOTE
-By intent, strings are maintained using the current multibyte encoding (as
-defined by @env{LC_@var{xxx}} environment variables) and not using wide
-characters. This matches how @command{gawk} stores strings internally
-and also how characters are likely to be input into and output from files.
+By intent, @command{gawk} maintains strings using the current multibyte
+encoding (as defined by @env{LC_@var{xxx}} environment variables)
+and not using wide characters. This matches how @command{gawk} stores
+strings internally and also how characters are likely to be input into
+and output from files.
+@end quotation
+
+@quotation NOTE
+String values passed to an extension by @command{gawk} are always
+@sc{nul}-terminated. Thus it is safe to pass such string values to
+standard library and system routines. However, because @command{gawk}
+allows embedded @sc{nul} characters in string data, before using the data
+as a regular C string, you should check that the length for that string
+passed to the extension matches the return value of @code{strlen()}
+for it.
@end quotation
@item
@@ -30810,6 +31831,8 @@ multibyte encoding.
@itemx @ @ @ @ AWK_UNDEFINED,
@itemx @ @ @ @ AWK_NUMBER,
@itemx @ @ @ @ AWK_STRING,
+@itemx @ @ @ @ AWK_REGEX,
+@itemx @ @ @ @ AWK_STRNUM,
@itemx @ @ @ @ AWK_ARRAY,
@itemx @ @ @ @ AWK_SCALAR,@ @ @ @ @ @ @ @ @ /* opaque access to a variable */
@itemx @ @ @ @ AWK_VALUE_COOKIE@ @ @ @ /* for updating a previously created value */
@@ -30832,6 +31855,8 @@ The @code{val_type} member indicates what kind of value the
@code{union} holds, and each member is of the appropriate type.
@item #define str_value@ @ @ @ @ @ u.s
+@itemx #define strnum_value@ @ @ str_value
+@itemx #define regex_value@ @ @ @ str_value
@itemx #define num_value@ @ @ @ @ @ u.d
@itemx #define array_cookie@ @ @ u.a
@itemx #define scalar_cookie@ @ u.scl
@@ -30852,7 +31877,7 @@ and in more detail in @ref{Cached values}.
@end table
-Scalar values in @command{awk} are either numbers or strings. The
+Scalar values in @command{awk} are numbers, strings, strnums, or typed regexps. The
@code{awk_value_t} struct represents values. The @code{val_type} member
indicates what is in the @code{union}.
@@ -30861,6 +31886,26 @@ require more work. Because @command{gawk} allows embedded @sc{nul} bytes
in string values, a string must be represented as a pair containing a
data pointer and length. This is the @code{awk_string_t} type.
+A strnum (numeric string) value is represented as a string and consists
+of user input data that appears to be numeric.
+When an extension creates a strnum value, the result is a string flagged
+as user input. Subsequent parsing by @command{gawk} then determines whether it
+looks like a number and should be treated as a strnum, or as a regular string.
+
+This is useful in cases where an extension function would like to do something
+comparable to the @code{split()} function which sets the strnum attribute
+on the array elements it creates. For example, an extension that implements
+CSV splitting would want to use this feature. This is also useful for a
+function that retrieves a data item from a database. The PostgreSQL
+@code{PQgetvalue()} function, for example, returns a string that may be numeric
+or textual depending on the contents.
+
+Typed regexp values (@pxref{Strong Regexp Constants}) are not of
+much use to extension functions. Extension functions can tell that
+they've received them, and create them for scalar values. Otherwise,
+they can examine the text of the regexp through @code{regex_value.str}
+and @code{regex_value.len}.
+
Identifiers (i.e., the names of global variables) can be associated
with either scalar values or with arrays. In addition, @command{gawk}
provides true arrays of arrays, where any given array element can
@@ -30947,8 +31992,8 @@ to use its version of @code{free()} when the memory came from an
unrelated version of @code{malloc()}, unexpected behavior would
likely result.
-Two convenience macros may be used for allocating storage
-from @code{gawk_malloc()} and
+Three convenience macros may be used for allocating storage
+from @code{gawk_malloc()}, @code{gawk_calloc}, and
@code{gawk_realloc()}. If the allocation fails, they cause @command{gawk}
to exit with a fatal error message. They should be used as if they were
procedure calls that do not return a value:
@@ -30987,6 +32032,12 @@ strcpy(message, greet);
make_malloced_string(message, strlen(message), & result);
@end example
+@item #define ezalloc(pointer, type, size, message) @dots{}
+This is like @code{emalloc()}, but it calls @code{gawk_calloc()}
+instead of @code{gawk_malloc()}.
+The arguments are the same as for the @code{emalloc()} macro, but this
+macro guarantees that the memory returned is initialized to zero.
+
@item #define erealloc(pointer, type, size, message) @dots{}
This is like @code{emalloc()}, but it calls @code{gawk_realloc()}
instead of @code{gawk_malloc()}.
@@ -31027,6 +32078,31 @@ It returns @code{result}.
@itemx make_number(double num, awk_value_t *result);
This function simply creates a numeric value in the @code{awk_value_t} variable
pointed to by @code{result}.
+
+@item static inline awk_value_t *
+@itemx make_const_user_input(const char *string, size_t length, awk_value_t *result);
+This function is identical to @code{make_const_string()}, but the string is
+flagged as user input that should be treated as a strnum value if the contents
+of the string are numeric.
+
+@item static inline awk_value_t *
+@itemx make_malloced_user_input(const char *string, size_t length, awk_value_t *result);
+This function is identical to @code{make_malloced_string()}, but the string is
+flagged as user input that should be treated as a strnum value if the contents
+of the string are numeric.
+
+@item static inline awk_value_t *
+@itemx make_const_regex(const char *string, size_t length, awk_value_t *result);
+This function creates a strongly typed regexp value by allocating a copy of the string.
+@code{string} is the regular expression of length @code{len}.
+
+@item static inline awk_value_t *
+@itemx make_malloced_regex(const char *string, size_t length, awk_value_t *result);
+This function creates a strongly typed regexp value. @code{string} is
+the regular expression of length @code{len}. It expects @code{string}
+to be a @samp{char *} value pointing to data previously obtained from
+@code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()}.
+
@end table
@node Registration Functions
@@ -31054,8 +32130,13 @@ Extension functions are described by the following record:
@example
typedef struct awk_ext_func @{
@ @ @ @ const char *name;
-@ @ @ @ awk_value_t *(*function)(int num_actual_args, awk_value_t *result);
-@ @ @ @ size_t num_expected_args;
+@ @ @ @ awk_value_t *(*const function)(int num_actual_args,
+@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result,
+@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo);
+@ @ @ @ const size_t max_expected_args;
+@ @ @ @ const size_t min_required_args;
+@ @ @ @ awk_bool_t suppress_lint;
+@ @ @ @ void *data; /* opaque pointer to any extra state */
@} awk_ext_func_t;
@end example
@@ -31073,36 +32154,94 @@ or an underscore, which may be followed by any number of
letters, digits, and underscores.
Letter case in function names is significant.
-@item awk_value_t *(*function)(int num_actual_args, awk_value_t *result);
+@item awk_value_t *(*const function)(int num_actual_args,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *result,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo);
This is a pointer to the C function that provides the extension's
functionality.
-The function must fill in @code{*result} with either a number
-or a string. @command{gawk} takes ownership of any string memory.
+The function must fill in @code{*result} with either a number,
+a string, or a regexp.
+@command{gawk} takes ownership of any string memory.
As mentioned earlier, string memory @emph{must} come from one of
@code{gawk_malloc()}, @code{gawk_calloc()}, or @code{gawk_realloc()}.
The @code{num_actual_args} argument tells the C function how many
actual parameters were passed from the calling @command{awk} code.
+The @code{finfo} parameter is a pointer to the @code{awk_ext_func_t} for
+this function. The called function may access data within it as desired, or not.
+
The function must return the value of @code{result}.
This is for the convenience of the calling code inside @command{gawk}.
-@item size_t num_expected_args;
-This is the number of arguments the function expects to receive.
-Each extension function may decide what to do if the number of
-arguments isn't what it expected. As with real @command{awk} functions, it
-is likely OK to ignore extra arguments.
+@item const size_t max_expected_args;
+This is the maximum number of arguments the function expects to receive.
+If called with more arguments than this, and if lint checking has
+been enabled, then @command{gawk} prints a warning message. For more
+information, see the entry for @code{suppress_lint}, later in this list.
+
+@item const size_t min_required_args;
+This is the minimum number of arguments the function expects to receive.
+If called with fewer arguments, @command{gawk} prints a fatal error
+message and exits.
+
+@item awk_bool_t suppress_lint;
+This flag tells @command{gawk} not to print a lint message if lint
+checking has been enabled and if more arguments were supplied in the call
+than expected. An extension function can tell if @command{gawk} already
+printed at least one such message by checking if @samp{num_actual_args >
+finfo->max_expected_args}. If so, and the function does not want more
+lint messages to be printed, it should set @code{finfo->suppress_lint}
+to @code{awk_true}.
+
+@item void *data;
+This is an opaque pointer to any data that an extension function may
+wish to have available when called. Passing the @code{awk_ext_func_t}
+structure to the extension function, and having this pointer available
+in it enable writing a single C or C++ function that implements multiple
+@command{awk}-level extension functions.
@end table
Once you have a record representing your extension function, you register
it with @command{gawk} using this API function:
@table @code
-@item awk_bool_t add_ext_func(const char *namespace, const awk_ext_func_t *func);
+@item awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func);
This function returns true upon success, false otherwise.
The @code{namespace} parameter is currently not used; you should pass in an
empty string (@code{""}). The @code{func} pointer is the address of a
@code{struct} representing your function, as just described.
+
+@command{gawk} does not modify what @code{func} points to, but the
+extension function itself receives this pointer and can modify what it
+points to, thus it is purposely not declared to be @code{const}.
+@end table
+
+The combination of @code{min_required_args}, @code{max_expected_args},
+and @code{suppress_lint} may be confusing. Here is how you should
+set things up.
+
+@table @asis
+@item Any number of arguments is valid
+Set @code{min_required_args} and @code{max_expected_args} to zero and
+set @code{suppress_lint} to @code{awk_true}.
+
+@item A minimum number of arguments is required, no limit on maximum number of arguments
+Set @code{min_required_args} to the minimum required. Set
+@code{max_expected_args} to zero and
+set @code{suppress_lint} to @code{awk_true}.
+
+@item A minimum number of arguments is required, a maximum number is expected
+Set @code{min_required_args} to the minimum required. Set
+@code{max_expected_args} to the maximum expected.
+Set @code{suppress_lint} to @code{awk_false}.
+
+@item A minimum number of arguments is required, and no more than a maximum is allowed
+Set @code{min_required_args} to the minimum required. Set
+@code{max_expected_args} to the maximum expected.
+Set @code{suppress_lint} to @code{awk_false}.
+In your extension function, check that @code{num_actual_args} does not
+exceed @code{f->max_expected_args}. If it does, issue a fatal error message.
@end table
@node Exit Callback Functions
@@ -31242,7 +32381,8 @@ typedef struct awk_input @{
#define INVALID_HANDLE (-1)
void *opaque; /* private data for input parsers */
int (*get_record)(char **out, struct awk_input *iobuf,
- int *errcode, char **rt_start, size_t *rt_len);
+ int *errcode, char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **field_width);
ssize_t (*read_func)();
void (*close_func)(struct awk_input *iobuf);
struct stat sbuf; /* stat buf */
@@ -31294,7 +32434,8 @@ is not required to use this pointer.
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct@ awk_input *iobuf,
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int *errcode,
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ char **rt_start,
-@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t *rt_len);
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t *rt_len,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_fieldwidth_info_t **field_width);
This function pointer should point to a function that creates the input
records. Said function is the core of the input parser. Its behavior
is described in the text following this list.
@@ -31346,6 +32487,21 @@ If the concept of a ``record terminator'' makes sense, then
data. Otherwise, @code{*rt_len} should be set to zero.
@command{gawk} makes its own copy of this data, so the
extension must manage this storage.
+
+@item const awk_fieldwidth_info_t **field_width
+If @code{field_width} is not @code{NULL}, then @code{*field_width} will be initialized
+to @code{NULL}, and the function may set it to point to a structure
+supplying field width information to override the default
+field parsing mechanism. Note that this structure will not
+be copied by @command{gawk}; it must persist at least until the next call
+to @code{get_record} or @code{close_func}. Note also that @code{field_width} is
+@code{NULL} when @code{getline} is assigning the results to a variable, thus
+field parsing is not needed. If the parser does set @code{*field_width},
+then @command{gawk} uses this layout to parse the input record,
+and the @code{PROCINFO["FS"]} value will be @code{"API"} while this record
+is active in @code{$0}.
+The @code{awk_fieldwidth_info_t} data structure
+is described below.
@end table
The return value is the length of the buffer pointed to by
@@ -31404,6 +32560,50 @@ Register the input parser pointed to by @code{input_parser} with
@command{gawk}.
@end table
+If you would like to override the default field parsing mechanism for a given
+record, then you must populate an @code{awk_fieldwidth_info_t} structure,
+which looks like this:
+
+@example
+typedef struct @{
+ awk_bool_t use_chars; /* false ==> use bytes */
+ size_t nf; /* number of fields in record (NF) */
+ struct awk_field_info @{
+ size_t skip; /* amount to skip before field starts */
+ size_t len; /* length of field */
+ @} fields[1]; /* actual dimension should be nf */
+@} awk_fieldwidth_info_t;
+@end example
+
+The fields are:
+
+@table @code
+@item awk_bool_t use_chars;
+Set this to @code{awk_true} if the field lengths are specified in terms
+of potentially multi-byte characters, and set it to @code{awk_false} if
+the lengths are in terms of bytes.
+Performance will be better if the values are supplied in
+terms of bytes.
+
+@item size_t nf;
+Set this to the number of fields in the input record, i.e. @code{NF}.
+
+@item struct awk_field_info fields[nf];
+This is a variable-length array whose actual dimension should be @code{nf}.
+For each field, the @code{skip} element should be set to the number
+of characters or bytes, as controlled by the @code{use_chars} flag,
+to skip before the start of this field. The @code{len} element provides
+the length of the field. The values in @code{fields[0]} provide the information
+for @code{$1}, and so on through the @code{fields[nf-1]} element containing the information for @code{$NF}.
+@end table
+
+A convenience macro @code{awk_fieldwidth_info_size(NF)} is provided to
+calculate the appropriate size of a variable-length
+@code{awk_fieldwidth_info_t} structure containing @code{NF} fields. This can
+be used as an argument to @code{malloc()} or in a union to allocate space
+statically. Please refer to the @code{readdir_test} sample extension for an
+example.
+
@node Output Wrappers
@subsubsection Customized Output Wrappers
@cindex customized output wrapper
@@ -31594,6 +32794,9 @@ that parameter. More's the pity.}
@item void fatal(awk_ext_id_t id, const char *format, ...);
Print a message and then cause @command{gawk} to exit immediately.
+@item void nonfatal(awk_ext_id_t id, const char *format, ...);
+Print a nonfatal error message.
+
@item void warning(awk_ext_id_t id, const char *format, ...);
Print a warning message.
@@ -31646,21 +32849,25 @@ value type, as appropriate. This behavior is summarized in
@caption{API value types returned}
@docbook
<informaltable>
-<tgroup cols="6">
- <colspec colwidth="16.6*"/>
- <colspec colwidth="16.6*"/>
- <colspec colwidth="19.8*" colname="c3"/>
- <colspec colwidth="15*" colname="c4"/>
- <colspec colwidth="15*" colname="c5"/>
- <colspec colwidth="16.6*" colname="c6"/>
- <spanspec spanname="hspan" namest="c3" nameend="c6" align="center"/>
+<tgroup cols="8">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <colspec colname="c3"/>
+ <colspec colname="c4"/>
+ <colspec colname="c5"/>
+ <colspec colname="c6"/>
+ <colspec colname="c7"/>
+ <colspec colname="c8"/>
+ <spanspec spanname="hspan" namest="c3" nameend="c8" align="center"/>
<thead>
<row><entry></entry><entry spanname="hspan"><para>Type of Actual Value</para></entry></row>
<row>
<entry></entry>
<entry></entry>
<entry><para>String</para></entry>
+ <entry><para>Strnum</para></entry>
<entry><para>Number</para></entry>
+ <entry><para>Regex</para></entry>
<entry><para>Array</para></entry>
<entry><para>Undefined</para></entry>
</row>
@@ -31671,48 +32878,80 @@ value type, as appropriate. This behavior is summarized in
<entry><para><emphasis role="bold">String</emphasis></para></entry>
<entry><para>String</para></entry>
<entry><para>String</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>String</para></entry>
+ <entry><para>String</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Strnum</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
<entry></entry>
<entry><para><emphasis role="bold">Number</emphasis></para></entry>
- <entry><para>Number if can be converted, else false</para></entry>
<entry><para>Number</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>Number</para></entry>
+ <entry><para>Number</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
<entry><para><emphasis role="bold">Type</emphasis></para></entry>
+ <entry><para><emphasis role="bold">Regex</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Regex</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry><para><emphasis role="bold">Requested</emphasis></para></entry>
<entry><para><emphasis role="bold">Array</emphasis></para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
<entry><para>Array</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
- <entry><para><emphasis role="bold">Requested</emphasis></para></entry>
+ <entry></entry>
<entry><para><emphasis role="bold">Scalar</emphasis></para></entry>
<entry><para>Scalar</para></entry>
<entry><para>Scalar</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
+ <entry><para>Scalar</para></entry>
+ <entry><para>Scalar</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
<row>
<entry></entry>
<entry><para><emphasis role="bold">Undefined</emphasis></para></entry>
<entry><para>String</para></entry>
+ <entry><para>Strnum</para></entry>
<entry><para>Number</para></entry>
+ <entry><para>Regex</para></entry>
<entry><para>Array</para></entry>
<entry><para>Undefined</para></entry>
</row>
<row>
<entry></entry>
<entry><para><emphasis role="bold">Value cookie</emphasis></para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para></entry>
- <entry><para>False</para>
- </entry><entry><para>False</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
</row>
</tbody>
</tgroup>
@@ -31728,41 +32967,45 @@ value type, as appropriate. This behavior is summarized in
@tex
\vglue-1.1\baselineskip
@end tex
-@multitable @columnfractions .166 .166 .198 .15 .15 .166
-@headitem @tab @tab String @tab Number @tab Array @tab Undefined
-@item @tab @b{String} @tab String @tab String @tab False @tab False
-@item @tab @b{Number} @tab Number if can be converted, else false @tab Number @tab False @tab False
-@item @b{Type} @tab @b{Array} @tab False @tab False @tab Array @tab False
-@item @b{Requested} @tab @b{Scalar} @tab Scalar @tab Scalar @tab False @tab False
-@item @tab @b{Undefined} @tab String @tab Number @tab Array @tab Undefined
-@item @tab @b{Value cookie} @tab False @tab False @tab False @tab False
+@c @multitable @columnfractions .166 .166 .198 .15 .15 .166
+@multitable {Requested} {Undefined} {Number} {Number} {Scalar} {Regex} {Array} {Undefined}
+@headitem @tab @tab String @tab Strnum @tab Number @tab Regex @tab Array @tab Undefined
+@item @tab @b{String} @tab String @tab String @tab String @tab String @tab false @tab false
+@item @tab @b{Strnum} @tab false @tab Strnum @tab Strnum @tab false @tab false @tab false
+@item @tab @b{Number} @tab Number @tab Number @tab Number @tab false @tab false @tab false
+@item @b{Type} @tab @b{Regex} @tab false @tab false @tab false @tab Regex @tab false @tab false
+@item @b{Requested} @tab @b{Array} @tab false @tab false @tab false @tab false @tab Array @tab false
+@item @tab @b{Scalar} @tab Scalar @tab Scalar @tab Scalar @tab Scalar @tab false @tab false
+@item @tab @b{Undefined} @tab String @tab Strnum @tab Number @tab Regex @tab Array @tab Undefined
+@item @tab @b{Value cookie} @tab false @tab false @tab false @tab false @tab false @tab false
@end multitable
@end ifnotdocbook
@end ifnotplaintext
@ifplaintext
-@example
- +-------------------------------------------------+
- | Type of Actual Value: |
- +------------+------------+-----------+-----------+
- | String | Number | Array | Undefined |
-+-----------+-----------+------------+------------+-----------+-----------+
-| | String | String | String | False | False |
-| |-----------+------------+------------+-----------+-----------+
-| | Number | Number if | Number | False | False |
-| | | can be | | | |
-| | | converted, | | | |
-| | | else false | | | |
-| |-----------+------------+------------+-----------+-----------+
-| Type | Array | False | False | Array | False |
-| Requested |-----------+------------+------------+-----------+-----------+
-| | Scalar | Scalar | Scalar | False | False |
-| |-----------+------------+------------+-----------+-----------+
-| | Undefined | String | Number | Array | Undefined |
-| |-----------+------------+------------+-----------+-----------+
-| | Value | False | False | False | False |
-| | cookie | | | | |
-+-----------+-----------+------------+------------+-----------+-----------+
-@end example
+@verbatim
+ +-------------------------------------------------------+
+ | Type of Actual Value: |
+ +--------+--------+--------+--------+-------+-----------+
+ | String | Strnum | Number | Regex | Array | Undefined |
++-----------+-----------+--------+--------+--------+--------+-------+-----------+
+| | String | String | String | String | String | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Strnum | false | Strnum | Strnum | false | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Number | Number | Number | Number | false | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Regex | false | false | false | Regex | false | false |
+| Type +-----------+--------+--------+--------+--------+-------+-----------+
+| Requested | Array | false | false | false | false | Array | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Scalar | Scalar | Scalar | Scalar | Scalar | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Undefined | String | Strnum | Number | Regex | Array | Undefined |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Value | false | false | false | false | false | false |
+| | Cookie | | | | | | |
++-----------+-----------+--------+--------+--------+--------+-------+-----------+
+@end verbatim
@end ifplaintext
@end float
@@ -31840,13 +33083,6 @@ An extension can look up the value of @command{gawk}'s special variables.
However, with the exception of the @code{PROCINFO} array, an extension
cannot change any of those variables.
-@quotation CAUTION
-It is possible for the lookup of @code{PROCINFO} to fail. This happens if
-the @command{awk} program being run does not reference @code{PROCINFO};
-in this case, @command{gawk} doesn't bother to create the array and
-populate it.
-@end quotation
-
@node Symbol table by cookie
@subsubsection Variable Access and Update by Cookie
@@ -31868,7 +33104,7 @@ Return false if the value cannot be retrieved.
@item awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *value);
Update the value associated with a scalar cookie. Return false if
-the new value is not of type @code{AWK_STRING} or @code{AWK_NUMBER}.
+the new value is not of type @code{AWK_STRING}, @code{AWK_STRNUM}, @code{AWK_REGEX}, or @code{AWK_NUMBER}.
Here too, the predefined variables may not be updated.
@end table
@@ -31989,7 +33225,7 @@ is what the routines in this @value{SECTION} let you do. The functions are as f
@table @code
@item awk_bool_t create_value(awk_value_t *value, awk_value_cookie_t *result);
Create a cached string or numeric value from @code{value} for
-efficient later assignment. Only values of type @code{AWK_NUMBER}
+efficient later assignment. Only values of type @code{AWK_NUMBER}, @code{AWK_REGEX}, @code{AWK_STRNUM},
and @code{AWK_STRING} are allowed. Any other type is rejected.
@code{AWK_UNDEFINED} could be allowed, but doing so would result in
inferior performance.
@@ -32215,9 +33451,10 @@ The array remains an array, but after calling this function, it
has no elements. This is equivalent to using the @code{delete}
statement (@pxref{Delete}).
-@item awk_bool_t flatten_array(awk_array_t a_cookie, awk_flat_array_t **data);
+@item awk_bool_t flatten_array_typed(awk_array_t a_cookie, awk_flat_array_t **data, awk_valtype_t index_type, awk_valtype_t value_type);
For the array represented by @code{a_cookie}, create an @code{awk_flat_array_t}
-structure and fill it in. Set the pointer whose address is passed as @code{data}
+structure and fill it in with indices and values of the requested types.
+Set the pointer whose address is passed as @code{data}
to point to this structure.
Return true upon success, or false otherwise.
@ifset FOR_PRINT
@@ -32229,6 +33466,14 @@ See the next @value{SECTION}
for a discussion of how to
flatten an array and work with it.
+@item awk_bool_t flatten_array(awk_array_t a_cookie, awk_flat_array_t **data);
+For the array represented by @code{a_cookie}, create an @code{awk_flat_array_t}
+structure and fill it in with @code{AWK_STRING} indices and
+@code{AWK_UNDEFINED} values.
+This is superseded by @code{flatten_array_typed()}.
+It is provided as a macro, and remains for convenience and for source code
+compatibility with the previous version of the API.
+
@item awk_bool_t release_flattened_array(awk_array_t a_cookie,
@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_flat_array_t *data);
When done with a flattened array, release the storage using this function.
@@ -32341,7 +33586,7 @@ to double-check that the count in the @code{awk_flat_array_t}
is the same as the count just retrieved:
@example
- if (! flatten_array(value2.array_cookie, & flat_array)) @{
+ if (! flatten_array_typed(value2.array_cookie, & flat_array, AWK_STRING, AWK_UNDEFINED)) @{
printf("dump_array_and_delete: could not flatten array\n");
goto out;
@}
@@ -32637,6 +33882,75 @@ $ @kbd{AWKLIBPATH=$PWD ./gawk -f subarray.awk}
(@xref{Finding Extensions} for more information on the
@env{AWKLIBPATH} environment variable.)
+@node Redirection API
+@subsection Accessing and Manipulating Redirections
+
+The following function allows extensions to access and manipulate redirections.
+
+@table @code
+@item awk_bool_t get_file(const char *name,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t name_len,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *filetype,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int fd,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_input_buf_t **ibufp,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_output_buf_t **obufp);
+Look up file @code{name} in @command{gawk}'s internal redirection table.
+If @code{name} is @code{NULL} or @code{name_len} is zero, return
+data for the currently open input file corresponding to @code{FILENAME}.
+(This does not access the @code{filetype} argument, so that may be undefined).
+If the file is not already open, attempt to open it.
+The @code{filetype} argument must be zero-terminated and should be one of:
+
+@table @code
+@item ">"
+A file opened for output.
+
+@item ">>"
+A file opened for append.
+
+@item "<"
+A file opened for input.
+
+@item "|>"
+A pipe opened for output.
+
+@item "|<"
+A pipe opened for input.
+
+@item "|&"
+A two-way coprocess.
+@end table
+
+On error, return an @code{awk_false} value. Otherwise, return
+@code{awk_true}, and return additional information about the redirection
+in the @code{ibufp} and @code{obufp} pointers. For input
+redirections, the @code{*ibufp} value should be non-@code{NULL},
+and @code{*obufp} should be @code{NULL}. For output redirections,
+the @code{*obufp} value should be non-@code{NULL}, and @code{*ibufp}
+should be @code{NULL}. For two-way coprocesses, both values should
+be non-@code{NULL}.
+
+In the usual case, the extension is interested in @code{(*ibufp)->fd}
+and/or @code{fileno((*obufp)->fp)}. If the file is not already
+open, and the @code{fd} argument is nonnegative, @command{gawk}
+will use that file descriptor instead of opening the file in the
+usual way. If @code{fd} is nonnegative, but the file exists already,
+@command{gawk} ignores @code{fd} and returns the existing file. It is
+the caller's responsibility to notice that neither the @code{fd} in
+the returned @code{awk_input_buf_t} nor the @code{fd} in the returned
+@code{awk_output_buf_t} matches the requested value.
+
+Note that supplying a file descriptor is currently @emph{not} supported
+for pipes. However, supplying a file descriptor should work for input,
+output, append, and two-way (coprocess) sockets. If @code{filetype}
+is two-way, @command{gawk} assumes that it is a socket! Note that in
+the two-way case, the input and output file descriptors may differ.
+To check for success, you must check whether either matches.
+@end table
+
+It is anticipated that this API function will be used to implement I/O
+multiplexing and a socket library.
+
@node Extension API Variables
@subsection API Variables
@@ -32663,10 +33977,10 @@ debugging:
@float Table,gawk-api-version
@caption{gawk API version constants}
-@multitable @columnfractions .33 .33 .33
-@headitem API Version @tab C preprocessor define @tab enum constant
-@item Major @tab gawk_api_major_version @tab GAWK_API_MAJOR_VERSION
-@item Minor @tab gawk_api_minor_version @tab GAWK_API_MINOR_VERSION
+@multitable {@b{API Version}} {@code{gawk_api_major_version}} {@code{GAWK_API_MAJOR_VERSION}}
+@headitem API Version @tab C Preprocessor Define @tab enum constant
+@item Major @tab @code{gawk_api_major_version} @tab @code{GAWK_API_MAJOR_VERSION}
+@item Minor @tab @code{gawk_api_minor_version} @tab @code{GAWK_API_MINOR_VERSION}
@end multitable
@end float
@@ -32685,10 +33999,10 @@ constant integers:
@table @code
@item api->major_version
-The major version of the running @command{gawk}
+The major version of the running @command{gawk}.
@item api->minor_version
-The minor version of the running @command{gawk}
+The minor version of the running @command{gawk}.
@end table
It is up to the extension to decide if there are API incompatibilities.
@@ -32761,7 +34075,7 @@ static awk_ext_id_t ext_id;
static const char *ext_version = NULL; /* or @dots{} = "some string" */
static awk_ext_func_t func_table[] = @{
- @{ "name", do_name, 1 @},
+ @{ "name", do_name, 1, 0, awk_false, NULL @},
/* @dots{} */
@};
@@ -32862,6 +34176,19 @@ If @code{ext_version} is not @code{NULL}, register
the version string with @command{gawk}.
@end enumerate
+
+@node Changes from API V1
+@subsection Changes From Version 1 of the API
+
+The current API is @emph{not} binary compatible with version 1 of the API.
+You will have to recompile your extensions in order to use them with
+the current version of @command{gawk}.
+
+Fortunately, at the possible expense of some compile-time warnings, the API remains
+source-code--compatible with the previous API. The major differences are
+the additional members in the @code{awk_ext_func_t} structure, and the
+addition of the third argument to the C implementation function.
+
@node Finding Extensions
@section How @command{gawk} Finds Extensions
@cindex extension search path
@@ -33102,17 +34429,12 @@ The second is a pointer to an @code{awk_value_t} structure, usually named
/* do_chdir --- provide dynamically loaded chdir() function for gawk */
static awk_value_t *
-do_chdir(int nargs, awk_value_t *result)
+do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused)
@{
awk_value_t newdir;
int ret = -1;
assert(result != NULL);
-
- if (do_lint && nargs != 1)
- lintwarn(ext_id,
- _("chdir: called with incorrect number of arguments, "
- "expecting 1"));
@end example
The @code{newdir}
@@ -33121,8 +34443,8 @@ with @code{get_argument()}. Note that the first argument is
numbered zero.
If the argument is retrieved successfully, the function calls the
-@code{chdir()} system call. If the @code{chdir()} fails, @code{ERRNO}
-is updated:
+@code{chdir()} system call. Otherwise, if the @code{chdir()} fails,
+it updates @code{ERRNO}:
@example
if (get_argument(0, AWK_STRING, & newdir)) @{
@@ -33326,15 +34648,11 @@ is set to point to @code{stat()}, instead.
Here is the @code{do_stat()} function, which starts with
variable declarations and argument checking:
-@ignore
-Changed message for page breaking. Used to be:
- "stat: called with incorrect number of arguments (%d), should be 2",
-@end ignore
@example
/* do_stat --- provide a stat() function for gawk */
static awk_value_t *
-do_stat(int nargs, awk_value_t *result)
+do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused)
@{
awk_value_t file_param, array_param;
char *name;
@@ -33345,13 +34663,6 @@ do_stat(int nargs, awk_value_t *result)
int (*statfunc)(const char *path, struct stat *sbuf) = lstat;
assert(result != NULL);
-
- if (nargs != 2 && nargs != 3) @{
- if (do_lint)
- lintwarn(ext_id,
- _("stat: called with wrong number of arguments"));
- return make_number(-1, result);
- @}
@end example
Then comes the actual work. First, the function gets the arguments.
@@ -33419,11 +34730,9 @@ structures for loading each function into @command{gawk}:
@example
static awk_ext_func_t func_table[] = @{
- @{ "chdir", do_chdir, 1 @},
- @{ "stat", do_stat, 2 @},
-#ifndef __MINGW32__
- @{ "fts", do_fts, 3 @},
-#endif
+ @{ "chdir", do_chdir, 1, 1, awk_false, NULL @},
+ @{ "stat", do_stat, 3, 2, awk_false, NULL @},
+ @dots{}
@};
@end example
@@ -34204,18 +35513,21 @@ As of this writing, there are seven extensions:
GD graphics library extension
@item
+MPFR library extension
+(this provides access to a number of MPFR functions that @command{gawk}'s
+native MPFR support does not)
+
+@item
PDF extension
@item
PostgreSQL extension
@item
-MPFR library extension
-(this provides access to a number of MPFR functions that @command{gawk}'s
-native MPFR support does not)
+Redis extension
@item
-Redis extension
+Select extension
@item
XML parser extension, using the @uref{http://expat.sourceforge.net, Expat}
@@ -34315,7 +35627,7 @@ output wrappers,
and two-way processors)
@item
-Printing fatal, warning, and ``lint'' warning messages
+Printing fatal, nonfatal, warning, and ``lint'' warning messages
@item
Updating @code{ERRNO}, or unsetting it
@@ -34844,6 +36156,10 @@ Indirect function calls
@item
Directories on the command line produce a warning and are skipped
(@pxref{Command-line directories})
+
+@item
+Output with @code{print} and @code{printf} need not be fatal
+(@pxref{Nonfatal})
@end itemize
@item
@@ -34931,6 +36247,11 @@ The @code{isarray()} function to check if a variable is an array or not
The @code{bindtextdomain()}, @code{dcgettext()}, and @code{dcngettext()}
functions for internationalization
(@pxref{Programmer i18n})
+
+@item
+The @code{intdiv()} function for doing integer
+division and remainder
+(@pxref{Numeric Functions})
@end itemize
@item
@@ -34969,6 +36290,7 @@ The
@option{-p},
@option{-P},
@option{-r},
+@option{-s},
@option{-S},
@option{-t},
and
@@ -34993,6 +36315,7 @@ and the
@option{--load},
@option{--non-decimal-data},
@option{--optimize},
+@option{--no-optimize},
@option{--posix},
@option{--pretty-print},
@option{--profile},
@@ -35063,6 +36386,19 @@ for @command{gawk} @value{PVERSION} 4.1:
Ultrix
@end itemize
+@item
+Support for the following systems was removed from the code
+for @command{gawk} @value{PVERSION} 4.2:
+
+@c nested table
+@itemize @value{MINUS}
+@item
+MirBSD
+
+@item
+GNU/Linux on Alpha
+@end itemize
+
@end itemize
@c XXX ADD MORE STUFF HERE
@@ -35689,6 +37025,56 @@ Support for Ultrix was removed.
@end itemize
+Version 4.2 introduced the following changes:
+
+@itemize @bullet
+@item
+Changes to @code{ENVIRON} are reflected into @command{gawk}'s
+environment and that of programs that it runs.
+@xref{Auto-set}.
+
+@item
+The @code{PROCINFO["argv"} array.
+@xref{Auto-set}.
+
+@item
+The @option{--pretty-print} option no longer runs the @command{awk}
+program too.
+@xref{Options}.
+
+@item
+The @command{igawk} program and its manual page are no longer
+installed when @command{gawk} is built.
+@xref{Igawk Program}.
+
+@item
+The @code{intdiv()} function.
+@xref{Numeric Functions}.
+
+@item
+The maximum number of hexadecimal digits in @samp{\x} escapes
+is now two.
+@xref{Escape Sequences}.
+
+@item
+Nonfatal output with @code{print} and @code{printf}.
+@xref{Nonfatal}.
+
+@item
+For many years, POSIX specified that default field splitting
+only allowed spaces and tabs to separate fields, and this was
+how @command{gawk} behaved with @option{--posix}. As of 2013,
+the standard restored historical behavior, and now default
+field splitting with @option{--posix} also allows newlines to
+separate fields.
+
+@item
+Support for MirBSD was removed.
+
+@item
+Support for GNU/Linux on Alpha was removed.
+@end itemize
+
@c XXX ADD MORE STUFF HERE
@end ifclear
@@ -35818,7 +37204,7 @@ and
@uref{http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap09.html#tag_21_09_03_05, its rationale}.}
By using this lovely technical term, the standard gives license
-to implementors to implement ranges in whatever way they choose.
+to implementers to implement ranges in whatever way they choose.
The @command{gawk} maintainer chose to apply the pre-POSIX meaning
both with the default regexp matching and when @option{--traditional} or
@option{--posix} are used.
@@ -36255,6 +37641,12 @@ These files contain the actual @command{gawk} source code.
@end table
@table @file
+@item support/*
+C header and source files for routines that @command{gawk}
+uses, but that are not part of its core functionality.
+For example, argument parsing, regular expression matching,
+and random number generating routines are all kept here.
+
@item ABOUT-NLS
A file containing information about GNU @command{gettext} and translations.
@@ -36355,6 +37747,8 @@ The generated Info file for
The @command{troff} source for a manual page describing the @command{igawk}
program presented in
@ref{Igawk Program}.
+(Since @command{gawk} can do its own @code{@@include} processing,
+neither @command{igawk} nor @file{igawk.1} are installed.)
@item doc/Makefile.in
The input file used during the configuration process to generate the
@@ -36399,8 +37793,6 @@ source file for this @value{DOCUMENT}. It also contains a @file{Makefile.in} fil
@file{Makefile.am} is used by GNU Automake to create @file{Makefile.in}.
The library functions from
@ref{Library Functions},
-and the @command{igawk} program from
-@ref{Igawk Program}
are included as ready-to-use files in the @command{gawk} distribution.
They are installed as part of the installation process.
The rest of the programs in this @value{DOCUMENT} are available in appropriate
@@ -36411,6 +37803,12 @@ The source code, manual pages, and infrastructure files for
the sample extensions included with @command{gawk}.
@xref{Dynamic Extensions}, for more information.
+@item extras/*
+Additional non-essential files. Currently, this directory contains some shell
+startup files to be installed in @file{/etc/profile.d} to aid in manipulating
+the @env{AWKPATH} and @env{AWKLIBPATH} environment variables.
+@xref{Shell Startup Files}, for more information.
+
@item posix/*
Files needed for building @command{gawk} on POSIX-compliant systems.
@@ -36439,6 +37837,7 @@ to configure @command{gawk} for your system yourself.
@menu
* Quick Installation:: Compiling @command{gawk} under Unix.
+* Shell Startup Files:: Shell convenience functions.
* Additional Configuration Options:: Other compile-time options.
* Configuration Philosophy:: How it's all supposed to work.
@end menu
@@ -36519,6 +37918,44 @@ is likely that you will be asked for your password, and you will have
to have been set up previously as a user who is allowed to run the
@command{sudo} command.
+@node Shell Startup Files
+@appendixsubsec Shell Startup Files
+
+The distribution contains shell startup files @file{gawk.sh} and
+@file{gawk.csh}, containing functions to aid in manipulating
+the @env{AWKPATH} and @env{AWKLIBPATH} environment variables.
+On a Fedora GNU/Linux system, these files should be installed in @file{/etc/profile.d};
+on other platforms, the appropriate location may be different.
+
+@table @command
+
+@cindex @command{gawkpath_default} shell function
+@item gawkpath_default
+Reset the @env{AWKPATH} environment variable to its default value.
+
+@cindex @command{gawkpath_prepend} shell function
+@item gawkpath_prepend
+Add the argument to the front of the @env{AWKPATH} environment variable.
+
+@cindex @command{gawkpath_append} shell function
+@item gawkpath_append
+Add the argument to the end of the @env{AWKPATH} environment variable.
+
+@cindex @command{gawklibpath_default} shell function
+@item gawklibpath_default
+Reset the @env{AWKLIBPATH} environment variable to its default value.
+
+@cindex @command{gawklibpath_prepend} shell function
+@item gawklibpath_prepend
+Add the argument to the front of the @env{AWKLIBPATH} environment variable.
+
+@cindex @command{gawklibpath_append} shell function
+@item gawklibpath_append
+Add the argument to the end of the @env{AWKLIBPATH} environment variable.
+
+@end table
+
+
@node Additional Configuration Options
@appendixsubsec Additional Configuration Options
@cindex @command{gawk}, configuring, options
@@ -36560,6 +37997,13 @@ Using this option will cause some of the tests in the test suite
to fail. This option may be removed at a later date.
@end quotation
+@cindex @option{--disable-mpfr} configuration option
+@cindex configuration option, @code{--disable-mpfr}
+@item --disable-mpfr
+Skip checking for the MPFR and GMP libraries. This is useful
+mainly for the developers, to make sure nothing breaks if
+MPFR support is not available.
+
@cindex @option{--disable-nls} configuration option
@cindex configuration option, @code{--disable-nls}
@item --disable-nls
@@ -41102,6 +42546,7 @@ Consistency issues:
Use MS-DOS not MS DOS
Use an empty set of parentheses after built-in and awk function names.
Use "multiFOO" without a hyphen.
+ Use "time zone" as two words, not "timezone".
Date: Wed, 13 Apr 94 15:20:52 -0400
From: rms@gnu.org (Richard Stallman)
diff --git a/doc/gawkworkflow.info b/doc/gawkworkflow.info
new file mode 100644
index 00000000..88240ba6
--- /dev/null
+++ b/doc/gawkworkflow.info
@@ -0,0 +1,1980 @@
+This is gawkworkflow.info, produced by makeinfo version 6.1 from
+gawkworkflow.texi.
+
+Copyright (C) 2017 Free Software Foundation, Inc.
+
+
+ This is Edition 0.7 of 'Participating in 'gawk' Development'.
+
+ Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being "GNU General Public License", with the
+Front-Cover Texts being "A GNU Manual", and with the Back-Cover Texts as
+in (a) below. A copy of the license is included in the section entitled
+"GNU Free Documentation License".
+
+ a. The FSF's Back-Cover Text is: "You have the freedom to copy and
+ modify this GNU manual."
+INFO-DIR-SECTION Text creation and manipulation
+START-INFO-DIR-ENTRY
+* Gawk Work Flow: (gawkworkflow). Participating in 'gawk' development.
+END-INFO-DIR-ENTRY
+
+INFO-DIR-SECTION Individual utilities
+START-INFO-DIR-ENTRY
+* Gawk Work Flow: (gawkworkflow)Overview. Participating in 'gawk' development.
+END-INFO-DIR-ENTRY
+
+
+File: gawkworkflow.info, Node: Top, Next: Preface, Up: (dir)
+
+General Introduction
+********************
+
+This file describes how to participate in software development for GNU
+Awk ('gawk') (http://www.gnu.org/software/gawk).
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+
+ This is Edition 0.7 of 'Participating in 'gawk' Development'.
+
+ Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being "GNU General Public License", with the
+Front-Cover Texts being "A GNU Manual", and with the Back-Cover Texts as
+in (a) below. A copy of the license is included in the section entitled
+"GNU Free Documentation License".
+
+ a. The FSF's Back-Cover Text is: "You have the freedom to copy and
+ modify this GNU manual."
+
+* Menu:
+
+* Preface:: Some introductory remarks.
+* Contributing:: How to contribute to 'gawk'
+ development.
+* Using Git:: Getting started with Git.
+* Configuring git:: Configuring Git.
+* Development without commit access:: How to work without commit access.
+* Development with commit access:: How to work with commit access.
+* General practices:: How things should usually be done.
+* Repo Maintenance:: Tips for keeping your repo clean.
+* Development Stuff:: Things you need to know to be a
+ 'gawk' developer.
+* Cheat Sheet:: Git command summary.
+* Resources:: Some further resources.
+* TODO:: Stuff still to do.
+* Index:: The index.
+
+* This Manual:: How to use this manual.
+* Conventions:: Typographical Conventions.
+* Acknowledgments:: Acknowledgments.
+* Reviewers:: A note to reviewers.
+* Push Pull:: The push/pull software development model.
+* Repo Copies:: What it means to have a copy of a repo.
+* Local Branches:: How to best use local branches.
+* Branches are state:: Branches represent development state.
+* Repo State:: The different branch types in the repo.
+* Local State:: Managing local branches.
+* Remotes:: What a "remote" is.
+* Cloning:: Cloning the repo the first time.
+* Switching Branches:: Moving from one branch to another.
+* Starting A New Branch:: Starting a new branch for development.
+* Undoing a change:: Throwing away changes.
+* Updating:: Keeping in sync with the upstream repo.
+* Rebasing:: Rebasing A Local Branch.
+* Merge Conflicts:: Dealing With Merge Conflicts.
+* Submitting Changes:: How to submit your changes.
+* Removing Branches:: Getting rid of unneeded branches.
+* Points to remember:: Things you need to keep in mind.
+* Initial setup:: Getting started with commit access.
+* ssh clone:: Cloning using an 'ssh://' URL.
+* Developing patches:: Developing patches.
+* Developing new features:: Developing new features.
+* Developing fixes:: Developing fixes.
+* Coding style:: Where to read up on the coding style.
+* Doing paperwork:: Legal stuff in order to contribute.
+* Tools:: Tools to have on your system for
+ development.
+* GNU Tools:: The GNU Autotools.
+* Compilers:: A discussion of compilers that can be
+ used.
+* Debugging:: Compiling for debugging.
+
+
+File: gawkworkflow.info, Node: Preface, Next: Contributing, Prev: Top, Up: Top
+
+Preface
+*******
+
+This Info file describes how to participate in development of GNU Awk
+('gawk'). GNU Awk is a Free Software project belonging to the Free
+Software Foundation's GNU project.
+
+ The Info file focuses on participation in the project (that is, how
+to work most effectively if you wish to contribute to it) and also
+describes how to make use of the Git (http://git-scm.org) distributed
+source code management system for 'gawk' development.
+
+ You should be comfortable working with traditional UNIX-style tools
+and with the C language and standard library facilities.
+
+* Menu:
+
+* This Manual:: How to use this manual.
+* Conventions:: Typographical Conventions.
+* Acknowledgments:: Acknowledgments.
+* Reviewers:: A note to reviewers.
+
+
+File: gawkworkflow.info, Node: This Manual, Next: Conventions, Up: Preface
+
+Using This Book
+===============
+
+This Info file has the following chapters and appendices:
+
+ * *note Contributing:: describes how to start contributing to the
+ 'gawk' project.
+
+ * *note Using Git:: introduces the Git distributed source code
+ management system.
+
+ * *note Configuring git:: describes some initial set-up you need to
+ do before using Git seriously.
+
+ * *note Development without commit access:: gets into the meat of the
+ development workflow, describing how to work if you don't have
+ commit access to the Savannah repository.
+
+ * *note Development with commit access:: continues the discussion,
+ covering what's different when you can commit directly to the
+ Savannah repository.
+
+ * *note General practices:: describes general development practices
+ used by the 'gawk' development team.
+
+ * *note Repo Maintenance:: presents several different things you need
+ to know about to keep your repo in good shape.
+
+ * *note Development Stuff:: describes some important points you
+ should be familiar with in order to participate in 'gawk'
+ development and presents some tools that may make your work easier.
+
+ * *note Cheat Sheet:: provides a short "cheat sheet" summarizing all
+ the Git commands referenced in this Info file.
+
+ * *note Resources:: provides a few pointers to Internet resources for
+ learning more about Git.
+
+
+File: gawkworkflow.info, Node: Conventions, Next: Acknowledgments, Prev: This Manual, Up: Preface
+
+Typographical Conventions
+=========================
+
+This Info file is written in Texinfo
+(http://www.gnu.org/software/texinfo/), the GNU documentation 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
+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 output.
+Error messages and other output on the command's standard error are
+preceded by the glyph "error->". For example:
+
+ $ echo hi on stdout
+ -| hi on stdout
+ $ echo hello on stderr 1>&2
+ error-> hello on stderr
+
+ Characters that you type at the keyboard look 'like this'. In
+particular, there are special characters called "control characters."
+These are characters that you type by holding down both the 'CONTROL'
+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.
+
+ NOTE: Notes of interest look like this.
+
+ CAUTION: Cautionary or warning notes look like this.
+
+
+File: gawkworkflow.info, Node: Acknowledgments, Next: Reviewers, Prev: Conventions, Up: Preface
+
+Acknowledgments
+===============
+
+Thanks to Ju"rgen Kahrs for his initial efforts to write a document like
+this. Although his prose has not survived, his material was helpful in
+preparing this Info file.
+
+ Thanks to Yehezkel Bernat for reviewing this document and in general
+for his good intentions.
+
+ *FIXME:* YOUR NAME HERE...
+
+
+File: gawkworkflow.info, Node: Reviewers, Prev: Acknowledgments, Up: Preface
+
+Notes to Reviewers
+==================
+
+Please let me know if anything is missing, or unclear. Real errors with
+respect Git commands and usage are very important as well.
+
+ Spelling errors and typo fixes welcome, but not as important.
+
+
+File: gawkworkflow.info, Node: Contributing, Next: Using Git, Prev: Preface, Up: Top
+
+1 How to Start Contributing
+***************************
+
+'gawk' development is distributed. It's done using electronic mail
+(email) and via branches in the Git repo(1) on Savannah
+(http://savannah.gnu.org), the GNU project's source code management
+site.
+
+ In this major node we use some Git terminology. If you're not at all
+familiar with Git, then skim this major node and come back after reading
+the rest of the Info file.
+
+ 'gawk' is similar to many other Free Software projects. To begin
+contributing, simply start! Take a look at the 'TODO' file in the
+distribution, see if there is something of interest to you, and ask on
+the <bug-gawk@gnu.org> mailing list if anyone else is working on it. If
+not, then go for it! (*Note Development Stuff:: for a discussion of
+some of the technical things you'll need to do. Here we describe the
+process in general.)
+
+ Your contribution can be almost anything that is relevant for 'gawk',
+such as code fixes, documentation fixes, and/or new features.
+
+ NOTE: If possible, new features should be done using 'gawk''s
+ extension mechanism. If you want to add a user-visible language
+ change to the 'gawk' core, you're going to have to convince the
+ maintainer and other developers that it's really worthwile to do
+ so.
+
+ Changes that improve performance or portability, or that fix bugs,
+ or that enable more things in extensions, will require less
+ convincing, of course.
+
+ As you complete a task, submit patches for review to the
+<bug-gawk@gnu.org> mailing list, where you'll be given feedback about
+your work. Once your changes are acceptable, the maintainer will commit
+them to the Git repository.
+
+ Over time, as the maintainer and development team gain confidence in
+your ability to contribute, you may be asked to join the private 'gawk'
+developers' mailing list, and/or be granted commit access to the Git
+repository on Savannah. This has happened to more than one person who
+just "came out of the woodwork."
+
+ Until that happens, or if you don't want to join the list, you should
+continue to work with private branches and submission of patches to the
+mailing list.
+
+ Once you have commit access, if you want to make a major change or
+add a major feature, where the patch(es) would be very large, it has
+become the practice to create a separate branch, based off of 'master',
+to host the feature. This way the maintainer can review it, and you can
+continue to improve it, until it's ready for integration into 'master'.
+
+ NOTE: Because of the GNU project's requirements for signed
+ paperwork for contributions, the 'gawk' project will *not* work
+ with pull requests from GitHub (http://github.com) or any other
+ Git-based software hosting service. You must submit patches to the
+ mailing list, and be willing to sign paperwork for large patches.
+
+ The <bug-gawk@gnu.org> mailing list is not private. Anyone may send
+mail to it, and anyone may subscribe to it. To subscribe, go to the
+list's web page (https://lists.gnu.org/mailman/listinfo/bug-gawk) and
+follow the instructions there. If you plan to be involved long-term
+with 'gawk' development, then you probably should subscribe to the list.
+
+ ---------- Footnotes ----------
+
+ (1) Short for "repository".
+
+
+File: gawkworkflow.info, Node: Using Git, Next: Configuring git, Prev: Contributing, Up: Top
+
+2 Using Git
+***********
+
+This chapter provides an introduction to using Git. Our point is _not_
+to rave about how wonderful Git is, nor to go into painful detail about
+how it works. Rather we want to give you enough background to
+understand how to use Git effectively for bug fix and feature
+development and to interact ("play nicely") with the development team.
+
+* Menu:
+
+* Push Pull:: The push/pull software development model.
+* Repo Copies:: What it means to have a copy of a repo.
+* Local Branches:: How to best use local branches.
+* Branches are state:: Branches represent development state.
+
+
+File: gawkworkflow.info, Node: Push Pull, Next: Repo Copies, Up: Using Git
+
+2.1 The "Push/Pull" Model of Software Development
+=================================================
+
+Git is a powerful, distributed source code management system. However,
+the way it's used for 'gawk' development purposely does not take
+advantage of all its features.
+
+ Instead, the model is rather simple, and in many ways much like more
+traditional distributed systems such as the Concurrent Versions System
+(http://www.nongnu.org/cvs) (CVS) or Subversion
+(http://subversion.apache.org) (SVN).
+
+ The central idea can be termed "push/pull." You _pull_ updates down
+from the central repository to your local copy, and if you have commit
+rights, you _push_ your changes or updates up to the central repository.
+
+ Where Git does stand out is in its management of multiple branches of
+development. Git makes it very easy to set up a separate branch for use
+in fixing a bug or developing a feature. You can then easily keep that
+branch up to date with respect to the main development branch(es), and
+eventually merge the changes from your branch into the main branch.
+
+ Almost always Git does these merges for you without problem. When
+there is a problem (a "merge conflict"), usually it is very easy for you
+to "resolve" them and then complete the merge. We talk about this in
+more detail later (*note Merge Conflicts::).
+
+
+File: gawkworkflow.info, Node: Repo Copies, Next: Local Branches, Prev: Push Pull, Up: Using Git
+
+2.2 How Git Stores Branches and Their Copies
+============================================
+
+So how does Git work?(1)
+
+ A repository consists of a collection of "branches". Each branch
+represents the history of a collection of files and directories (a file
+"tree"). Each combined set of changes to this collection (files and
+directories added or deleted, and/or file contents changed) is termed a
+"commit".
+
+ When you first create a local copy of a remote repository ("clone the
+repo"), Git copies all of the original repository's branches to your
+local system. The original remote repository is referred to as being
+"upstream", and your local repo is "downstream" from it. Git
+distinguishes branches from the upstream repo by prefixing their names
+with 'origin/'. Let's draw some pictures. *note Figure 2.1:
+savannah-repo. represents the state of the repo on Savannah:
+
+ +======================+
+ | Branches |
+ +======================+
+ | master |
+ +----------------------+
+ | gawk-4.1-stable |
+ +----------------------+
+ | gawk-4.0-stable |
+ +----------------------+
+ | feature/fix-comments |
+ +----------------------+
+ | ... |
+ +----------------------+
+
+Figure 2.1: The Savannah 'gawk' Repository
+
+ After you clone the repo, on your local system you will have a single
+branch named 'master' that's visible when you use 'git branch' to see
+your branches.
+
+ $ git clone http://git.savannah.gnu.org/r/gawk.git Clone the repo
+ $ cd gawk Change to local copy
+ $ git branch See branch information
+ -| * master
+
+The current branch is always indicated with a leading asterisk ('*').
+
+ Pictorially, the local repo looks like *note Figure 2.2: your-repo.
+(you can ignore the 'T' column for the moment):
+
+ +===+======================++=============================+
+ | T | Local Branches || Remote Branches |
+ +===+======================++=============================+
+ | X | master || origin/master |
+ +---+----------------------++-----------------------------+
+ | | || origin/gawk-4.1-stable |
+ +---+----------------------++-----------------------------+
+ | | || origin/gawk-4.0-stable |
+ +---+----------------------++-----------------------------+
+ | | || origin/feature/fix-comments |
+ +---+----------------------++-----------------------------+
+ | | || ... |
+ +---+----------------------++-----------------------------+
+
+Figure 2.2: Your Local 'gawk' Repository
+
+Note that what is simply 'gawk-4.1-stable' in the upstream repo is now
+referred to as 'origin/gawk-4.1-stable'. The 'origin/' branches are a
+snapshot of the state of the upstream repo. This is how Git allows you
+to see what changes you've made with respect to the upstream repo,
+without having to actually communicate with the upstream repo over the
+Internet. (When files are identical, Git is smart enough to not have
+two separate physical copies on your local disk.)
+
+ If you're working on a simple bug fix or change, you can do so
+directly in your local 'master' branch. You can then commit your
+changes, and if you have access rights, push them upstream to the
+Savannah repo. (However, there is a process to follow. Please read the
+rest of this Info file.)
+
+ ---------- Footnotes ----------
+
+ (1) The following description is greatly simplified.
+
+
+File: gawkworkflow.info, Node: Local Branches, Next: Branches are state, Prev: Repo Copies, Up: Using Git
+
+2.3 Local Branches
+==================
+
+Let's talk about local branches in more detail. (The terminology used
+here is my own, not official Git jargon.) There are two kinds of local
+branches:
+
+"Tracking Branches"
+ Tracking branches track branches from the upstream repository. You
+ first create a tracking branch simply by checking out a branch from
+ the upstream. You use the branch name without the leading
+ 'origin/' prefix. For example, 'git checkout gawk-4.1-stable'.
+
+ You can then work on this branch, making commitments to it as you
+ wish. Once things are ready to move upstream, you simply use 'git
+ push', and your changes will be pushed up to the main repo.(1)
+
+ You should *never* checkout a branch using the 'origin/' prefix.
+ Things will get very confused. Always work on local tracking
+ branches.
+
+"Purely Local Branches"
+ A "purely local branch" exists only on your system. You may be
+ developing some large new feature, or fixing a very difficult bug,
+ or have a change for which paperwork has not yet been completed.
+
+ In such a case, you would keep your changes on a local branch, and
+ periodically synchronize it with 'master' (or whichever upstream
+ branch you started from).
+
+ This may seem somewhat abstract so far. We demonstrate with commands
+and branches in *note Development without commit access::, later in this
+Info file.
+
+ Let's say you have checked out a copy of 'gawk-4.1-stable' and have
+created a purely local branch named 'better-random'. Then our picture
+now looks like *note Figure 2.3: your-repo-2, where the 'T' column
+indicates a tracking branch.
+
+ +===+======================++=============================+
+ | T | Local Branches || Remote Branches |
+ +===+======================++=============================+
+ | X | master || origin/master |
+ +---+----------------------++-----------------------------+
+ | X | gawk-4.1-stable || origin/gawk-4.1-stable |
+ +---+----------------------++-----------------------------+
+ | | || origin/gawk-4.0-stable |
+ +---+----------------------++-----------------------------+
+ | | || origin/feature/fix-comments |
+ +---+----------------------++-----------------------------+
+ | | || ... |
+ +---+----------------------++-----------------------------+
+ | | better-random || |
+ +---+----------------------++-----------------------------+
+
+Figure 2.3: Your Local 'gawk' Repository With a Purely Local Branch
+
+ ---------- Footnotes ----------
+
+ (1) Assuming you have permission to do so, of course.
+
+
+File: gawkworkflow.info, Node: Branches are state, Prev: Local Branches, Up: Using Git
+
+2.4 Branches Represent Development State
+========================================
+
+Branches represent development state. At any given time, when you
+checkout a particular branch (or create a new one), you have a copy of
+the 'gawk' source tree that you should be able to build and test.
+
+ The following minor nodes describe the different branches in the
+'gawk' repository and what they are for, as well as how to use your own
+branches.
+
+* Menu:
+
+* Repo State:: The different branch types in the repo.
+* Local State:: Managing local branches.
+* Remotes:: What a "remote" is.
+
+
+File: gawkworkflow.info, Node: Repo State, Next: Local State, Up: Branches are state
+
+2.4.1 Branches in the Savannah Repository
+-----------------------------------------
+
+There are several kinds of branches in the Savannah repository.
+
+"Dead Branches"
+ Branches with the prefix 'dead-branches/' (such as
+ 'dead-branches/const') hold code that was never merged into the
+ main code base. For example, a feature which was started, but
+ later deemed to be unwise to add. These branches keep the code
+ available, but they are not updated.
+
+"Stable Branches"
+ These branches are used for bug fixes to released versions of
+ 'gawk'. Sometimes new development (i.e., user-visible changes)
+ also occurs on these branches, although in a perfect world they
+ would be used only for bug fixes.
+
+ These branches have names like 'gawk-4.1-stable',
+ 'gawk-4.0-stable', and so on. Once a release has been made from
+ 'master', the previous stable branch is not updated. For example,
+ once 'gawk' 4.1.0 was released, no more work was done on
+ 'gawk-4.0-stable'.
+
+"The Main Branch"
+ This is the 'master' branch. Here is where most new feature
+ development takes place, and releases of new major versions are
+ based off of this branch.
+
+ Feature branches are typically based off this branch as well, and
+ when the feature is deemed complete, merged back into it.
+
+"Feature Branches"
+ Often, a proposed new feature or code improvement is quite
+ involved. It may take some time to perfect, or the 'gawk'
+ development team may not be convinced that the feature should be
+ kept.
+
+ For this purpose, the team uses branches prefixed with 'feature/'.
+ This prefix is used even for code that simply improves the
+ internals and does not make a user-visible change.
+
+ Having large changes on separate branches makes it easier for
+ members of the team to review the code, and also makes it easier to
+ keep the changes up-to-date with respect to 'master', since Git
+ excels at merging commits from one branch to another.
+
+
+File: gawkworkflow.info, Node: Local State, Next: Remotes, Prev: Repo State, Up: Branches are state
+
+2.4.2 Branches in Your Local Repository
+---------------------------------------
+
+Purely local branches are where you do your own development. You may
+use purely local branches because you don't have commit rights to the
+Savannah repo. You may also use them if you are doing some work that
+isn't ready for sharing with the rest of the team, or cannot be
+committed for some other reason.
+
+ For example, for around a nine-month period, the maintainer kept a
+purely local branch for some contributed changes for which paperwork had
+not yet been completed.
+
+
+File: gawkworkflow.info, Node: Remotes, Prev: Local State, Up: Branches are state
+
+2.4.3 A Closer Look at Branch Naming
+------------------------------------
+
+Earlier, we said that Git maintains copies of the branches in the
+upstream repo, as well as manages your local branches. You can see all
+these branches with 'git branch -a':
+
+ $ git branch -a
+ -| gawk-4.1-stable
+ -| * master
+ -| remotes/origin/HEAD -> origin/master
+ -| remotes/origin/dead-branches/async-events
+ -| ...
+ -| remotes/origin/feature/api-mpfr
+ -| remotes/origin/feature/array-iface
+ -| remotes/origin/feature/fix-comments
+ -| ...
+
+ You'll note that what we've referred to as 'origin/' branches appear
+in the output with an additional prefix: 'remotes/'. Up to this point,
+we've treated Git as if it allowed only a singled upstream repository.
+But in fact, you can configure it to use more than one. All the known
+upstream repositories are grouped under the 'remotes/' prefix, with
+'remotes/origin' being the one from which you initially cloned your
+local repository.
+
+ The ability to work with multiple upstream repositories is an
+advanced one; 'gawk' development does not make use of it. The intent of
+this node is to explain the output from 'git branch -a', nothing more.
+
+
+File: gawkworkflow.info, Node: Configuring git, Next: Development without commit access, Prev: Using Git, Up: Top
+
+3 Configuring Global Settings For Git
+*************************************
+
+Before starting to use Git, you should configure it with some important
+settings that won't change as you use Git. You may configure options
+both globally, and on a per-repository basis. Here, we discuss only
+global configuration settings.
+
+ You can configure Git using either 'git config', or by editing the
+relevant files with your favorite text editor.(1)
+
+ The first things to set are your email address and your real name:
+
+ $ git config --global user.name "J.P. Developer" Set full name
+ $ git config --global user.email jpdev@example.com Set email address
+
+ Setting these two items are an absolute requirement. *Note*: No
+aliases are allowed. If you can't supply your real name, you cannot
+contribute to the project. Other options that the 'gawk' maintainer
+recommends that you use are:
+
+ $ git config --global push.default=simple Only push current branch
+ $ git config --global pager.status=true Use pager for output of git status
+
+ The global settings are stored in the '.gitconfig' file in your home
+directory. The file looks like this:
+
+ [user]
+ name = J.P. Developer
+ email = jpdev@example.com
+ [push]
+ default = simple
+ [pager]
+ status = true
+
+ The 'push.default=simple' setting ensures that older versions of Git
+only push the current branch up to the Savannah repo. This is the
+safest way to operate, and is the default in current Git versions.
+
+ There may be other settings in your configuration file as well. Use
+'git config' to see your settings:
+
+ $ git config --list
+ -| user.name=J.P. Developer
+ -| user.email=jpdev@example.com
+ -| push.default=simple
+
+ Here are the 'gawk' maintainer's settings:
+
+ $ git config --global --list
+ -| user.name=Arnold D. Robbins
+ -| user.email=arnold@...
+ -| credential.helper=cache --timeout=3600
+ -| push.default=simple
+ -| color.ui=false
+ -| core.autocrlf=input
+ -| pager.status=true
+ -| log.decorate=auto
+
+ Additional, per-project ("local") settings are stored in each repo's
+'.git/config' file.
+
+ ---------- Footnotes ----------
+
+ (1) You are required to use either Vim or Emacs, other text editors
+are not allowed. Of course, reasonable developers wouldn't want to use
+any other editor anyway.
+
+
+File: gawkworkflow.info, Node: Development without commit access, Next: Development with commit access, Prev: Configuring git, Up: Top
+
+4 Development Without Commit Access
+***********************************
+
+In this chapter we present step-by-step recipes for checking out and
+working with a local copy of the Savannah Git repo for 'gawk'. The
+presentation is for when you do not have commit access to the Git repo,
+and so you cannot push your changes directly.
+
+* Menu:
+
+* Cloning:: Cloning the repo the first time.
+* Switching Branches:: Moving from one branch to another.
+* Starting A New Branch:: Starting a new branch for development.
+* Undoing a change:: Throwing away changes.
+* Updating:: Keeping in sync with the upstream repo.
+* Submitting Changes:: How to submit your changes.
+* Removing Branches:: Getting rid of unneeded branches.
+* Points to remember:: Things you need to keep in mind.
+
+
+File: gawkworkflow.info, Node: Cloning, Next: Switching Branches, Up: Development without commit access
+
+4.1 Cloning The Repo
+====================
+
+Clone the Savannah repo using 'git clone'. You may do so using either
+the native Git protocol, or using HTTP if you must go through a gateway
+or firewall that won't pass the Git protocol.
+
+ To choose which method, you supply a "URL" for the repo when you
+clone it, as follows.
+
+ * Clone via the Git native protocol:
+
+ $ git clone git://git.savannah.gnu.org/gawk.git Clone the repo
+ -| ...
+ $ cd gawk Start working
+
+ This will be faster, but not all firewalls pass the Git protocol on
+ through.
+
+ * Clone via the HTTP protocol:
+
+ $ git clone http://git.savannah.gnu.org/r/gawk.git Clone the repo
+ -| ...
+ $ cd gawk Start working
+
+ _You only need to clone the repo once._ From then on, you update its
+contents using other Git commands. For example, after coming back from
+your vacation in the Bahamas:
+
+ $ cd gawk Move to the repo
+ $ make distclean A good idea before updating
+ -| ...
+ $ git pull Update it
+
+ To build, you should generally follow this recipe:
+
+ $ ./bootstrap.sh && ./configure && make -j && make check
+
+ NOTE: Unless you have installed all the tools described in *note
+ GNU Tools::, you _must_ run './bootstrap.sh' every time you clone a
+ repo, do a 'git pull' or checkout a different branch. (In the
+ latter case, do 'make distclean' first.) Otherwise things will get
+ messy very quickly. The 'bootstrap.sh' script ensures that all of
+ the file time stamps are up to date so that it's not necessary to
+ run the various configuration tools.
+
+
+File: gawkworkflow.info, Node: Switching Branches, Next: Starting A New Branch, Prev: Cloning, Up: Development without commit access
+
+4.2 Switching Branches
+======================
+
+So far, we've been working in the default 'master' branch. Let's check
+what's happening in the 'gawk-4.1-stable' branch:
+
+ $ make distclean Clean up
+ $ git checkout gawk-4.1-stable Checkout a different branch
+ -| ...
+ $ git pull Get up to date
+ -| ...
+ $ ./bootstrap.sh && ./configure && make -j && make check Start working
+
+
+File: gawkworkflow.info, Node: Starting A New Branch, Next: Undoing a change, Prev: Switching Branches, Up: Development without commit access
+
+4.3 Starting A New Branch
+=========================
+
+Let's say you want to work on a new feature. For example, you might
+decide to add Python syntax support.(1) You should create a new branch
+on which to work. First, switch back to 'master':
+
+ $ make distclean
+ $ git checkout master
+
+ Now, create a new branch. The easiest way to do that is with the
+'-b' option to 'git checkout':
+
+ $ git checkout -b feature/python
+ -| ...
+
+ You now do massive amounts of work in order to add Python syntax
+support. As you do each defined chunk of work, you update the
+'ChangeLog' file with your changes before "committing" them to the repo.
+
+ Let's say you've added a new file 'python.c' and updated several
+others. Use 'git status' to see what's changed:
+
+ $ git status
+ -| ...
+
+ Before committing the current set of changes, you can use 'git diff'
+to view the changes. You may also use 'git difftool'(2) to run an
+external 'diff' command, such as 'meld' on GNU/Linux:
+
+ $ git diff Regular built-in tool
+ $ git difftool --tool=meld GUI diff tool
+
+ When you're happy with the changes, use 'git add' to tell Git which
+of the changed and/or new files you wish to have ready to be committed:
+
+ $ git add ...
+
+ Use 'git status' to see that your changes are scheduled for
+committing:
+
+ $ git status
+ -|
+
+ Now you can commit your changes to your branch:
+
+ $ git commit
+
+Running 'git commit' causes Git to invoke an editor (typically from the
+'$EDITOR' environment variable) in which you can compose a commit
+message. Please supply a short message summarizing the commit. This
+message will be visible via 'git log'.
+
+ ---------- Footnotes ----------
+
+ (1) Just joking. Please don't attempt this for real.
+
+ (2) Don't run 'git difftool' in the background; it works
+interactively.
+
+
+File: gawkworkflow.info, Node: Undoing a change, Next: Updating, Prev: Starting A New Branch, Up: Development without commit access
+
+4.4 Undoing A Change
+====================
+
+Should you need to undo a change that you have not yet committed (so
+that you can start over), you can do so on per-file basis by simply
+checking out the file again:
+
+ git checkout awkgram.y Undo changes to awkgram.y. There is no output
+
+ To start over completely, use 'git reset --hard'. Note that this
+will _throw away_ all your changes, with no chance for recovery, so be
+sure you really want to do it.
+
+
+File: gawkworkflow.info, Node: Updating, Next: Submitting Changes, Prev: Undoing a change, Up: Development without commit access
+
+4.5 Updating and Merging
+========================
+
+As you work on your branch, you will occasionally want to bring it up to
+date with respect to 'master'. This minor node discusses updating local
+branches and handling merge conflicts.
+
+* Menu:
+
+* Rebasing:: Rebasing A Local Branch.
+* Merge Conflicts:: Dealing With Merge Conflicts.
+
+
+File: gawkworkflow.info, Node: Rebasing, Next: Merge Conflicts, Up: Updating
+
+4.5.1 Rebasing A Local Branch
+-----------------------------
+
+For purely local branches, bringing your branch up to date is called
+"rebasing", which causes the branch to look _as if_ you had started from
+the latest version of 'master'. The steps are as follows:
+
+ $ git checkout master Checkout master
+ $ git pull Update it
+ $ git checkout feature/python Move back to new, purely local branch
+ $ git rebase master "Start over" from current master
+
+
+File: gawkworkflow.info, Node: Merge Conflicts, Prev: Rebasing, Up: Updating
+
+4.5.2 Dealing With Merge Conflicts
+----------------------------------
+
+Sometimes, when merging from 'master' into your branch, or from a branch
+into 'master', there will be "merge conflicts". These are one or more
+areas within a file where there are conflicting sets of changes, and Git
+could not do the merge for you. In this case, the conflicted area will
+be delimited by the traditional conflict markers, '<<<', '===' and
+'>>>'.
+
+ Your mission is then to edit the file and "resolve" the conflict by
+fixing the order of additions (such as in a 'ChangeLog' file), or fixing
+the code to take new changes into account.
+
+ Once you have done so, you tell Git that everything is OK using 'git
+add' and 'git commit':
+
+ $ git checkout feature/python Move back to new, purely local branch
+ $ git rebase master "Start over" from current master
+ -| ... Kaboom! Conflict. FIXME: Show real output here
+ $ gvim main.c Edit the file and fix the problem
+ $ git add main.c Tell Git everything is OK now ...
+ $ git commit ... and it's settled
+ $ git rebase --continue Continue the rebase
+
+ The 'git rebase --continue' then continues the process of rebasing
+the current branch that we started in *note Rebasing::. It's not
+necessary if you are using 'git merge' (*note Points to remember::).
+
+
+File: gawkworkflow.info, Node: Submitting Changes, Next: Removing Branches, Prev: Updating, Up: Development without commit access
+
+4.6 Submitting Your Changes
+===========================
+
+So now your feature is complete. You've added test cases for it to the
+test suite(1), you have 'ChangeLog' entries that describe all the
+changes(2), you have documented the new feature(3), and everything works
+great. You're ready to submit the changes for review, and with any
+luck, inclusion into 'gawk'.
+
+ There are two ways to submit your changes for review.
+
+_Generate a single large patch_
+ To do this, simply compare your branch to the branch off which it
+ is based:
+
+ $ git checkout feature/python
+ $ git diff master > /tmp/python.diff
+
+ Mail the 'python.diff' file to the appropriate mailing list along
+ with a description of what you've changed and why.
+
+_Generate a set of patches that in toto comprise your changes_
+ To do this, use 'git format-patch':
+
+ $ git checkout feature/python
+ $ git format-patch
+
+ This creates a set of patch files, one per commit that isn't on the
+ original branch. Mail these patches, either separately, or as a
+ set of attachments, to the appropriate mailing list along with a
+ description of what you've changed and why.
+
+ Either way you choose to submit your changes, the 'gawk' maintainer
+and development team will review your changes and provide feedback. If
+you have signed paperwork with the FSF for 'gawk' and the maintainer
+approves your changes, he will apply the patch(es) and commit the
+changes.
+
+ Which list should you send mail to? If you are just starting to
+contribute, use <bug-gawk@gnu.org>. After making enough contributions,
+you may be invited to join the private 'gawk' developers' mailing list.
+If you do so, then submit your changes to that list.
+
+ If you make any substantial changes, you will need to assign
+copyright in those changes to the Free Software Foundation before the
+maintainer can commit those changes. *Note Doing paperwork::, for more
+information.
+
+ ---------- Footnotes ----------
+
+ (1) You did do this, didn't you?
+
+ (2) You remembered this, right?
+
+ (3) You wouldn't neglect this, would you?
+
+
+File: gawkworkflow.info, Node: Removing Branches, Next: Points to remember, Prev: Submitting Changes, Up: Development without commit access
+
+4.7 Removing Branches
+=====================
+
+Once the maintainer has integrated your changes, you can get rid of your
+local branch:
+
+ $ git checkout master Move to upstream branch
+ $ git pull Update
+ $ gvim ChangeLog ... Verify your changes are in
+ $ git branch -d feature/python Remove your local branch
+
+
+File: gawkworkflow.info, Node: Points to remember, Prev: Removing Branches, Up: Development without commit access
+
+4.8 Points to Remember
+======================
+
+There are some important points to remember:
+
+ * Always do a 'make distclean' before switching between branches.
+ Things will get really confused if you don't.
+
+ * For upstream branches, _always_ work with tracking branches.
+ _Never_ use 'git checkout origin/WHATEVER'. Git will happily let
+ you do something like that, but it's just plain asking for trouble.
+
+ * Make sure your tracking branches are up-to-date before doing
+ anything with them, particularly using them as the basis for a
+ rebase or merge. This typically means a three-step process:
+
+ $ git checkout master Get to local copy
+ $ git pull Bring it up to date
+ $ git checkout feature/python Go back to your branch
+
+ You can then do the actual rebase:
+
+ $ git rebase master Now rebase your feature off of master
+
+ * Git always treats the currently checked-out branch as the object of
+ operations. For example, when comparing files with the regular
+ 'diff' command, the usage is 'diff OLDFILE NEWFILE'. For 'git
+ diff', the current branch takes the place of NEWFILE, thus:
+
+ $ git checkout feature/python
+ $ git diff master Compare master to current branch
+
+ or if merging:
+
+ $ git checkout master Checkout master
+ $ git pull Update tracking branch
+ $ git merge feature/python Merge changes into master
+
+
+File: gawkworkflow.info, Node: Development with commit access, Next: General practices, Prev: Development without commit access, Up: Top
+
+5 Development With Commit Access
+********************************
+
+This major node describes how to do development when you _do_ have
+commit access to the 'gawk' repo on Savannah.
+
+* Menu:
+
+* Initial setup:: Getting started with commit access.
+* ssh clone:: Cloning using an 'ssh://' URL.
+* Developing patches:: Developing patches.
+* Developing new features:: Developing new features.
+* Developing fixes:: Developing fixes.
+
+
+File: gawkworkflow.info, Node: Initial setup, Next: ssh clone, Up: Development with commit access
+
+5.1 Initial Setup
+=================
+
+Congratulations! After becoming a quality contributor to 'gawk'
+development, you've been invited to join the private development list
+and to accept having commit access to the repo.
+
+ The first thing to do is to create an account on Savannah, choosing a
+unique user name. To do so, go to the Savannah home page
+(http://savannah.gnu.org) and click on the "New User" link. The setup
+will include uploading of your 'ssh' key, as per the instructions on the
+Savannah web page.
+
+ After you've done all this, send email to the maintainer with your
+Savannah user name, and he will add you to the list of users who have
+commit access to the repo.
+
+
+File: gawkworkflow.info, Node: ssh clone, Next: Developing patches, Prev: Initial setup, Up: Development with commit access
+
+5.2 Cloning The Repo With An 'ssh' URL
+======================================
+
+In order to be able to commit changes to the repo, you must clone it
+using an 'ssh://' URL. Cloning the repo with 'ssh' is similar to cloning
+with the Git protocol or with HTTP, but the URL is different:
+
+ $ git clone ssh://yourname@git.sv.gnu.org/srv/git/gawk.git
+ -| ...
+
+ Here, you should replace 'yourname' in the command with the user name
+you chose for use on Savannah.
+
+
+File: gawkworkflow.info, Node: Developing patches, Next: Developing new features, Prev: ssh clone, Up: Development with commit access
+
+5.3 Developing Patches
+======================
+
+The first part of developing a patch is the same as for developers
+without commit access:
+
+ 1. Develop the code and test it.
+
+ 2. Update the 'ChangeLog'.
+
+ 3. If necessary, update the documentation: 'doc/gawktexi.in' and/or
+ 'doc/gawk.1'.
+
+ 4. Use 'git diff > mychange.diff' to create a patch file.
+
+ 5. Send it to the mailing list for discussion.
+
+ 6. Iterate until the patch is ready to be committed.
+
+ However, now that you have commit access, you can commit the fix and
+push it up to the repo yourself! Let's assume you've made a bug fix
+directly on 'master'. Here's how to commit your changes:
+
+ $ git diff Review the patch one more time
+ $ git add ... Add any files for committing
+ $ git commit Commit the files. Include a commit message.
+ $ git push Push the files up to the repo. Ta da!
+
+ The first three steps are the same described earlier (*note Starting
+A New Branch::). The 'git push' is what's new, and it updates the repo
+on Savannah. Congratulations!
+
+ As a courtesy, you should send a note to the mailing list indicating
+that you have pushed your change.
+
+
+File: gawkworkflow.info, Node: Developing new features, Next: Developing fixes, Prev: Developing patches, Up: Development with commit access
+
+5.4 Developing New Features
+===========================
+
+Developing a new feature can be easier once you have commit access to
+the repo. First, create a new branch to hold your feature:
+
+ $ git checkout master Start from master
+ $ git pull Be sure to be up to date
+ $ git checkout -b feature/python Create and switch to a new branch
+
+ Now, you can develop as normal, adding new files if necessary (such
+as new tests), modifying code, updating the 'ChangeLog' and
+documentation, and so on.
+
+ You can share changes with the mailing list as diffs, as usual.
+However, especially for a large feature, it would be better to push your
+branch up to Savannah. Then, everyone else can simply pull it down to
+their local systems and review your changes at their leisure.
+
+ To push your branch up initially:
+
+ $ git diff Review your changes
+ $ git add ... Add any files for committing
+ $ git commit Commit the files. Include a commit message
+ $ git push -u origin feature/python Push the branch up to the repo
+
+ When you use 'push -u origin', Git helpfully converts your purely
+local branch into a tracking branch. It becomes as if the branch had
+originated from the upstream repo and you checked it out locally.
+
+ _You only need to do 'git push -u origin' once._ As you continue to
+work on your branch, the workflow simplifies into this:
+
+ $ git diff Review your changes
+ $ git add ... Add any files for committing
+ $ git commit Commit the files
+ $ git push Push your changes to the branch upstream
+
+
+File: gawkworkflow.info, Node: Developing fixes, Prev: Developing new features, Up: Development with commit access
+
+5.5 Developing Fixes
+====================
+
+If you want to make a fix on 'master' or on the current stable branch,
+you work the same way, by producing and discussing a diff on the mailing
+list. Once it's approved, you can commit it yourself:
+
+ $ git checkout master Move to master
+ $ git pull Make sure we're up to date with the maintainer
+ $ gvim ... Make any fixes, compile, test
+ $ git diff Review your changes
+ $ git add ... Add any files for committing
+ $ git commit Commit the files. Include a commit message.
+
+ When you're ready to push your changes:
+
+ $ git pull Download latest version; Git will merge
+ $ gvim ... Resolve any merge conflicts with git add and git commit
+ $ git push Now you can push your changes upstream
+
+ *Note Merge Conflicts:: for instructions on dealing with merge
+conflicts.
+
+
+File: gawkworkflow.info, Node: General practices, Next: Repo Maintenance, Prev: Development with commit access, Up: Top
+
+6 General Development Practices
+*******************************
+
+This major node discusses general practices for 'gawk' development. The
+discussion here is mainly for developers with commit access to the
+Savannah repo.
+
+"Propagating Fixes"
+ Usually, bug fixes should be made on the current "stable" branch.
+ Once a fix has been reviewed and approved, you can commit it and
+ push it yourself. Typically, the maintainer then takes care to
+ merge the fix to 'master' and from there to any other branches.
+ However, you are welcome to save him the time and do this yourself.
+
+"Directory ownership"
+ Some developers "own" certain parts of the tree, such as the 'pc'
+ and 'vms' directories. They are allowed to commit changes to those
+ directories without review by the mailing list, but changes that
+ also touch the mainline code should be submitted for review.
+
+"New feature development"
+ Unless you can convince the maintainer (and the other developers!)
+ otherwise, you should _always_ start branches for new features from
+ 'master', and not from the current "stable" branch.
+
+ Use 'checkout -b feature/FEATURE_NAME' to create the initial
+ branch. You may then elect to keep it purely local, or to push it
+ up to Savannah for review, even if the feature is not yet totally
+ "ready for prime time."
+
+ During development of a new feature, you will most likely wish to
+keep your feature branch up to date with respect to ongoing improvements
+in 'master'. This is generally easy to do. There are two different
+mechanisms, and which one you use depends upon the nature of your new
+feature branch.
+
+"As long as your branch is purely local"
+ You should use 'git rebase' to the keep the branch synchronized
+ with the original branch from which it was forked:
+
+ $ git checkout master Move to master
+ $ git pull Bring it up to date
+ $ git checkout feature/python Move to your new feature branch
+ $ git rebase master Rebase from master
+
+ The rebasing operation may require that you resolve conflicts
+ (*note Merge Conflicts::). Edit any conflicted files and resolve
+ the problem(s). Compile and test your changes, then use 'git add'
+ and 'git commit' to indicate resolution, and then use 'git rebase
+ --continue' to continue the rebasing. Git is very good about
+ providing short instructions on how to continue when such conflicts
+ occur.
+
+"Once the branch has been pushed up to Savannah"
+ You _must_ use 'git merge' to bring your feature branch up to date.
+ That flow looks like this:
+
+ $ git checkout master Move to master
+ $ git pull Bring it up to date
+ $ git checkout feature/python Move to your new feature branch
+ $ git merge master Merge from master
+
+ Here too, you may have to resolve any merge conflicts (*note Merge
+ Conflicts::). Once that's done, you can push the changes up to
+ Savannah.
+
+ When the changes on your branch are complete, usually the
+ maintainer merges the branch to 'master'. But there's really no
+ magic involved, the merge is simply done in the other direction:
+
+ $ git checkout feature/python Checkout feature branch
+ $ git pull Bring it up to date
+ $ git checkout master Checkout master
+ $ git pull Bring it up to date
+ $ git merge feature/python Merge from feature/python into master
+
+ If you've been keeping 'feature/python' in sync with 'master', then
+ there should be no merge conflicts to resolve, and you can push the
+ result to Savannah:
+
+ $ git push Push up to Savannah
+
+ Since 'feature/python' is no longer needed, it can be gotten rid
+ of:
+
+ $ git branch -d feature/python Still on master, delete feature branch
+ $ git push -u origin -d feature/python Delete the branch on Savannah
+
+ The 'git push' command deletes the 'feature/python' branch from the
+ Savannah repo.
+
+ Finally, you should send an email to developer's list describing
+ what you've done so that everyone else can delete their copies of
+ the branch and do a 'git fetch --prune' (*note Repo Maintenance::).
+
+ To update the other remaining development branches with the latest
+ changes on 'master', use the 'helpers/update-branches.sh' script in
+ the repo.
+
+
+File: gawkworkflow.info, Node: Repo Maintenance, Next: Development Stuff, Prev: General practices, Up: Top
+
+7 Keeping Your Repo Organized
+*****************************
+
+There are a few commands you should know about to help keep your local
+repo clean.
+
+_Removing old branches_
+ Developers add branches to the Savannah repo and when development
+ on them is done, they get merged into 'master'. Then the branches
+ on Savannah are deleted (as shown in *note General practices::).
+
+ However, your local copies of those branches (labelled with the
+ 'origin/' prefix) remain in your local repo. If you don't need
+ them, then you can clean up your repo as follows.
+
+ First, remove any related tracking branch you may have:
+
+ $ git pull Get up to date
+ $ git branch -d feature/merged-feature Remove tracking branch
+
+ Then, ask Git to clean things up for you:
+
+ $ git fetch --prune Remove unneeded branches
+
+_Removing cruft_
+ As Git works, occasional "cruft" collects in the repository. Git
+ does occasionally clean this out on its own, but if you're
+ concerned about disk usage, you can do so yourself using 'git gc'
+ (short for "garbage collect"). For example:
+
+ $ du -s . Check disk usage
+ -| 99188 . Almost 10 megabytes
+ $ git gc Collect garbage
+ -| Counting objects: 32114, done.
+ -| Delta compression using up to 4 threads.
+ -| Compressing objects: 100% (6370/6370), done.
+ -| Writing objects: 100% (32114/32114), done.
+ -| Total 32114 (delta 25655), reused 31525 (delta 25231)
+ $ du -s . Check disk usage again
+ -| 75168 . Down to 7 megabytes
+
+_Renaming branches_
+ Occasionally you may want to rename a branch.(1) If your branch is
+ local and you are on it, us:
+
+ $ git branch -m feature/NEW-NAME
+
+ Otherwise, use:
+
+ $ git branch -m feature/OLD-NAME feature/NEW-NAME
+
+ You then need to fix the upstream repo. This command does so,
+ using an older syntax to simultaneously delete the old name and
+ push the new name. You should be on the new branch:
+
+ $ git push origin :feature/OLD-NAME feature/NEW-NAME
+
+ NOTE: It is the leading ':' in the first branch name that
+ causes Git to delete the old name in the upstream repo. Don't
+ omit it!
+
+ Finally, reset the upstream branch for the local branch with the
+ new name:
+
+ $ git push -u origin feature/NEW-NAME
+
+ ---------- Footnotes ----------
+
+ (1) This discussion adopted from here
+(https://multiplestates.wordpress.com/2015/02/05/rename-a-local-and-remote-branch-in-git).
+
+
+File: gawkworkflow.info, Node: Development Stuff, Next: Cheat Sheet, Prev: Repo Maintenance, Up: Top
+
+8 Development Stuff
+*******************
+
+This major node discusses other things you need to know and/or do if
+you're going to participate seriously in 'gawk' development.
+
+* Menu:
+
+* Coding style:: Where to read up on the coding style.
+* Doing paperwork:: Legal stuff in order to contribute.
+* Tools:: Tools to have on your system for development.
+* Debugging:: Compiling for debugging.
+
+
+File: gawkworkflow.info, Node: Coding style, Next: Doing paperwork, Up: Development Stuff
+
+8.1 Coding Style
+================
+
+You should read the discussion about adding code in the 'gawk'
+documentation. *Note Additions: (gawk)Additions, for a discussion of
+the general procedure. In particular, pay attention to the coding style
+guidelines in *note Adding Code: (gawk)Adding Code.(1) These two
+sections may also be found online, at
+<https://www.gnu.org/software/gawk/manual/html_node/Additions.html#Additions>,
+and
+<https://www.gnu.org/software/gawk/manual/html_node/Adding-Code.html#Adding-Code>,
+respectively.
+
+ ---------- Footnotes ----------
+
+ (1) Changes that don't follow the coding style guidelines won't be
+accepted. Period.
+
+
+File: gawkworkflow.info, Node: Doing paperwork, Next: Tools, Prev: Coding style, Up: Development Stuff
+
+8.2 Assigning Copyrights to the FSF
+===================================
+
+For any change of more than just a few lines, you will need to assign
+copyright in (that is, ownership of) those changes to the Free Software
+Foundation.
+
+ This is generally an easy thing to do. In particular, you can choose
+to use a version of the copyright assignment which assigns all your
+current _and future_ changes to 'gawk' to the FSF. This means that you
+only need to do the paperwork once, and from then on all your changes
+will automatically belong to the FSF. The maintainer recommends doing
+this.
+
+ The maintainer will help you with this process once you have a
+contribution that warrants it.
+
+
+File: gawkworkflow.info, Node: Tools, Next: Debugging, Prev: Doing paperwork, Up: Development Stuff
+
+8.3 Software Tools You Will Need
+================================
+
+This minor node discusses additional tools that you may need to install
+on your system in order to be in sync with what the 'gawk' maintainer
+uses. It also discusses different C compiler options for use during
+code development, and how to compile 'gawk' for debugging.
+
+* Menu:
+
+* GNU Tools:: The GNU Autotools.
+* Compilers:: A discussion of compilers that can be used.
+
+
+File: gawkworkflow.info, Node: GNU Tools, Next: Compilers, Up: Tools
+
+8.3.1 GNU Tools
+---------------
+
+If you expect to work with the configuration files and/or the 'Makefile'
+files, you will need to install a number of other GNU tools. In
+general, you should be using the latest versions of the tools, or least
+the same ones that the maintainer himself uses. This helps minimize the
+differences that the maintainer has to resolve when merging changes, and
+in general avoids confusion and hassle. Similarly, you should install
+the latest GNU documentation tools as well. The tools are described in
+the following list:
+
+'autoconf'
+ GNU Autoconf processes the 'configure.ac' files in order to
+ generate the 'configure' shell script and 'config.h.in' input file.
+ See the Autoconf home page
+ (https://www.gnu.org/software/autoconf/autoconf.html) for more
+ information.
+
+'automake'
+ GNU Automake processes the 'configure.ac' and 'Makefile.am' files
+ to produce 'Makefile.in' files. See the Automake home page
+ (https://www.gnu.org/software/automake) for more information.
+
+'gettext'
+ GNU Gettext processes the 'gawk' source code to produce the
+ original 'po/gawk.pot' message template file. Normally you should
+ not need need to do this; the maintainer usually manages this task.
+ See the Gettext home page (https://www.gnu.org/software/gettext)
+ for more information.
+
+'libtool'
+ GNU Libtool works with Autoconf and Automake to produce portable
+ shared libraries. It is used for the extensions that ship with
+ 'gawk', whose code is in the 'extensions' directory. See the
+ Libtool home page (https://www.gnu.org/software/libtool) for more
+ information.
+
+'makeinfo'
+ The 'makeinfo' command is used to build the Info versions of the
+ documentation. You need to have the same version as the maintainer
+ uses, so that when you make a change to the documentation, the
+ corresponding change to the generated Info file will be minimal.
+ 'makeinfo' is part of GNU Texinfo. See the Texinfo home page
+ (https://www.gnu.org/software/texinfo) for more information.
+
+
+File: gawkworkflow.info, Node: Compilers, Prev: GNU Tools, Up: Tools
+
+8.3.2 Compilers
+---------------
+
+The default compiler for 'gawk' development is GCC, the GNU Compiler
+Collection (https://gcc.gnu.org). The default version of GCC is
+whatever is on the maintainer's personal GNU/Linux system, although he
+does try to build the latest released version if that is newer than
+what's on his system, and then occasionally test 'gawk' with it.
+
+ He also attempts to test occasionally with 'clang'
+(https://clang.llvm.org/). However, he uses whatever is the default for
+his GNU/Linux system, and does _not_ make an effort to build the current
+version for testing.
+
+ Both GCC and 'clang' are highly optimizing compilers that produce
+good code, but are very slow. There are two other compilers that are
+faster, but that may not produce quite as good code. However, they are
+both reasonable for doing development.
+
+_The Tiny C Compiler, 'tcc'_
+ This compiler is _very_ fast, but it produces only mediocre code.
+ It is capable of compiling 'gawk', and it does so well enough that
+ 'make check' runs without errors.
+
+ However, in the past the quality has varied, and the maintainer has
+ had problems with it. He recommends using it for regular
+ development, where fast compiles are important, but rebuilding with
+ GCC before doing any commits, in case 'tcc' has missed
+ something.(1)
+
+ See the project's home page (http://www.tinycc.org) for some
+ information. More information can be found in the project's Git
+ repository (http://repo.or.cz/tinycc.git). The maintainer builds
+ from the 'mob' branch for his work, but after updating it you
+ should check that this branch still works to compile 'gawk' before
+ installing it.
+
+_The (Revived) Portable C Compiler_
+ This is an updated version of the venerable Unix Portable C
+ Compiler, PCC. It accepts ANSI C syntax and supports both older and
+ modern architectures. It produces better code than 'tcc' but is
+ slower, although still much faster than GCC and 'clang'.
+
+ See the project's home page (http://pcc.ludd.ltu.se) for more
+ information. See <http://pcc.ludd.ltu.se/supported-platforms> for
+ instructions about obtaining the code using CVS and building it.
+
+ An alternative location for the source is the 'gawk' maintainer's
+ Git mirror (https://github.com/arnoldrobbins/pcc-revived) of the
+ code.
+
+ ---------- Footnotes ----------
+
+ (1) This bit the maintainer once.
+
+
+File: gawkworkflow.info, Node: Debugging, Prev: Tools, Up: Development Stuff
+
+8.4 Compiling For Debugging
+===========================
+
+If you wish to compile for debugging, you should use GCC. After running
+'configure' but before running 'make', edit the 'Makefile' and remove
+the '-O2' flag from the definition of 'CFLAGS'. Optionally, do the same
+for 'extensions/Makefile'. Then run 'make'.
+
+ You can enable additional debugging code by creating a file named
+'.developing' in the 'gawk' source code directory _before_ running
+'configure'. Doing so enables additional conditionally-compiled
+debugging code within 'gawk', and adds additional warning and debugging
+options if compiling with GCC.
+
+
+File: gawkworkflow.info, Node: Cheat Sheet, Next: Resources, Prev: Development Stuff, Up: Top
+
+Appendix A Git Command Cheat Sheet
+**********************************
+
+This major node provides an alphabetical list of the Git commands cited
+in this Info file, along with brief descriptions of what the commands
+do.
+
+ Note that you may always use either 'git help COMMAND' or 'git
+COMMAND --help' to get short, man-page style help on how to use any
+given Git command.
+
+'git add'
+ Add a file to the list of files to be committed.
+
+'git branch'
+ View existing branches, or delete a branch. Most useful options:
+ '-a' and '-d'.
+
+'git checkout'
+ Checkout an existing branch, create a new branch, or checkout a
+ file to reset it. Use the '-b' option to create and checkout a new
+ branch in one operation.
+
+'git clone'
+ Clone (make a new copy of) an existing repository. You generally
+ only need to do this once.
+
+'git commit'
+ Commit changes to files which have been staged for committing with
+ 'git add'. This makes your changes permanent, _in your local
+ repository only_. To publish your changes to an upstream repo, you
+ must use 'git push'.
+
+'git config'
+ Display and/or change global and/or local configuration settings.
+
+'git diff'
+ Show a unified-format diff of what's changed in the current
+ directory as of the last commit. It helps to have Git configured
+ to use its builtin pager for reviewing diffs (*note Configuring
+ git::).
+
+'git difftool'
+ Use a "tool" (usually a GUI-based program) to view differences,
+ instead of the standard textual diff as you'd get from 'git diff'.
+
+'git fetch'
+ Update your local copy of the upstream's branches. That is, update
+ the various 'origin/' branches. This leaves your local tracking
+ branches unchanged. With the '--prune' option, this removes any
+ copies of stale 'origin/' branches.
+
+'git format-patch'
+ Create a series of patch files, one per commit not on the original
+ branch from which you started.
+
+'git gc'
+ Run a "garbage collection" pass in the current repository. This
+ can often reduce the space used in a large repo. For 'gawk' it
+ does not make that much difference.
+
+'git help'
+ Print a man-page-style usage summary for a command.
+
+'git log'
+ Show the current branch's commit log. This includes who made the
+ commit, the date, and the commit message. Commits are shown from
+ newest to oldest.
+
+'git merge'
+ Merge changes from the named branch into the current one.
+
+'git pull'
+ When in your local tracking branch 'XXX', run 'git fetch', and then
+ merge from 'origin/XXX' into 'XXX'.
+
+'git push'
+ Push commits from your local tracking branch 'XXX' through
+ 'origin/XXX' and on to branch 'XXX' in the upstream repo. Use 'git
+ push -u origin -d XXX' to delete an upstream branch. (Do so
+ carefully!)
+
+'git rebase'
+ Rebase the changes in the current purely local branch to look as if
+ they had been made relative to the latest commit in the current
+ upstream branch (typically 'master'). This is how you keep your
+ local, in-progress changes up-to-date with respect to the original
+ branch from which they were started.
+
+'git reset'
+ Restore the original state of the repo, especially with the
+ '--hard' option. Read up on this command, and use it carefully.
+
+'git status'
+ Show the status of files that are scheduled to be committed, and
+ those that have been modified but not yet scheduled for committing.
+ Use 'git add' to schedule a file for committing. This command also
+ lists untracked files.
+
+
+File: gawkworkflow.info, Node: Resources, Next: TODO, Prev: Cheat Sheet, Up: Top
+
+Appendix B Git Resources
+************************
+
+There are many Git resources available on the Internet. Start at the
+Git Project home page (http://git-scm.org). In particular, the 'Pro
+Git' book (https://git-scm.com/book/en/v2) is available online.
+
+ See also the Savannah quick introduction to Git
+(http://savannah.gnu.org/maintenance/UsingGit).
+
+
+File: gawkworkflow.info, Node: TODO, Next: Index, Prev: Resources, Up: Top
+
+Appendix C Stuff Still To Do In This Document
+*********************************************
+
+ * Fill out all examples with full output
+
+
+File: gawkworkflow.info, Node: Index, Prev: TODO, Up: Top
+
+Index
+*****
+
+
+* Menu:
+
+* --help option for git: Cheat Sheet. (line 10)
+* .developing file: Debugging. (line 11)
+* .gitconfig file: Configuring git. (line 27)
+* account, Savannah, creation of: Initial setup. (line 10)
+* assigning copyright: Doing paperwork. (line 6)
+* autoconf: GNU Tools. (line 15)
+* automake: GNU Tools. (line 22)
+* autotools: GNU Tools. (line 6)
+* Bernat, Yehezkel: Acknowledgments. (line 10)
+* bootstrap.sh script: Cloning. (line 41)
+* branch, main: Repo State. (line 27)
+* branch, master: Repo State. (line 27)
+* branches, dead: Repo State. (line 8)
+* branches, feature: Repo State. (line 35)
+* branches, local: Local Branches. (line 6)
+* branches, origin/: Repo Copies. (line 68)
+* branches, purely local: Local State. (line 6)
+* branches, removing: Removing Branches. (line 6)
+* branches, removing <1>: Repo Maintenance. (line 9)
+* branches, renaming: Repo Maintenance. (line 44)
+* branches, stable: Repo State. (line 15)
+* branches, tracking: Local Branches. (line 11)
+* ChangeLog file: Starting A New Branch.
+ (line 19)
+* ChangeLog file <1>: Developing patches. (line 11)
+* changes, submitting for review: Submitting Changes. (line 12)
+* clang compiler: Compilers. (line 12)
+* coding style: Coding style. (line 6)
+* committing changes: Starting A New Branch.
+ (line 19)
+* compilers: Compilers. (line 6)
+* compiling for debugging: Debugging. (line 6)
+* configuration setting, pager.status: Configuring git. (line 24)
+* configuration setting, push.default: Configuring git. (line 24)
+* configuration setting, user.email: Configuring git. (line 16)
+* configuration setting, user.name: Configuring git. (line 16)
+* configuration settings: Configuring git. (line 6)
+* configuration settings, global: Configuring git. (line 6)
+* configure.ac file: GNU Tools. (line 15)
+* conflicts, from merging: Merge Conflicts. (line 6)
+* copyright, assignment: Doing paperwork. (line 6)
+* cruft, removing: Repo Maintenance. (line 27)
+* dead branches: Repo State. (line 8)
+* debugging, compiling for: Debugging. (line 6)
+* directory ownership: General practices. (line 17)
+* documentation files: Developing patches. (line 13)
+* email address: Configuring git. (line 14)
+* extensions, gawk: GNU Tools. (line 34)
+* feature branches: Repo State. (line 35)
+* fixes, propagating to other branches: General practices. (line 10)
+* gawk.1 manual page: Developing patches. (line 13)
+* gawk.pot file: GNU Tools. (line 27)
+* gawktexi.in documentation: Developing patches. (line 13)
+* GCC, the GNU Compiler Collection: Compilers. (line 6)
+* generating a single patch: Submitting Changes. (line 14)
+* generating multiple patches: Submitting Changes. (line 24)
+* gettext: GNU Tools. (line 27)
+* git add: Starting A New Branch.
+ (line 36)
+* git add <1>: Developing patches. (line 26)
+* git add <2>: Developing new features.
+ (line 24)
+* git add <3>: Developing new features.
+ (line 36)
+* git add <4>: Developing fixes. (line 10)
+* git branch: Repo Copies. (line 38)
+* git branch <1>: Removing Branches. (line 9)
+* git branch <2>: General practices. (line 88)
+* git branch <3>: Repo Maintenance. (line 20)
+* git branch command, -a option: Remotes. (line 6)
+* git checkout: Local Branches. (line 11)
+* git checkout <1>: Switching Branches. (line 9)
+* git checkout <2>: Starting A New Branch.
+ (line 10)
+* git checkout <3>: Undoing a change. (line 10)
+* git checkout <4>: Rebasing. (line 10)
+* git checkout <5>: Submitting Changes. (line 18)
+* git checkout <6>: Submitting Changes. (line 27)
+* git checkout <7>: Removing Branches. (line 9)
+* git checkout <8>: Points to remember. (line 19)
+* git checkout <9>: Points to remember. (line 32)
+* git checkout <10>: Points to remember. (line 37)
+* git checkout <11>: Developing new features.
+ (line 9)
+* git checkout <12>: Developing fixes. (line 10)
+* git checkout <13>: General practices. (line 43)
+* git checkout <14>: General practices. (line 60)
+* git checkout <15>: General practices. (line 73)
+* git clone: Repo Copies. (line 42)
+* git clone <1>: Cloning. (line 6)
+* git clone <2>: ssh clone. (line 10)
+* git command, --help option: Cheat Sheet. (line 10)
+* git commit: Starting A New Branch.
+ (line 49)
+* git commit <1>: Developing patches. (line 26)
+* git commit <2>: Developing new features.
+ (line 24)
+* git commit <3>: Developing new features.
+ (line 36)
+* git commit <4>: Developing fixes. (line 10)
+* git config: Configuring git. (line 11)
+* git diff: Starting A New Branch.
+ (line 29)
+* git diff <1>: Submitting Changes. (line 18)
+* git diff <2>: Points to remember. (line 32)
+* git diff <3>: Developing patches. (line 16)
+* git diff <4>: Developing patches. (line 26)
+* git diff <5>: Developing new features.
+ (line 24)
+* git diff <6>: Developing new features.
+ (line 36)
+* git diff <7>: Developing fixes. (line 10)
+* git difftool: Starting A New Branch.
+ (line 29)
+* git fetch: General practices. (line 94)
+* git fetch <1>: Repo Maintenance. (line 25)
+* git format-patch: Submitting Changes. (line 24)
+* git gc: Repo Maintenance. (line 33)
+* git help: Cheat Sheet. (line 10)
+* git log: Starting A New Branch.
+ (line 51)
+* git merge: Points to remember. (line 37)
+* git merge <1>: General practices. (line 60)
+* git merge <2>: General practices. (line 73)
+* Git Project: Preface. (line 10)
+* git pull: Cloning. (line 32)
+* git pull <1>: Switching Branches. (line 9)
+* git pull <2>: Rebasing. (line 10)
+* git pull <3>: Removing Branches. (line 9)
+* git pull <4>: Points to remember. (line 19)
+* git pull <5>: Points to remember. (line 37)
+* git pull <6>: Developing new features.
+ (line 9)
+* git pull <7>: Developing fixes. (line 10)
+* git pull <8>: Developing fixes. (line 19)
+* git pull <9>: General practices. (line 43)
+* git pull <10>: General practices. (line 60)
+* git pull <11>: General practices. (line 73)
+* git pull <12>: Repo Maintenance. (line 20)
+* git push: Local Branches. (line 16)
+* git push <1>: Developing patches. (line 26)
+* git push <2>: Developing new features.
+ (line 24)
+* git push <3>: Developing new features.
+ (line 36)
+* git push <4>: Developing fixes. (line 19)
+* git push <5>: General practices. (line 83)
+* git push <6>: General practices. (line 88)
+* git rebase: Rebasing. (line 10)
+* git rebase <1>: Points to remember. (line 25)
+* git rebase <2>: General practices. (line 43)
+* git reset: Undoing a change. (line 12)
+* git reset, --hard option: Cheat Sheet. (line 93)
+* git status: Starting A New Branch.
+ (line 23)
+* git status <1>: Starting A New Branch.
+ (line 41)
+* GitHub: Contributing. (line 57)
+* global configuration settings: Configuring git. (line 6)
+* GNU autoconf: GNU Tools. (line 15)
+* GNU automake: GNU Tools. (line 22)
+* GNU gettext: GNU Tools. (line 27)
+* GNU libtool: GNU Tools. (line 34)
+* GNU makeinfo: GNU Tools. (line 41)
+* GNU software tools: GNU Tools. (line 6)
+* GNU Texinfo: GNU Tools. (line 41)
+* Kahrs, Ju"rgen: Acknowledgments. (line 6)
+* libtool: GNU Tools. (line 34)
+* local branches: Local Branches. (line 6)
+* main branch: Repo State. (line 27)
+* Makefile.am file: GNU Tools. (line 22)
+* makeinfo: GNU Tools. (line 41)
+* master branch: Repo State. (line 27)
+* meld utility: Starting A New Branch.
+ (line 29)
+* merge conflicts: Merge Conflicts. (line 6)
+* old branches, removing: Repo Maintenance. (line 9)
+* origin/ branches: Repo Copies. (line 68)
+* ownership of directories: General practices. (line 17)
+* pager.status configuration setting: Configuring git. (line 24)
+* patch, single, generation of: Submitting Changes. (line 14)
+* patches, multiple, generation of: Submitting Changes. (line 24)
+* pcc compiler: Compilers. (line 40)
+* pcc compiler, Git mirror: Compilers. (line 50)
+* Portable C compiler: Compilers. (line 40)
+* Pro Git book: Resources. (line 6)
+* propagating fixes to other branches: General practices. (line 10)
+* purely local branches: Local State. (line 6)
+* push.default configuration setting: Configuring git. (line 24)
+* rebasing: Rebasing. (line 6)
+* removing branches: Removing Branches. (line 6)
+* removing cruft: Repo Maintenance. (line 27)
+* removing old branches: Repo Maintenance. (line 9)
+* renaming branches: Repo Maintenance. (line 44)
+* Repository, gawk, URL for: Cloning. (line 13)
+* Repository, gawk, URL for <1>: ssh clone. (line 10)
+* review, changes you made: Submitting Changes. (line 12)
+* Savannah, creating an account: Initial setup. (line 10)
+* Savannah, using Git guide: Resources. (line 10)
+* settings, configuration: Configuring git. (line 6)
+* software tools: Tools. (line 6)
+* ssh key: Initial setup. (line 10)
+* stable branches: Repo State. (line 15)
+* tcc compiler: Compilers. (line 22)
+* Texinfo: Conventions. (line 6)
+* Texinfo <1>: GNU Tools. (line 41)
+* Tiny C compiler: Compilers. (line 22)
+* tracking branches: Local Branches. (line 11)
+* URL, for cloning repositories: Cloning. (line 10)
+* URL, for gawk repository: Cloning. (line 13)
+* URL, for gawk repository <1>: ssh clone. (line 10)
+* user.email configuration setting: Configuring git. (line 16)
+* user.name configuration setting: Configuring git. (line 16)
+
+
+
+Tag Table:
+Node: Top1102
+Node: Preface5173
+Node: This Manual6069
+Node: Conventions7558
+Node: Acknowledgments9027
+Node: Reviewers9464
+Node: Contributing9785
+Ref: Contributing-Footnote-113140
+Node: Using Git13172
+Node: Push Pull13928
+Node: Repo Copies15343
+Ref: savannah-repo16326
+Ref: your-repo17359
+Ref: Repo Copies-Footnote-119053
+Node: Local Branches19110
+Ref: your-repo-220888
+Ref: Local Branches-Footnote-121969
+Node: Branches are state22027
+Node: Repo State22750
+Node: Local State24870
+Node: Remotes25534
+Node: Configuring git26849
+Ref: Configuring git-Footnote-129202
+Node: Development without commit access29371
+Node: Cloning30373
+Node: Switching Branches32232
+Node: Starting A New Branch32885
+Ref: Starting A New Branch-Footnote-134773
+Ref: Starting A New Branch-Footnote-234831
+Node: Undoing a change34907
+Node: Updating35508
+Node: Rebasing36010
+Node: Merge Conflicts36622
+Node: Submitting Changes38122
+Ref: Submitting Changes-Footnote-140266
+Ref: Submitting Changes-Footnote-240303
+Ref: Submitting Changes-Footnote-340339
+Node: Removing Branches40385
+Node: Points to remember40921
+Node: Development with commit access42598
+Node: Initial setup43243
+Node: ssh clone44031
+Node: Developing patches44628
+Node: Developing new features45964
+Node: Developing fixes47868
+Node: General practices48955
+Node: Repo Maintenance53685
+Ref: Repo Maintenance-Footnote-156454
+Node: Development Stuff56587
+Node: Coding style57150
+Ref: Coding style-Footnote-157808
+Node: Doing paperwork57898
+Node: Tools58693
+Node: GNU Tools59275
+Node: Compilers61436
+Ref: Compilers-Footnote-163930
+Node: Debugging63968
+Node: Cheat Sheet64674
+Node: Resources68355
+Node: TODO68798
+Node: Index69018
+
+End Tag Table
diff --git a/doc/gawkworkflow.texi b/doc/gawkworkflow.texi
new file mode 100644
index 00000000..f9ec2088
--- /dev/null
+++ b/doc/gawkworkflow.texi
@@ -0,0 +1,2158 @@
+\input texinfo @c -*-texinfo-*-
+@c vim: filetype=texinfo expandtab tabstop=4 shiftwidth=4
+@c %**start of header (This is for running Texinfo on a region.)
+@setfilename gawkworkflow.info
+@settitle GNU Awk Development Workflow
+@c %**end of header (This is for running Texinfo on a region.)
+
+@dircategory Text creation and manipulation
+@direntry
+* Gawk Work Flow: (gawkworkflow). Participating in @command{gawk} development.
+@end direntry
+@dircategory Individual utilities
+@direntry
+* Gawk Work Flow: (gawkworkflow)Overview. Participating in @command{gawk} development.
+@end direntry
+
+@c With early 2014 texinfo.tex, restore PDF links and colors
+@tex
+\gdef\linkcolor{0.5 0.09 0.12} % Dark Red
+\gdef\urlcolor{0.5 0.09 0.12} % Also
+\global\urefurlonlylinktrue
+@end tex
+
+@set xref-automatic-section-title
+
+@c The following information should be updated here only!
+@c This sets the edition of the document, the version of gawk it
+@c applies to and all the info about who's publishing this edition
+
+@c These apply across the board.
+@set UPDATE-MONTH April, 2017
+
+@set TITLE Participating in @command{gawk} Development
+@set EDITION 0.7
+
+@iftex
+@set DOCUMENT booklet
+@set CHAPTER chapter
+@set APPENDIX appendix
+@set SECTION section
+@set SUBSECTION subsection
+@end iftex
+@ifinfo
+@set DOCUMENT Info file
+@set CHAPTER major node
+@set APPENDIX major node
+@set SECTION minor node
+@set SUBSECTION node
+@end ifinfo
+@ifhtml
+@set DOCUMENT Web page
+@set CHAPTER chapter
+@set APPENDIX appendix
+@set SECTION section
+@set SUBSECTION subsection
+@end ifhtml
+@ifdocbook
+@set DOCUMENT booklet
+@set CHAPTER chapter
+@set APPENDIX appendix
+@set SECTION section
+@set SUBSECTION subsection
+@end ifdocbook
+@ifxml
+@set DOCUMENT booklet
+@set CHAPTER chapter
+@set APPENDIX appendix
+@set SECTION section
+@set SUBSECTION subsection
+@end ifxml
+@ifplaintext
+@set DOCUMENT booklet
+@set CHAPTER chapter
+@set APPENDIX appendix
+@set SECTION section
+@set SUBSECTION subsection
+@end ifplaintext
+
+
+@ifnottex
+@ifnotdocbook
+@macro ii{text}
+@i{\text\}
+@end macro
+@end ifnotdocbook
+@end ifnottex
+
+@ifdocbook
+@macro ii{text}
+@inlineraw{docbook,<lineannotation>\text\</lineannotation>}
+@end macro
+@end ifdocbook
+
+@c For HTML, spell out email addresses, to avoid problems with
+@c address harvesters for spammers.
+@ifhtml
+@macro EMAIL{real,spelled}
+``\spelled\''
+@end macro
+@end ifhtml
+@ifnothtml
+@macro EMAIL{real,spelled}
+@email{\real\}
+@end macro
+@end ifnothtml
+
+
+@c merge the function and variable indexes into the concept index
+@ifinfo
+@synindex fn cp
+@synindex vr cp
+@end ifinfo
+@iftex
+@syncodeindex fn cp
+@syncodeindex vr cp
+@end iftex
+@ifxml
+@syncodeindex fn cp
+@syncodeindex vr cp
+@end ifxml
+@ifdocbook
+@synindex fn cp
+@synindex vr cp
+@end ifdocbook
+
+@c If "finalout" is commented out, the printed output will show
+@c black boxes that mark lines that are too long. Thus, it is
+@c unwise to comment it out when running a master in case there are
+@c overfulls which are deemed okay.
+
+@iftex
+@finalout
+@end iftex
+
+@copying
+@docbook
+<para>Published by:</para>
+
+<literallayout class="normal">Free Software Foundation
+51 Franklin Street, Fifth Floor
+Boston, MA 02110-1301 USA
+Phone: +1-617-542-5942
+Fax: +1-617-542-2652
+Email: <email>gnu@@gnu.org</email>
+URL: <ulink url="http://www.gnu.org">http://www.gnu.org/</ulink></literallayout>
+
+<literallayout class="normal">Copyright &copy; 2017
+Free Software Foundation, Inc.
+All Rights Reserved.</literallayout>
+@end docbook
+
+@ifnotdocbook
+Copyright @copyright{} 2017
+Free Software Foundation, Inc.
+@end ifnotdocbook
+@sp 2
+
+This is Edition @value{EDITION} of @cite{@value{TITLE}}.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being ``GNU General Public License'', with the
+Front-Cover Texts being ``A GNU Manual'', and with the Back-Cover Texts
+as in (a) below.
+A copy of the license is included in the section entitled
+``GNU Free Documentation License''.
+
+@enumerate a
+@item
+The FSF's Back-Cover Text is: ``You have the freedom to
+copy and modify this GNU manual.''
+@end enumerate
+@end copying
+
+@c Comment out the "smallbook" for technical review. Saves
+@c considerable paper. Remember to turn it back on *before*
+@c starting the page-breaking work.
+
+@c 4/2002: Karl Berry recommends commenting out this and the
+@c `@setchapternewpage odd', and letting users use `texi2dvi -t'
+@c if they want to waste paper.
+@c @smallbook
+
+
+@c Uncomment this for the release. Leaving it off saves paper
+@c during editing and review.
+@c @setchapternewpage odd
+
+@c @shorttitlepage @value{TITLE}
+@titlepage
+@title @value{TITLE}
+@subtitle Edition @value{EDITION}
+@subtitle @value{UPDATE-MONTH}
+@author Arnold D. Robbins
+
+@ifnotdocbook
+@c Include the Distribution inside the titlepage environment so
+@c that headings are turned off. Headings on and off do not work.
+
+@page
+@vskip 0pt plus 1filll
+Published by:
+@sp 1
+
+Free Software Foundation @*
+51 Franklin Street, Fifth Floor @*
+Boston, MA 02110-1301 USA @*
+Phone: +1-617-542-5942 @*
+Fax: +1-617-542-2652 @*
+Email: @email{gnu@@gnu.org} @*
+URL: @uref{http://www.gnu.org/} @*
+
+@c ISBN x-xxxxxx-xx-x @*
+@sp 2
+@insertcopying
+@end ifnotdocbook
+@end titlepage
+
+@iftex
+@headings off
+@evenheading @thispage@ @ @ @strong{@value{TITLE}} @| @|
+@oddheading @| @| @strong{@thischapter}@ @ @ @thispage
+@end iftex
+
+@ifnottex
+@ifnotxml
+@ifnotdocbook
+@node Top
+@top General Introduction
+@c Preface node should come right after the Top
+@c node, in `unnumbered' sections, then the first chapter.
+
+This file describes how to participate in software development for
+@uref{http://www.gnu.org/software/gawk, GNU Awk (@command{gawk})}.
+
+@insertcopying
+
+@end ifnotdocbook
+@end ifnotxml
+@end ifnottex
+
+@menu
+* Preface:: Some introductory remarks.
+* Contributing:: How to contribute to @command{gawk}
+ development.
+* Using Git:: Getting started with Git.
+* Configuring git:: Configuring Git.
+* Development without commit access:: How to work without commit access.
+* Development with commit access:: How to work with commit access.
+* General practices:: How things should usually be done.
+* Repo Maintenance:: Tips for keeping your repo clean.
+* Development Stuff:: Things you need to know to be a
+ @command{gawk} developer.
+* Cheat Sheet:: Git command summary.
+* Resources:: Some further resources.
+* TODO:: Stuff still to do.
+* Index:: The index.
+
+@detailmenu
+* This Manual:: How to use this manual.
+* Conventions:: Typographical Conventions.
+* Acknowledgments:: Acknowledgments.
+* Reviewers:: A note to reviewers.
+* Push Pull:: The push/pull software development model.
+* Repo Copies:: What it means to have a copy of a repo.
+* Local Branches:: How to best use local branches.
+* Branches are state:: Branches represent development state.
+* Repo State:: The different branch types in the repo.
+* Local State:: Managing local branches.
+* Remotes:: What a ``remote'' is.
+* Cloning:: Cloning the repo the first time.
+* Switching Branches:: Moving from one branch to another.
+* Starting A New Branch:: Starting a new branch for development.
+* Undoing a change:: Throwing away changes.
+* Updating:: Keeping in sync with the upstream repo.
+* Rebasing:: Rebasing A Local Branch.
+* Merge Conflicts:: Dealing With Merge Conflicts.
+* Submitting Changes:: How to submit your changes.
+* Removing Branches:: Getting rid of unneeded branches.
+* Points to remember:: Things you need to keep in mind.
+* Initial setup:: Getting started with commit access.
+* ssh clone:: Cloning using an @samp{ssh://} URL.
+* Developing patches:: Developing patches.
+* Developing new features:: Developing new features.
+* Developing fixes:: Developing fixes.
+* Coding style:: Where to read up on the coding style.
+* Doing paperwork:: Legal stuff in order to contribute.
+* Tools:: Tools to have on your system for
+ development.
+* GNU Tools:: The GNU Autotools.
+* Compilers:: A discussion of compilers that can be
+ used.
+* Debugging:: Compiling for debugging.
+@end detailmenu
+@end menu
+
+@c @summarycontents
+@contents
+
+@node Preface
+@unnumbered Preface
+@c I saw a comment somewhere that the preface should describe the book itself,
+@c and the introduction should describe what the book covers.
+
+This @value{DOCUMENT} describes how to participate in development
+of GNU Awk (@command{gawk}). GNU Awk is a Free Software project
+belonging to the Free Software Foundation's GNU project.
+
+@cindex Git Project
+The @value{DOCUMENT} focuses on participation in the project (that is,
+how to work most effectively if you wish to contribute to it) and
+also describes how to make use of the @uref{http://git-scm.org, Git}
+distributed source code management system for @command{gawk} development.
+
+You should be comfortable working with traditional UNIX-style
+tools and with the C language and standard library facilities.
+
+@menu
+* This Manual:: How to use this manual.
+* Conventions:: Typographical Conventions.
+* Acknowledgments:: Acknowledgments.
+* Reviewers:: A note to reviewers.
+@end menu
+
+
+@node This Manual
+@unnumberedsec Using This Book
+
+This @value{DOCUMENT} has the following chapters and appendices:
+
+@itemize @bullet
+
+@item
+@ref{Contributing} describes how to start contributing to
+the @command{gawk} project.
+
+@item
+@ref{Using Git} introduces the Git distributed source code
+management system.
+
+@item
+@ref{Configuring git} describes some initial set-up you need to do
+before using Git seriously.
+
+@item
+@ref{Development without commit access} gets into the meat of the
+development workflow, describing how to work if you don't have
+commit access to the Savannah repository.
+
+@item
+@ref{Development with commit access} continues the discussion,
+covering what's different when you can commit directly to the
+Savannah repository.
+
+@item
+@ref{General practices} describes general development
+practices used by the @command{gawk} development team.
+
+@item
+@ref{Repo Maintenance} presents several different things
+you need to know about to keep your repo in good shape.
+
+@item
+@ref{Development Stuff} describes some important points you
+should be familiar with in order to participate in @command{gawk}
+development and presents some tools that may make your work easier.
+
+@item
+@ref{Cheat Sheet} provides a short ``cheat sheet'' summarizing
+all the Git commands referenced in this @value{DOCUMENT}.
+
+@item
+@ref{Resources} provides a few pointers to Internet
+resources for learning more about Git.
+
+@end itemize
+
+@node Conventions
+@unnumberedsec Typographical Conventions
+
+@cindex Texinfo
+This @value{DOCUMENT} is written in @uref{http://www.gnu.org/software/texinfo/, Texinfo},
+the GNU documentation formatting language.
+A single Texinfo source file is used to produce both the printed and online
+versions of the documentation.
+@ifnotinfo
+Because of this, the typographical conventions
+are slightly different than in other books you may have read.
+@end ifnotinfo
+@ifinfo
+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
+shell primary and secondary prompts, @samp{$} and @samp{>}.
+Input that you type is shown @kbd{like this}.
+Output from the command is preceded by the glyph ``@print{}''.
+This typically represents the command's standard output.
+Error messages and other output on the command's standard error are preceded
+by the glyph ``@error{}''. For example:
+
+@example
+$ @kbd{echo hi on stdout}
+@print{} hi on stdout
+$ @kbd{echo hello on stderr 1>&2}
+@error{} hello on stderr
+@end example
+
+@ifnotinfo
+In the text, almost anything related to programming, such as command
+names, variable and function names, and string, numeric and regexp
+constants appear in @code{this font}. Code fragments appear in the same
+font and quoted, @samp{like this}. Things that are replaced by the
+user or programmer appear in @var{this font}. Options look like this:
+@option{-f}. File names are indicated like this: @file{/path/to/ourfile}.
+Some things are emphasized @emph{like this}, and if a point needs to be
+made strongly, it is done @strong{like this}. The first occurrence of
+a new term is usually its @dfn{definition} and appears in the same font
+as the previous occurrence of ``definition'' in this sentence.
+@end ifnotinfo
+
+Characters that you type at the keyboard look @kbd{like this}. In particular,
+there are special characters called ``control characters.'' These are
+characters that you type by holding down both the @kbd{CONTROL} key and
+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.
+
+@quotation NOTE
+Notes of interest look like this.
+@end quotation
+
+@quotation CAUTION
+Cautionary or warning notes look like this.
+@end quotation
+
+@node Acknowledgments
+@unnumberedsec Acknowledgments
+
+@cindex Kahrs, J@"urgen
+Thanks to J@"urgen Kahrs for his initial efforts to write a document like this.
+Although his prose has not survived, his material was helpful in preparing
+this @value{DOCUMENT}.
+
+@cindex Bernat, Yehezkel
+Thanks to Yehezkel Bernat for reviewing this document and
+in general for his good intentions.
+
+@strong{FIXME:} YOUR NAME HERE...
+
+@node Reviewers
+@unnumberedsec Notes to Reviewers
+
+Please let me know if anything is missing, or unclear.
+Real errors with respect Git commands and usage are
+very important as well.
+
+Spelling errors and typo fixes welcome, but not as important.
+
+@node Contributing
+@chapter How to Start Contributing
+
+@command{gawk} development is distributed. It's done using electronic
+mail (email) and via branches in the Git repo@footnote{Short for
+``repository''.} on @uref{http://savannah.gnu.org, Savannah}, the GNU
+project's source code management site.
+
+In this @value{CHAPTER} we use some Git terminology. If you're not at
+all familiar with Git, then skim this @value{CHAPTER} and come back
+after reading the rest of the @value{DOCUMENT}.
+
+@command{gawk} is similar to many other Free Software projects. To begin
+contributing, simply start! Take a look at the @file{TODO} file in the
+distribution, see if there is something of interest to you, and ask on
+the @email{bug-gawk@@gnu.org} mailing list if anyone else is working
+on it. If not, then go for it! (@xref{Development Stuff} for a discussion of some
+of the technical things you'll need to do. Here we describe the process
+in general.)
+
+Your contribution can be almost anything that is relevant for
+@command{gawk}, such as code fixes, documentation fixes, and/or new
+features.
+
+@quotation NOTE
+If possible, new features should be done using @command{gawk}'s extension
+mechanism. If you want to add a user-visible language change to the
+@command{gawk} core, you're going to have to convince the maintainer
+and other developers that it's really worthwile to do so.
+
+Changes that improve performance or portability, or that fix bugs,
+or that enable more things in extensions,
+will require less convincing, of course.
+@end quotation
+
+As you complete a task, submit patches for review to the
+@email{bug-gawk@@gnu.org} mailing list, where you'll be given feedback
+about your work. Once your changes are acceptable, the maintainer will
+commit them to the Git repository.
+
+Over time, as the maintainer and development team gain confidence in your
+ability to contribute, you may be asked to join the private @command{gawk}
+developers' mailing list, and/or be granted commit access to the Git
+repository on Savannah. This has happened to more than one person who
+just ``came out of the woodwork.''
+
+Until that happens, or if you don't want to join the list, you should
+continue to work with private branches and submission of patches to the
+mailing list.
+
+Once you have commit access, if you want to make a major change or add a
+major feature, where the patch(es) would be very large, it has become the
+practice to create a separate branch, based off of @code{master}, to host
+the feature. This way the maintainer can review it, and you can continue
+to improve it, until it's ready for integration into @code{master}.
+
+@cindex GitHub
+@quotation NOTE
+Because of the GNU project's requirements for signed paperwork for
+contributions, the @command{gawk} project will @strong{not} work
+with pull requests from @uref{http://github.com, GitHub} or any other
+Git-based software hosting service. You must submit patches to the
+mailing list, and be willing to sign paperwork for large patches.
+@end quotation
+
+The @email{bug-gawk@@gnu.org} mailing list is not private. Anyone may
+send mail to it, and anyone may subscribe to it. To subscribe,
+go to the list's @uref{https://lists.gnu.org/mailman/listinfo/bug-gawk,
+web page} and follow the instructions there. If you plan to be involved
+long-term with @command{gawk} development, then you probably should
+subscribe to the list.
+
+@node Using Git
+@chapter Using Git
+
+This chapter provides an introduction to using Git. Our point is
+@emph{not} to rave about how wonderful Git is, nor to go into painful
+detail about how it works. Rather we want to give you enough background
+to understand how to use Git effectively for bug fix and feature
+development and to interact (``play nicely'') with the development team.
+
+@menu
+* Push Pull:: The push/pull software development model.
+* Repo Copies:: What it means to have a copy of a repo.
+* Local Branches:: How to best use local branches.
+* Branches are state:: Branches represent development state.
+@end menu
+
+@node Push Pull
+@section The ``Push/Pull'' Model of Software Development
+
+Git is a powerful, distributed source code management system. However,
+the way it's used for @command{gawk} development purposely does not take
+advantage of all its features.
+
+Instead, the model is rather simple, and in many ways much like more
+traditional distributed systems such as the @uref{http://www.nongnu.org/cvs,
+Concurrent Versions System} (CVS) or
+@uref{http://subversion.apache.org, Subversion} (SVN).
+
+The central idea can be termed ``push/pull.'' You @emph{pull} updates down from
+the central repository to your local copy, and if you have commit rights,
+you @emph{push} your changes or updates up to the central repository.
+
+Where Git does stand out is in its management of multiple branches of
+development. Git makes it very easy to set up a separate branch for
+use in fixing a bug or developing a feature. You can then easily keep
+that branch up to date with respect to the main development branch(es),
+and eventually merge the changes from your branch into the main branch.
+
+Almost always Git does these merges for you without problem. When there
+is a problem (a @dfn{merge conflict}), usually it is very easy for you
+to @dfn{resolve} them and then complete the merge. We talk about this
+in more detail later (@pxref{Merge Conflicts}).
+
+@node Repo Copies
+@section How Git Stores Branches and Their Copies
+
+So how does Git work?@footnote{The following description is greatly
+simplified.}
+
+A repository consists of a collection of @dfn{branches}. Each branch
+represents the history of a collection of files and directories (a file
+@dfn{tree}). Each combined set of changes to this collection (files and
+directories added or deleted, and/or file contents changed) is termed
+a @dfn{commit}.
+
+When you first create a local copy of a remote repository (``clone
+the repo''), Git copies all of the original repository's branches to
+your local system. The original remote repository is referred to as
+being @dfn{upstream}, and your local repo is @dfn{downstream} from it.
+Git distinguishes branches from the upstream repo by prefixing their
+names with @samp{origin/}. Let's draw some pictures. @ref{savannah-repo}
+represents the state of the repo on Savannah:
+
+@page
+@float Figure,savannah-repo
+@caption{The Savannah @command{gawk} Repository}
+@smallexample
++======================+
+| Branches |
++======================+
+| master |
++----------------------+
+| gawk-4.1-stable |
++----------------------+
+| gawk-4.0-stable |
++----------------------+
+| feature/fix-comments |
++----------------------+
+| ... |
++----------------------+
+@end smallexample
+@end float
+
+@cindex @code{git branch}
+After you clone the repo, on your local system you will have a single
+branch named @code{master} that's visible when you use @samp{git branch}
+to see your branches.
+
+@cindex @code{git clone}
+@example
+$ @kbd{git clone http://git.savannah.gnu.org/r/gawk.git} @ii{Clone the repo}
+$ @kbd{cd gawk} @ii{Change to local copy}
+$ @kbd{git branch} @ii{See branch information}
+@print{} * master
+@end example
+
+@noindent
+The current branch is always indicated with a leading asterisk (@samp{*}).
+
+Pictorially, the local repo looks like @ref{your-repo} (you can ignore
+the @samp{T} column for the moment):
+
+@float Figure,your-repo
+@caption{Your Local @command{gawk} Repository}
+@smallexample
++===+======================++=============================+
+| T | Local Branches || Remote Branches |
++===+======================++=============================+
+| X | master || origin/master |
++---+----------------------++-----------------------------+
+| | || origin/gawk-4.1-stable |
++---+----------------------++-----------------------------+
+| | || origin/gawk-4.0-stable |
++---+----------------------++-----------------------------+
+| | || origin/feature/fix-comments |
++---+----------------------++-----------------------------+
+| | || ... |
++---+----------------------++-----------------------------+
+@end smallexample
+@end float
+
+@noindent
+@cindex @code{origin/} branches
+@cindex branches, @code{origin/}
+Note that what is simply @code{gawk-4.1-stable} in the upstream repo
+is now referred to as @code{origin/gawk-4.1-stable}. The @samp{origin/}
+branches are a snapshot of the state of the upstream repo. This is
+how Git allows you to see what changes you've made with respect to the
+upstream repo, without having to actually communicate with the upstream
+repo over the Internet. (When files are identical, Git is smart enough
+to not have two separate physical copies on your local disk.)
+
+If you're working on a simple bug fix or change, you can do so directly
+in your local @code{master} branch. You can then commit your changes,
+and if you have access rights, push them upstream to the Savannah repo.
+(However, there is a process to follow. Please read the rest of
+this @value{DOCUMENT}.)
+
+@node Local Branches
+@section Local Branches
+
+@cindex local branches
+@cindex branches, local
+Let's talk about local branches in more detail. (The terminology used
+here is my own, not official Git jargon.) There are two kinds of local
+branches:
+
+@table @dfn
+@item Tracking Branches
+@cindex tracking branches
+@cindex branches, tracking
+@cindex @code{git checkout}
+Tracking branches track branches from the upstream repository. You first
+create a tracking branch simply by checking out a branch from the
+upstream. You use the branch name without the leading @samp{origin/}
+prefix. For example, @samp{git checkout gawk-4.1-stable}.
+
+@cindex @code{git push}
+You can then work on this branch, making commitments to it as you wish.
+Once things are ready to move upstream, you simply use @samp{git push},
+and your changes will be pushed up to the main repo.@footnote{Assuming
+you have permission to do so, of course.}
+
+You should @strong{never} checkout a branch using the @samp{origin/}
+prefix. Things will get very confused. Always work on local tracking
+branches.
+
+@item Purely Local Branches
+A @dfn{purely local branch} exists only on your system. You may be developing
+some large new feature, or fixing a very difficult bug, or have a change
+for which paperwork has not yet been completed.
+
+In such a case, you would keep your changes on a local branch, and
+periodically synchronize it with @code{master} (or whichever upstream
+branch you started from).
+@end table
+
+This may seem somewhat abstract so far. We demonstrate with commands
+and branches in @ref{Development without commit access},
+later in this @value{DOCUMENT}.
+
+Let's say you have checked out a copy of @code{gawk-4.1-stable} and
+have created a purely local branch named @code{better-random}. Then
+our picture now looks like @ref{your-repo-2}, where the @samp{T} column
+indicates a tracking branch.
+
+@float Figure,your-repo-2
+@caption{Your Local @command{gawk} Repository With a Purely Local Branch}
+@smallexample
++===+======================++=============================+
+| T | Local Branches || Remote Branches |
++===+======================++=============================+
+| X | master || origin/master |
++---+----------------------++-----------------------------+
+| X | gawk-4.1-stable || origin/gawk-4.1-stable |
++---+----------------------++-----------------------------+
+| | || origin/gawk-4.0-stable |
++---+----------------------++-----------------------------+
+| | || origin/feature/fix-comments |
++---+----------------------++-----------------------------+
+| | || ... |
++---+----------------------++-----------------------------+
+| | better-random || |
++---+----------------------++-----------------------------+
+@end smallexample
+@end float
+
+@node Branches are state
+@section Branches Represent Development State
+
+Branches represent development state. At any given time, when you
+checkout a particular branch (or create a new one), you have a copy
+of the @command{gawk} source tree that you should be able to build
+and test.
+
+The following @value{SECTION}s describe the different branches
+in the @command{gawk} repository and what they are for, as well
+as how to use your own branches.
+
+@menu
+* Repo State:: The different branch types in the repo.
+* Local State:: Managing local branches.
+* Remotes:: What a ``remote'' is.
+@end menu
+
+@node Repo State
+@subsection Branches in the Savannah Repository
+
+There are several kinds of branches in the Savannah repository.
+
+@table @dfn
+@cindex branches, dead
+@cindex dead branches
+@item Dead Branches
+Branches with the prefix @samp{dead-branches/} (such as
+@code{dead-branches/const}) hold code that was never merged into the
+main code base. For example, a feature which was started, but later
+deemed to be unwise to add. These branches keep the code available,
+but they are not updated.
+
+@cindex branches, stable
+@cindex stable branches
+@item Stable Branches
+These branches are used for bug fixes to released versions
+of @command{gawk}. Sometimes new development (i.e., user-visible
+changes) also occurs on these branches, although in a perfect world
+they would be used only for bug fixes.
+
+These branches have names like @code{gawk-4.1-stable},
+@code{gawk-4.0-stable}, and so on. Once a release has been made from
+@code{master}, the previous stable branch is not updated. For example,
+once @command{gawk} 4.1.0 was released, no more work was done on
+@code{gawk-4.0-stable}.
+
+@cindex branch, main
+@cindex main branch
+@cindex branch, @code{master}
+@cindex @code{master} branch
+@item The Main Branch
+This is the @code{master} branch. Here is where most new feature
+development takes place, and releases of new major versions are based
+off of this branch.
+
+Feature branches are typically based off this branch as well, and when
+the feature is deemed complete, merged back into it.
+
+@cindex branches, feature
+@cindex feature branches
+@item Feature Branches
+Often, a proposed new feature or code improvement is quite involved.
+It may take some time to perfect, or the @command{gawk} development team
+may not be convinced that the feature should be kept.
+
+For this purpose, the team uses branches prefixed with @samp{feature/}.
+This prefix is used even for code that simply improves the internals
+and does not make a user-visible change.
+
+Having large changes on separate branches makes it easier for members
+of the team to review the code, and also makes it easier to keep the
+changes up-to-date with respect to @code{master}, since Git excels at
+merging commits from one branch to another.
+@end table
+
+@node Local State
+@subsection Branches in Your Local Repository
+
+@cindex branches, purely local
+@cindex purely local branches
+Purely local branches are where you do your own development.
+You may use purely local branches because you don't have commit rights
+to the Savannah repo. You may also use them if you are doing some work
+that isn't ready for sharing with the rest of the team, or cannot be
+committed for some other reason.
+
+For example, for around a nine-month period, the maintainer kept a
+purely local branch for some contributed changes for which paperwork had
+not yet been completed.
+
+@node Remotes
+@subsection A Closer Look at Branch Naming
+
+@cindex @command{git branch} command, @option{-a} option
+Earlier, we said that Git maintains copies of the branches
+in the upstream repo, as well as manages your local branches.
+You can see all these branches with @samp{git branch -a}:
+
+@example
+$ @kbd{git branch -a}
+@print{} gawk-4.1-stable
+@print{} * master
+@print{} remotes/origin/HEAD -> origin/master
+@print{} remotes/origin/dead-branches/async-events
+@print{} @dots{}
+@print{} remotes/origin/feature/api-mpfr
+@print{} remotes/origin/feature/array-iface
+@print{} remotes/origin/feature/fix-comments
+@print{} @dots{}
+@end example
+
+You'll note that what we've referred to as @samp{origin/} branches
+appear in the output with an additional prefix: @samp{remotes/}.
+Up to this point, we've treated Git as if it allowed only a singled
+upstream repository. But in fact, you can configure it to use more
+than one. All the known upstream repositories are grouped under
+the @samp{remotes/} prefix, with @code{remotes/origin} being the one
+from which you initially cloned your local repository.
+
+The ability to work with multiple upstream repositories is an
+advanced one; @command{gawk} development does not make use of it.
+The intent of this @value{SUBSECTION} is to explain the output
+from @samp{git branch -a}, nothing more.
+
+@node Configuring git
+@chapter Configuring Global Settings For Git
+
+@cindex configuration settings
+@cindex settings, configuration
+@cindex global configuration settings
+@cindex configuration settings, global
+Before starting to use Git, you should configure it with some important
+settings that won't change as you use Git. You may configure options
+both globally, and on a per-repository basis. Here, we discuss only
+global configuration settings.
+
+@cindex @code{git config}
+You can configure Git using either @samp{git config}, or by editing
+the relevant files with your favorite text editor.@footnote{You are
+required to use either Vim or Emacs, other text editors are not
+allowed. Of course, reasonable developers wouldn't want to use
+any other editor anyway.}
+
+@cindex email address
+The first things to set are your email address and your real name:
+
+@cindex @code{user.name} configuration setting
+@cindex @code{user.email} configuration setting
+@cindex configuration setting, @code{user.name}
+@cindex configuration setting, @code{user.email}
+@example
+$ @kbd{git config --global user.name "J.P. Developer"} @ii{Set full name}
+$ @kbd{git config --global user.email jpdev@@example.com} @ii{Set email address}
+@end example
+
+Setting these two items are an absolute requirement.
+@strong{Note}: No aliases are allowed. If you can't supply your
+real name, you cannot contribute to the project. Other options that
+the @command{gawk} maintainer recommends that you use are:
+
+@cindex @code{push.default} configuration setting
+@cindex @code{pager.status} configuration setting
+@cindex configuration setting, @code{push.default}
+@cindex configuration setting, @code{pager.status}
+@example
+$ @kbd{git config --global push.default=simple} @ii{Only push current branch}
+$ @kbd{git config --global pager.status=true} @ii{Use pager for output of} git status
+@end example
+
+@cindex @file{.gitconfig} file
+The global settings are stored in the @file{.gitconfig} file in your
+home directory. The file looks like this:
+
+@example
+[user]
+ name = J.P. Developer
+ email = jpdev@@example.com
+[push]
+ default = simple
+[pager]
+ status = true
+@end example
+
+The @code{push.default=simple} setting ensures that older
+versions of Git only push the current branch up to the Savannah
+repo. This is the safest way to operate, and is the default
+in current Git versions.
+
+There may be other settings in your configuration file as well.
+Use @samp{git config} to see your settings:
+
+@example
+$ @kbd{git config --list}
+@print{} user.name=J.P. Developer
+@print{} user.email=jpdev@@example.com
+@print{} push.default=simple
+@end example
+
+Here are the @command{gawk} maintainer's settings:
+
+@example
+$ @kbd{git config --global --list}
+@print{} user.name=Arnold D. Robbins
+@print{} user.email=arnold@@@dots{}
+@print{} credential.helper=cache --timeout=3600
+@print{} push.default=simple
+@print{} color.ui=false
+@print{} core.autocrlf=input
+@print{} pager.status=true
+@print{} log.decorate=auto
+@end example
+
+Additional, per-project (``local'') settings are stored in
+each repo's @file{.git/config} file.
+
+@node Development without commit access
+@chapter Development Without Commit Access
+
+In this chapter we present step-by-step recipes for checking out
+and working with a local
+copy of the Savannah Git repo for @command{gawk}.
+The presentation is for when you do not have commit access
+to the Git repo, and so you cannot push your changes directly.
+
+@menu
+* Cloning:: Cloning the repo the first time.
+* Switching Branches:: Moving from one branch to another.
+* Starting A New Branch:: Starting a new branch for development.
+* Undoing a change:: Throwing away changes.
+* Updating:: Keeping in sync with the upstream repo.
+* Submitting Changes:: How to submit your changes.
+* Removing Branches:: Getting rid of unneeded branches.
+* Points to remember:: Things you need to keep in mind.
+@end menu
+
+@node Cloning
+@section Cloning The Repo
+
+@cindex @code{git clone}
+Clone the Savannah repo using @samp{git clone}. You may do so using
+either the native Git protocol, or using HTTP if you must go through a
+gateway or firewall that won't pass the Git protocol.
+
+@cindex URL, for cloning repositories
+To choose which method, you supply a @dfn{URL} for the repo when you
+clone it, as follows.
+
+@cindex URL, for @command{gawk} repository
+@cindex Repository, @command{gawk}, URL for
+@itemize @bullet
+@item
+Clone via the Git native protocol:
+
+@example
+$ @kbd{git clone git://git.savannah.gnu.org/gawk.git} @ii{Clone the repo}
+@print{} ...
+$ @kbd{cd gawk} @ii{Start working}
+@end example
+
+This will be faster, but not all firewalls pass the Git protocol
+on through.
+
+@item
+Clone via the HTTP protocol:
+
+@example
+$ @kbd{git clone http://git.savannah.gnu.org/r/gawk.git} @ii{Clone the repo}
+@print{} ...
+$ @kbd{cd gawk} @ii{Start working}
+@end example
+@end itemize
+
+@emph{You only need to clone the repo once.} From then on, you update its
+contents using other Git commands. For example, after coming back from
+your vacation in the Bahamas:
+
+@cindex @code{git pull}
+@example
+$ @kbd{cd gawk} @ii{Move to the repo}
+$ @kbd{make distclean} @ii{A good idea before updating}
+@print{} ...
+$ @kbd{git pull} @ii{Update it}
+@end example
+
+To build, you should generally follow this recipe:
+
+@example
+$ @kbd{./bootstrap.sh && ./configure && make -j && make check}
+@end example
+
+@cindex @file{bootstrap.sh} script
+@quotation NOTE
+Unless you have installed all the tools described in @ref{GNU Tools},
+you @emph{must} run @command{./bootstrap.sh} every time you clone a repo,
+do a @samp{git pull} or checkout a different branch. (In the latter case,
+do @samp{make distclean} first.) Otherwise things will get messy very
+quickly. The @command{bootstrap.sh} script ensures that all of the file
+time stamps are up to date so that it's not necessary to run the various
+configuration tools.
+@end quotation
+
+@node Switching Branches
+@section Switching Branches
+
+So far, we've been working in the default @code{master} branch.
+Let's check what's happening in the @code{gawk-4.1-stable} branch:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@example
+$ @kbd{make distclean} @ii{Clean up}
+$ @kbd{git checkout gawk-4.1-stable} @ii{Checkout a different branch}
+@print{} ...
+$ @kbd{git pull} @ii{Get up to date}
+@print{} ...
+$ @kbd{./bootstrap.sh && ./configure && make -j && make check} @ii{Start working}
+@end example
+
+@node Starting A New Branch
+@section Starting A New Branch
+
+Let's say you want to work on a new feature. For example,
+you might decide to add Python syntax support.@footnote{Just joking.
+Please don't attempt this for real.} You should create a
+new branch on which to work. First, switch back to @code{master}:
+
+@cindex @code{git checkout}
+@example
+$ @kbd{make distclean}
+$ @kbd{git checkout master}
+@end example
+
+Now, create a new branch. The easiest way to do that is
+with the @option{-b} option to @samp{git checkout}:
+
+@example
+$ @kbd{git checkout -b feature/python}
+@print{} ...
+@end example
+
+@cindex @file{ChangeLog} file
+@cindex committing changes
+You now do massive amounts of work in order to add Python syntax support.
+As you do each defined chunk of work, you update the @file{ChangeLog}
+file with your changes before @dfn{committing} them to the repo.
+
+@cindex @code{git status}
+Let's say you've added a new file @file{python.c} and updated several
+others. Use @samp{git status} to see what's changed:
+
+@example
+$ @kbd{git status}
+@print{} ...
+@end example
+
+@cindex @code{git diff}
+@cindex @code{git difftool}
+@cindex @command{meld} utility
+Before committing the current set of changes, you can use @samp{git diff}
+to view the changes. You may also use @samp{git difftool}@footnote{Don't
+run @samp{git difftool} in the background; it works interactively.} to run an
+external @command{diff} command, such as @command{meld} on GNU/Linux:
+
+@example
+$ @kbd{git diff} @ii{Regular built-in tool}
+$ @kbd{git difftool --tool=meld} @ii{GUI diff tool}
+@end example
+
+@cindex @code{git add}
+When you're happy with the changes, use @samp{git add} to tell
+Git which of the changed and/or new files you wish to have ready to
+be committed:
+
+@example
+$ @kbd{git add ...}
+@end example
+
+@cindex @code{git status}
+Use @samp{git status} to see that your changes are scheduled for committing:
+
+@example
+$ @kbd{git status}
+@print{}
+@end example
+
+Now you can commit your changes to your branch:
+
+@cindex @code{git commit}
+@example
+$ @kbd{git commit}
+@end example
+
+@noindent
+@cindex @code{git log}
+Running @samp{git commit} causes Git to invoke an editor
+(typically from the @env{$EDITOR} environment variable)
+in which you can compose a commit message. Please supply a
+short message summarizing the commit. This message will be
+visible via @samp{git log}.
+
+@node Undoing a change
+@section Undoing A Change
+
+Should you need to undo a change that you have not yet
+committed (so that you can start over), you can do so on
+per-file basis by simply checking out the file again:
+
+@cindex @code{git checkout}
+@example
+git checkout awkgram.y @ii{Undo changes to} awkgram.y@ii{. There is no output}
+@end example
+
+@cindex @code{git reset}
+To start over completely, use @samp{git reset --hard}.
+Note that this will @emph{throw away} all your changes, with no
+chance for recovery, so be sure you really want to do it.
+
+@node Updating
+@section Updating and Merging
+
+As you work on your branch, you will occasionally want to bring it
+up to date with respect to @code{master}.
+This @value{SECTION} discusses updating local branches
+and handling merge conflicts.
+
+@menu
+* Rebasing:: Rebasing A Local Branch.
+* Merge Conflicts:: Dealing With Merge Conflicts.
+@end menu
+
+@node Rebasing
+@subsection Rebasing A Local Branch
+
+@cindex rebasing
+For purely local branches, bringing your branch up to date is called
+@dfn{rebasing}, which causes the branch to look @emph{as if} you had
+started from the latest version of @code{master}. The steps are as
+follows:
+
+@cindex @code{git rebase}
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@example
+$ @kbd{git checkout master} @ii{Checkout} master
+$ @kbd{git pull} @ii{Update it}
+$ @kbd{git checkout feature/python} @ii{Move back to new, purely local branch}
+$ @kbd{git rebase master} @ii{``Start over'' from current} master
+@end example
+
+@node Merge Conflicts
+@subsection Dealing With Merge Conflicts
+
+@cindex conflicts, from merging
+@cindex merge conflicts
+
+Sometimes, when merging from @code{master} into your branch, or from
+a branch into @code{master}, there will be @dfn{merge conflicts}.
+These are one or more areas within a file where there are conflicting
+sets of changes, and Git could not do the merge for you.
+In this case, the conflicted area will be delimited by the traditional
+conflict markers, @samp{<<<}, @samp{===} and @samp{>>>}.
+
+Your mission is then to edit the file and @dfn{resolve} the conflict
+by fixing the order of additions (such as in a @file{ChangeLog} file),
+or fixing the code to take new changes into account.
+
+Once you have done so, you tell Git that everything is OK using
+@samp{git add} and @samp{git commit}:
+
+@example
+$ @kbd{git checkout feature/python} @ii{Move back to new, purely local branch}
+$ @kbd{git rebase master} @ii{``Start over'' from current} master
+@print{} ... Kaboom! Conflict. FIXME: Show real output here
+$ @kbd{gvim main.c} @ii{Edit the file and fix the problem}
+$ @kbd{git add main.c} @ii{Tell Git everything is OK now @dots{}}
+$ @kbd{git commit} @ii{@dots{} and it's settled}
+$ @kbd{git rebase --continue} @ii{Continue the rebase}
+@end example
+
+The @command{git rebase --continue} then continues the process of
+rebasing the current branch that we started in @ref{Rebasing}.
+It's not necessary if you are using @samp{git merge}
+(@pxref{Points to remember}).
+
+@node Submitting Changes
+@section Submitting Your Changes
+
+So now your feature is complete. You've added test cases for it to
+the test suite@footnote{You did do this, didn't you?}, you have
+@file{ChangeLog} entries that describe all the changes@footnote{You remembered this, right?},
+you have documented the new feature@footnote{You wouldn't neglect this, would you?},
+and everything works great. You're ready
+to submit the changes for review, and with any luck, inclusion into
+@command{gawk}.
+
+@cindex review, changes you made
+@cindex changes, submitting for review
+There are two ways to submit your changes for review.
+
+@table @emph
+@cindex generating a single patch
+@cindex patch, single, generation of
+@item Generate a single large patch
+To do this, simply compare your branch
+to the branch off which it is based:
+
+@cindex @code{git checkout}
+@cindex @code{git diff}
+@example
+$ @kbd{git checkout feature/python}
+$ @kbd{git diff master > /tmp/python.diff}
+@end example
+
+Mail the @file{python.diff} file to the appropriate mailing list
+along with a description of what you've changed and why.
+
+@cindex @code{git format-patch}
+@cindex generating multiple patches
+@cindex patches, multiple, generation of
+@item Generate a set of patches that in toto comprise your changes
+To do this, use @samp{git format-patch}:
+
+@cindex @code{git checkout}
+@example
+$ @kbd{git checkout feature/python}
+$ @kbd{git format-patch}
+@end example
+
+This creates a set of patch files, one per commit that isn't on the
+original branch. Mail these patches, either separately, or as a set of
+attachments, to the appropriate mailing list along with a description
+of what you've changed and why.
+
+@end table
+
+Either way you choose to submit your changes, the @command{gawk}
+maintainer and development team will review your changes and provide feedback.
+If you have signed paperwork with the FSF for @command{gawk} and the maintainer
+approves your changes, he will apply the patch(es) and commit the changes.
+
+Which list should you send mail to? If you are just starting to
+contribute, use @email{bug-gawk@@gnu.org}. After making enough
+contributions, you may be invited to join the private @command{gawk}
+developers' mailing list. If you do so, then submit your changes to
+that list.
+
+If you make any substantial changes, you will need to assign copyright
+in those changes to the Free Software Foundation before the maintainer
+can commit those changes. @xref{Doing paperwork}, for more information.
+
+@node Removing Branches
+@section Removing Branches
+
+@cindex removing branches
+@cindex branches, removing
+Once the maintainer has integrated your changes, you can get
+rid of your local branch:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@cindex @code{git branch}
+@example
+$ @kbd{git checkout master} @ii{Move to upstream branch}
+$ @kbd{git pull} @ii{Update}
+$ @kbd{gvim ChangeLog ...} @ii{Verify your changes are in}
+$ @kbd{git branch -d feature/python} @ii{Remove your local branch}
+@end example
+
+@node Points to remember
+@section Points to Remember
+
+There are some important points to remember:
+
+@itemize @bullet
+@item
+Always do a @samp{make distclean} before switching between branches.
+Things will get really confused if you don't.
+
+@item
+For upstream branches, @emph{always} work with tracking branches. @emph{Never}
+use @samp{git checkout origin/@var{whatever}}. Git will happily let
+you do something like that, but it's just plain asking for trouble.
+
+@item
+Make sure your tracking branches are up-to-date before doing anything
+with them, particularly using them as the basis for a rebase
+or merge. This typically means a three-step process:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@example
+$ @kbd{git checkout master} @ii{Get to local copy}
+$ @kbd{git pull} @ii{Bring it up to date}
+$ @kbd{git checkout feature/python} @ii{Go back to your branch}
+@end example
+
+@noindent
+You can then do the actual rebase:
+
+@cindex @code{git rebase}
+@example
+$ @kbd{git rebase master} @ii{Now rebase your feature off of master}
+@end example
+
+@item
+Git always treats the currently checked-out branch as the object of
+operations. For example, when comparing files with the regular
+@command{diff} command, the usage is @samp{diff @var{oldfile} @var{newfile}}.
+For @samp{git diff}, the current branch takes the place of @var{newfile}, thus:
+
+@cindex @code{git checkout}
+@cindex @code{git diff}
+@example
+$ @kbd{git checkout feature/python}
+$ @kbd{git diff master} @ii{Compare} master @ii{to current branch}
+@end example
+
+@noindent
+or if merging:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@cindex @code{git merge}
+@example
+$ @kbd{git checkout master} @ii{Checkout} master
+$ @kbd{git pull} @ii{Update tracking branch}
+$ @kbd{git merge feature/python} @ii{Merge changes into} master
+@end example
+
+@end itemize
+
+@node Development with commit access
+@chapter Development With Commit Access
+
+This @value{CHAPTER} describes how to do development when you @emph{do}
+have commit access to the @command{gawk} repo on Savannah.
+
+@menu
+* Initial setup:: Getting started with commit access.
+* ssh clone:: Cloning using an @samp{ssh://} URL.
+* Developing patches:: Developing patches.
+* Developing new features:: Developing new features.
+* Developing fixes:: Developing fixes.
+@end menu
+
+@node Initial setup
+@section Initial Setup
+
+Congratulations! After becoming a quality contributor to @command{gawk}
+development, you've been invited to join the private development list
+and to accept having commit access to the repo.
+
+@cindex Savannah, creating an account
+@cindex account, Savannah, creation of
+@cindex @code{ssh} key
+The first thing to do is to create an account on Savannah, choosing a
+unique user name. To do so, go to the @uref{http://savannah.gnu.org,
+Savannah home page} and click on the ``New User'' link. The setup
+will include uploading of your @command{ssh} key, as per the instructions
+on the Savannah web page.
+
+After you've done all this, send email to the maintainer with your
+Savannah user name, and he will add you to the list of users who have
+commit access to the repo.
+
+@node ssh clone
+@section Cloning The Repo With An @command{ssh} URL
+
+In order to be able to commit changes to the repo, you must
+clone it using an @samp{ssh://} URL.
+Cloning the repo with @command{ssh} is similar to cloning
+with the Git protocol or with HTTP, but the URL is different:
+
+@cindex @code{git clone}
+@cindex URL, for @command{gawk} repository
+@cindex Repository, @command{gawk}, URL for
+@example
+$ @kbd{git clone ssh://yourname@@git.sv.gnu.org/srv/git/gawk.git}
+@print{} ...
+@end example
+
+Here, you should replace @samp{yourname} in the command with the user
+name you chose for use on Savannah.
+
+@node Developing patches
+@section Developing Patches
+
+The first part of developing a patch is the same as for developers
+without commit access:
+
+@enumerate 1
+@item
+Develop the code and test it.
+
+@item
+@cindex @file{ChangeLog} file
+Update the @file{ChangeLog}.
+
+@item
+@cindex documentation files
+@cindex @file{gawktexi.in} documentation
+@cindex @file{gawk.1} manual page
+If necessary, update the documentation: @file{doc/gawktexi.in}
+and/or @file{doc/gawk.1}.
+
+@cindex @code{git diff}
+@item
+Use @samp{git diff > mychange.diff} to create a patch file.
+
+@item
+Send it to the mailing list for discussion.
+
+@item
+Iterate until the patch is ready to be committed.
+@end enumerate
+
+However, now that you have commit access, you can commit the fix and push
+it up to the repo yourself!
+Let's assume you've made a bug fix directly on @code{master}.
+Here's how to commit your changes:
+
+@cindex @code{git diff}
+@cindex @code{git add}
+@cindex @code{git commit}
+@cindex @code{git push}
+@example
+$ @kbd{git diff} @ii{Review the patch one more time}
+$ @kbd{git add @dots{}} @ii{Add any files for committing}
+$ @kbd{git commit} @ii{Commit the files. Include a commit message.}
+$ @kbd{git push} @ii{Push the files up to the repo. Ta da!}
+@end example
+
+The first three steps are the same described earlier
+(@pxref{Starting A New Branch}).
+The @samp{git push} is what's new, and it updates the repo on
+Savannah. Congratulations!
+
+As a courtesy, you should send a note to the mailing list indicating
+that you have pushed your change.
+
+@node Developing new features
+@section Developing New Features
+
+Developing a new feature can be easier once you have commit access
+to the repo. First, create a new branch to hold your feature:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@example
+$ @kbd{git checkout master} @ii{Start from} master
+$ @kbd{git pull} @ii{Be sure to be up to date}
+$ @kbd{git checkout -b feature/python} @ii{Create and switch to a new branch}
+@end example
+
+Now, you can develop as normal, adding new files if necessary (such as new tests),
+modifying code, updating the @file{ChangeLog} and documentation, and so on.
+
+You can share changes with the mailing list as diffs, as usual. However, especially
+for a large feature, it would be better to push your branch up to Savannah. Then,
+everyone else can simply pull it down to their local systems and review your
+changes at their leisure.
+
+To push your branch up initially:
+
+@cindex @code{git diff}
+@cindex @code{git add}
+@cindex @code{git commit}
+@cindex @code{git push}
+@example
+$ @kbd{git diff} @ii{Review your changes}
+$ @kbd{git add @dots{}} @ii{Add any files for committing}
+$ @kbd{git commit} @ii{Commit the files. Include a commit message}
+$ @kbd{git push -u origin feature/python} @ii{Push the branch up to the repo}
+@end example
+
+When you use @samp{push -u origin}, Git helpfully converts
+your purely local branch into a tracking branch. It becomes
+as if the branch had originated from the upstream repo
+and you checked it out locally.
+
+@emph{You only need to do @samp{git push -u origin} once.}
+As you continue to work on your branch, the workflow simplifies
+into this:
+
+@cindex @code{git diff}
+@cindex @code{git add}
+@cindex @code{git commit}
+@cindex @code{git push}
+@example
+$ @kbd{git diff} @ii{Review your changes}
+$ @kbd{git add @dots{}} @ii{Add any files for committing}
+$ @kbd{git commit} @ii{Commit the files}
+$ @kbd{git push} @ii{Push your changes to the branch upstream}
+@end example
+
+@node Developing fixes
+@section Developing Fixes
+
+If you want to make a fix on @code{master} or on the current
+stable branch, you work the same way, by producing and discussing
+a diff on the mailing list. Once it's approved, you can commit it
+yourself:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@cindex @code{git add}
+@cindex @code{git commit}
+@cindex @code{git diff}
+@example
+$ @kbd{git checkout master} @ii{Move to} master
+$ @kbd{git pull} @ii{Make sure we're up to date with the maintainer}
+$ @kbd{gvim @dots{}} @ii{Make any fixes, compile, test}
+$ @kbd{git diff} @ii{Review your changes}
+$ @kbd{git add @dots{}} @ii{Add any files for committing}
+$ @kbd{git commit} @ii{Commit the files. Include a commit message.}
+@end example
+
+When you're ready to push your changes:
+
+@cindex @code{git pull}
+@cindex @code{git push}
+@example
+$ @kbd{git pull} @ii{Download latest version; Git will merge}
+$ @kbd{gvim ...} @ii{Resolve any merge conflicts with} git add @ii{and} git commit
+$ @kbd{git push} @ii{Now you can push your changes upstream}
+@end example
+
+@xref{Merge Conflicts} for instructions on dealing with merge conflicts.
+
+@node General practices
+@chapter General Development Practices
+
+This @value{CHAPTER} discusses general practices for @command{gawk} development.
+The discussion here is mainly for developers with commit access to the
+Savannah repo.
+
+@table @dfn
+@cindex propagating fixes to other branches
+@cindex fixes, propagating to other branches
+@item Propagating Fixes
+Usually, bug fixes should be made on the current ``stable'' branch.
+Once a fix has been reviewed and approved, you can commit it and
+push it yourself.
+Typically, the maintainer then takes care to merge the fix to @code{master}
+and from there to any other branches. However, you are welcome to
+save him the time and do this yourself.
+
+@cindex directory ownership
+@cindex ownership of directories
+@item Directory ownership
+Some developers ``own'' certain parts of the tree, such as the @file{pc} and @file{vms} directories.
+They are allowed to commit changes to those directories without review by the mailing
+list, but changes that also touch the mainline code should be submitted for review.
+
+@item New feature development
+Unless you can convince the maintainer (and the other developers!) otherwise,
+you should @emph{always} start branches for new features from @code{master},
+and not from the current ``stable'' branch.
+
+Use @samp{checkout -b feature/@var{feature_name}} to create the initial branch.
+You may then elect to keep it purely local, or to push it up to Savannah for
+review, even if the feature is not yet totally ``ready for prime time.''
+@end table
+
+During development of a new feature, you will most likely wish to keep your
+feature branch up to date with respect to ongoing improvements in @code{master}.
+This is generally easy to do. There are two different mechanisms, and which
+one you use depends upon the nature of your new feature branch.
+
+@table @dfn
+@item As long as your branch is purely local
+You should use @samp{git rebase}
+to the keep the branch synchronized with the original branch from which it was forked:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@cindex @code{git rebase}
+@example
+$ @kbd{git checkout master} @ii{Move to} master
+$ @kbd{git pull} @ii{Bring it up to date}
+$ @kbd{git checkout feature/python} @ii{Move to your new feature branch}
+$ @kbd{git rebase master} @ii{Rebase from} master
+@end example
+
+@noindent
+The rebasing operation may require that you resolve conflicts
+(@pxref{Merge Conflicts}).
+Edit any conflicted files and resolve the problem(s). Compile and
+test your changes, then use @samp{git add}
+and @samp{git commit} to indicate resolution, and then use
+@samp{git rebase --continue} to continue the rebasing.
+Git is very good about providing short instructions on how to
+continue when such conflicts occur.
+
+@item Once the branch has been pushed up to Savannah
+You @emph{must} use @samp{git merge} to bring your feature branch up
+to date. That flow looks like this:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@cindex @code{git merge}
+@example
+$ @kbd{git checkout master} @ii{Move to} master
+$ @kbd{git pull} @ii{Bring it up to date}
+$ @kbd{git checkout feature/python} @ii{Move to your new feature branch}
+$ @kbd{git merge master} @ii{Merge from} master
+@end example
+
+@noindent
+Here too, you may have to resolve any merge conflicts
+(@pxref{Merge Conflicts}).
+Once that's done, you can push the changes up to Savannah.
+
+When the changes on your branch are complete, usually the
+maintainer merges the branch to @code{master}. But
+there's really no magic involved, the merge is simply
+done in the other direction:
+
+@cindex @code{git checkout}
+@cindex @code{git pull}
+@cindex @code{git merge}
+@example
+$ @kbd{git checkout feature/python} @ii{Checkout feature branch}
+$ @kbd{git pull} @ii{Bring it up to date}
+$ @kbd{git checkout master} @ii{Checkout} master
+$ @kbd{git pull} @ii{Bring it up to date}
+$ @kbd{git merge feature/python} @ii{Merge from} feature/python @ii{into} master
+@end example
+
+If you've been keeping @samp{feature/python} in sync with
+@code{master}, then there should be no merge conflicts to
+resolve, and you can push the result to Savannah:
+
+@cindex @code{git push}
+@example
+$ @kbd{git push} @ii{Push up to Savannah}
+@end example
+
+Since @samp{feature/python} is no longer needed, it can be
+gotten rid of:
+
+@cindex @code{git branch}
+@cindex @code{git push}
+@example
+$ @kbd{git branch -d feature/python} @ii{Still on} master@ii{, delete feature branch}
+$ @kbd{git push -u origin -d feature/python} @ii{Delete the branch on Savannah}
+@end example
+
+The @samp{git push} command deletes the @code{feature/python}
+branch from the Savannah repo.
+
+@cindex @code{git fetch}
+@noindent
+Finally, you should send an email to developer's list describing
+what you've done so that everyone else can delete their
+copies of the branch and do a @samp{git fetch --prune}
+(@pxref{Repo Maintenance}).
+
+To update the other remaining development branches
+with the latest changes on @code{master}, use the
+@samp{helpers/update-branches.sh} script in the repo.
+
+@end table
+
+@node Repo Maintenance
+@chapter Keeping Your Repo Organized
+
+There are a few commands you should know about to help keep
+your local repo clean.
+
+@table @emph
+@cindex removing old branches
+@cindex old branches, removing
+@cindex branches, removing
+@item Removing old branches
+Developers add branches to the Savannah repo and when development
+on them is done, they
+get merged into @code{master}. Then the branches on Savannah are
+deleted (as shown in @ref{General practices}).
+
+However, your local copies of those branches (labelled with the
+@samp{origin/} prefix) remain in your local repo. If you don't
+need them, then you can clean up your repo as follows.
+
+First, remove any related tracking branch you may have:
+
+@cindex @code{git pull}
+@cindex @code{git branch}
+@example
+$ @kbd{git pull} @ii{Get up to date}
+$ @kbd{git branch -d feature/merged-feature} @ii{Remove tracking branch}
+@end example
+
+Then, ask Git to clean things up for you:
+
+@cindex @code{git fetch}
+@example
+$ @kbd{git fetch --prune} @ii{Remove unneeded branches}
+@end example
+
+@cindex removing cruft
+@cindex cruft, removing
+@item Removing cruft
+As Git works, occasional ``cruft'' collects in the repository.
+Git does occasionally clean this out on its own, but if you're
+concerned about disk usage, you can do so yourself
+using @samp{git gc} (short for ``garbage collect''). For
+example:
+
+@cindex @code{git gc}
+@example
+$ @kbd{du -s .} @ii{Check disk usage}
+@print{} 99188 . @ii{Almost 10 megabytes}
+$ @kbd{git gc} @ii{Collect garbage}
+@print{} Counting objects: 32114, done.
+@print{} Delta compression using up to 4 threads.
+@print{} Compressing objects: 100% (6370/6370), done.
+@print{} Writing objects: 100% (32114/32114), done.
+@print{} Total 32114 (delta 25655), reused 31525 (delta 25231)
+$ @kbd{du -s .} @ii{Check disk usage again}
+@print{} 75168 . @ii{Down to 7 megabytes}
+@end example
+
+@cindex renaming branches
+@cindex branches, renaming
+@item Renaming branches
+Occasionally you may want to rename a branch.@footnote{This discussion
+adopted from
+@uref{https://multiplestates.wordpress.com/2015/02/05/rename-a-local-and-remote-branch-in-git, here}.}
+If your branch is local and you are on it, us:
+
+@example
+$ @kbd{git branch -m feature/@var{new-name}}
+@end example
+
+@noindent
+Otherwise, use:
+
+@example
+$ @kbd{git branch -m feature/@var{old-name} feature/@var{new-name}}
+@end example
+
+You then need to fix the upstream repo. This command does so,
+using an older syntax to simultaneously delete the old name and
+push the new name. You should be on the new branch:
+
+@example
+$ @kbd{git push origin :feature/@var{old-name} feature/@var{new-name}}
+@end example
+
+@quotation NOTE
+It is the leading @samp{:} in the first branch name that causes
+Git to delete the old name in the upstream repo. Don't omit it!
+@end quotation
+
+Finally, reset the upstream branch for the local branch
+with the new name:
+
+@example
+$ @kbd{git push -u origin feature/@var{new-name}}
+@end example
+
+@end table
+
+@node Development Stuff
+@chapter Development Stuff
+
+This @value{CHAPTER} discusses other things you need to know and/or do
+if you're going to participate seriously in @command{gawk} development.
+
+@menu
+* Coding style:: Where to read up on the coding style.
+* Doing paperwork:: Legal stuff in order to contribute.
+* Tools:: Tools to have on your system for development.
+* Debugging:: Compiling for debugging.
+@end menu
+
+@node Coding style
+@section Coding Style
+
+@cindex coding style
+You should read the discussion about adding code in the @command{gawk}
+documentation.
+@ifnothtml
+@xref{Additions, Additions, Making Additions to @command{gawk}, gawk, GAWK: Effective awk Programming},
+for a discussion of the general procedure. In particular, pay attention to the
+coding style guidelines in
+@ref{Adding Code, Adding Code, Adding New Features, gawk, GAWK: Effective awk Programming}.@footnote{Changes that don't follow the coding
+style guidelines won't be accepted. Period.}
+These two sections may also be found online, at
+@uref{https://www.gnu.org/software/gawk/manual/html_node/Additions.html#Additions}, and
+@uref{https://www.gnu.org/software/gawk/manual/html_node/Adding-Code.html#Adding-Code},
+respectively.
+@end ifnothtml
+@ifhtml
+See @uref{https://www.gnu.org/software/gawk/manual/html_node/Additions.html#Additions,
+the section @cite{Making Additions to @command{gawk}}}, in the online documentation
+for a discussion of the general procedure. In particular, pay attention to the
+coding style guidelines in
+@uref{https://www.gnu.org/software/gawk/manual/html_node/Adding-Code.html#Adding-Code,
+the section @cite{Adding New Features}}, also in the online documentation.
+@end ifhtml
+
+@node Doing paperwork
+@section Assigning Copyrights to the FSF
+
+@cindex assigning copyright
+@cindex copyright, assignment
+For any change of more than just a few lines, you will need to assign
+copyright in (that is, ownership of) those changes to the Free Software
+Foundation.
+
+This is generally an easy thing to do. In particular, you can choose to
+use a version of the copyright assignment which assigns all your current
+@emph{and future} changes to @command{gawk} to the FSF. This means
+that you only need to do the paperwork once, and from then on all your
+changes will automatically belong to the FSF. The maintainer recommends
+doing this.
+
+The maintainer will help you with this process once you have a
+contribution that warrants it.
+
+@node Tools
+@section Software Tools You Will Need
+
+@cindex software tools
+This @value{SECTION} discusses additional tools that you may need to
+install on your system in order to be in sync with what the @command{gawk}
+maintainer uses. It also discusses different C compiler options for use
+during code development, and how to compile @command{gawk} for debugging.
+
+@menu
+* GNU Tools:: The GNU Autotools.
+* Compilers:: A discussion of compilers that can be used.
+@end menu
+
+@node GNU Tools
+@subsection GNU Tools
+
+@cindex GNU software tools
+@cindex autotools
+If you expect to work with the configuration files and/or the
+@file{Makefile} files, you will need to install a number of other GNU
+tools. In general, you should be using the latest versions of the tools,
+or least the same ones that the maintainer himself uses. This helps
+minimize the differences that the maintainer has to resolve when merging
+changes, and in general avoids confusion and hassle.
+Similarly, you should install the latest GNU documentation tools as well.
+The tools are described in the following list:
+
+@table @command
+@cindex @command{autoconf}
+@cindex GNU @command{autoconf}
+@cindex @file{configure.ac} file
+@item autoconf
+GNU Autoconf processes the @file{configure.ac} files in order to
+generate the @file{configure} shell script and @file{config.h.in}
+input file. See @uref{https://www.gnu.org/software/autoconf/autoconf.html,
+the Autoconf home page} for more information.
+
+@cindex @command{automake}
+@cindex GNU @command{automake}
+@cindex @file{Makefile.am} file
+@item automake
+GNU Automake processes the @file{configure.ac} and @file{Makefile.am}
+files to produce @file{Makefile.in} files. See @uref{https://www.gnu.org/software/automake,
+the Automake home page} for more information.
+
+@cindex @command{gettext}
+@cindex GNU @command{gettext}
+@cindex @file{gawk.pot} file
+@item gettext
+GNU Gettext processes the @command{gawk} source code to produce the
+original @file{po/gawk.pot} message template file. Normally you
+should not need need to do this; the maintainer usually
+manages this task. See @uref{https://www.gnu.org/software/gettext,
+the Gettext home page} for more information.
+
+@cindex @command{libtool}
+@cindex GNU @command{libtool}
+@cindex extensions, @command{gawk}
+@item libtool
+GNU Libtool works with Autoconf and Automake to produce portable
+shared libraries. It is used for the extensions that ship with @command{gawk},
+whose code is in the @file{extensions} directory.
+See @uref{https://www.gnu.org/software/libtool, the Libtool home page}
+for more information.
+
+@cindex @command{makeinfo}
+@cindex GNU @command{makeinfo}
+@cindex @command{Texinfo}
+@cindex GNU Texinfo
+@item makeinfo
+The @command{makeinfo} command is used to build the Info versions of
+the documentation. You need to have the same version as the maintainer
+uses, so that when you make a change to the documentation, the corresponding
+change to the generated Info file will be minimal. @command{makeinfo} is
+part of GNU Texinfo. See @uref{https://www.gnu.org/software/texinfo,
+the Texinfo home page} for more information.
+
+@end table
+
+@node Compilers
+@subsection Compilers
+
+@cindex compilers
+@cindex GCC, the GNU Compiler Collection
+The default compiler for @command{gawk} development is GCC, the
+@uref{https://gcc.gnu.org, GNU Compiler Collection}.
+The default version of GCC is whatever is on the
+maintainer's personal GNU/Linux system, although he does try to build
+the latest released version if that is newer than what's
+on his system, and then occasionally test @command{gawk} with it.
+
+@cindex @command{clang} compiler
+He also attempts to test occasionally with @uref{https://clang.llvm.org/,
+@command{clang}}. However, he uses whatever is the default for his
+GNU/Linux system, and does @emph{not} make an effort to build the current
+version for testing.
+
+Both GCC and @command{clang} are highly optimizing compilers that produce
+good code, but are very slow. There are two other compilers that
+are faster, but that may not produce quite as good code. However, they
+are both reasonable for doing development.
+
+@table @emph
+@cindex @command{tcc} compiler
+@cindex Tiny C compiler
+@item The Tiny C Compiler, @command{tcc}
+This compiler is @emph{very} fast, but it produces only mediocre code.
+It is capable of compiling @command{gawk}, and it does so well enough
+that @samp{make check} runs without errors.
+
+However, in the past the quality has varied, and the maintainer has
+had problems with it. He recommends using it for regular development,
+where fast compiles are important, but rebuilding with GCC before doing
+any commits, in case @command{tcc} has missed something.@footnote{This
+bit the maintainer once.}
+
+See @uref{http://www.tinycc.org, the project's home page} for
+some information. More information can be found in the project's
+@uref{http://repo.or.cz/tinycc.git, Git repository}. The maintainer builds
+from the @code{mob} branch for his work, but after updating it you should
+check that this branch still works to compile @command{gawk} before
+installing it.
+
+@cindex @command{pcc} compiler
+@cindex Portable C compiler
+@item The (Revived) Portable C Compiler
+This is an updated version of the venerable Unix Portable C Compiler,
+PCC. It accepts ANSI C syntax and supports both older and modern
+architectures. It produces better code than @command{tcc} but is slower,
+although still much faster than GCC and @command{clang}.
+
+See @uref{http://pcc.ludd.ltu.se, the project's home page} for more
+information. See @uref{http://pcc.ludd.ltu.se/supported-platforms}
+for instructions about obtaining the code using CVS and building it.
+
+@cindex @command{pcc} compiler, Git mirror
+An alternative location for the source is the @command{gawk}
+maintainer's @uref{https://github.com/arnoldrobbins/pcc-revived,
+Git mirror} of the code.
+@end table
+
+@node Debugging
+@section Compiling For Debugging
+
+@cindex debugging, compiling for
+@cindex compiling for debugging
+If you wish to compile for debugging, you should use GCC. After
+running @command{configure} but before running @command{make}, edit the
+@file{Makefile} and remove the @option{-O2} flag from the definition of
+@code{CFLAGS}. Optionally, do the same for @file{extensions/Makefile}.
+Then run @command{make}.
+
+@cindex @file{.developing} file
+You can enable additional debugging code by creating a file
+named @file{.developing} in the @command{gawk} source code directory
+@emph{before} running @command{configure}. Doing so enables additional
+conditionally-compiled debugging code within @command{gawk}, and adds
+additional warning and debugging options if compiling with GCC.
+
+@node Cheat Sheet
+@appendix Git Command Cheat Sheet
+
+This @value{APPENDIX} provides an alphabetical list of the Git commands
+cited in this @value{DOCUMENT}, along with brief descriptions of
+what the commands do.
+
+@cindex @code{git help}
+@cindex @option{--help} option for @command{git}
+@cindex @command{git} command, @option{--help} option
+Note that you may always use either @samp{git help @var{command}}
+or @samp{git @var{command} --help} to get short, man-page style
+help on how to use any given Git command.
+
+@table @code
+@item git add
+Add a file to the list of files to be committed.
+
+@item git branch
+View existing branches, or delete a branch.
+Most useful options: @option{-a} and @option{-d}.
+
+@item git checkout
+Checkout an existing branch, create a new branch, or checkout a file to
+reset it. Use the @option{-b} option to create and checkout a
+new branch in one operation.
+
+@item git clone
+Clone (make a new copy of) an existing repository. You generally
+only need to do this once.
+
+@item git commit
+Commit changes to files which have been staged for committing
+with @samp{git add}.
+This makes your changes permanent, @emph{in your local repository only}.
+To publish your changes to an upstream repo, you must use @samp{git push}.
+
+@item git config
+Display and/or change global and/or local configuration settings.
+
+@item git diff
+Show a unified-format diff of what's changed in the current directory
+as of the last commit. It helps to have Git configured to use
+its builtin pager for reviewing diffs (@pxref{Configuring git}).
+
+@item git difftool
+Use a ``tool'' (usually a GUI-based program) to view differences,
+instead of the standard textual diff as you'd get from @samp{git diff}.
+
+@item git fetch
+Update your local copy of the upstream's branches. That is,
+update the various @samp{origin/} branches. This leaves your
+local tracking branches unchanged.
+With the @option{--prune} option, this removes any copies
+of stale @samp{origin/} branches.
+
+@item git format-patch
+Create a series of patch files, one per commit not on the
+original branch from which you started.
+
+@item git gc
+Run a ``garbage collection'' pass in the current repository.
+This can often reduce the space used in a large repo. For
+@command{gawk} it does not make that much difference.
+
+@item git help
+Print a man-page--style usage summary for a command.
+
+@item git log
+Show the current branch's commit log. This includes who
+made the commit, the date, and the commit message.
+Commits are shown from newest to oldest.
+
+@item git merge
+Merge changes from the named branch into the current one.
+
+@item git pull
+When in your local tracking branch @code{@var{xxx}},
+run @samp{git fetch}, and then merge from @code{origin/@var{xxx}}
+into @code{@var{xxx}}.
+
+@item git push
+Push commits from your local tracking branch @code{@var{xxx}}
+through @code{origin/@var{xxx}} and on to branch @code{@var{xxx}}
+in the upstream repo. Use @samp{git push -u origin -d @var{xxx}} to delete
+an upstream branch. (Do so carefully!)
+
+@item git rebase
+Rebase the changes in the current purely local branch to
+look as if they had been made relative to the latest
+commit in the current upstream branch (typically @code{master}).
+This is how you keep your local, in-progress changes up-to-date
+with respect to the original branch from which they were started.
+
+@item git reset
+@cindex @code{git reset}, @option{--hard} option
+Restore the original state of the repo, especially with the
+@option{--hard} option. Read up on this command, and use it carefully.
+
+@item git status
+Show the status of files that are scheduled to be committed,
+and those that have been modified but not yet scheduled for committing.
+Use @samp{git add} to schedule a file for committing.
+This command also lists untracked files.
+
+@end table
+
+@node Resources
+@appendix Git Resources
+
+@cindex @cite{Pro Git} book
+There are many Git resources available on the Internet.
+Start at the @uref{http://git-scm.org, Git Project home page}.
+In particular, the @uref{https://git-scm.com/book/en/v2,
+@cite{Pro Git} book} is available online.
+
+@cindex Savannah, using Git guide
+See also @uref{http://savannah.gnu.org/maintenance/UsingGit,
+the Savannah quick introduction to Git}.
+
+@node TODO
+@appendix Stuff Still To Do In This Document
+
+@itemize @bullet
+@item
+Fill out all examples with full output
+
+@end itemize
+
+@ifnotdocbook
+@node Index
+@unnumbered Index
+@end ifnotdocbook
+@printindex cp
+
+@bye
diff --git a/doc/it/ChangeLog b/doc/it/ChangeLog
new file mode 100644
index 00000000..112686c5
--- /dev/null
+++ b/doc/it/ChangeLog
@@ -0,0 +1,7 @@
+2017-04-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * ChangeLog: created.
+
+ Italian translation of "The Gawk Manual", contributed
+ by Antonio Giovanni Colombo <azc100@gmail.com>
+ and Marco Curreli <marcocurreli@tiscali.it>.
diff --git a/doc/it/api-figura1.eps b/doc/it/api-figura1.eps
new file mode 100644
index 00000000..93560797
--- /dev/null
+++ b/doc/it/api-figura1.eps
@@ -0,0 +1,536 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: api-figura1.fig
+%%Creator: fig2dev Version 3.2 Patchlevel 5e
+%%CreationDate: Wed Jun 29 10:59:41 2016
+%%BoundingBox: 0 0 356 221
+%Magnification: 1.0000
+%%EndComments
+%%BeginProlog
+/MyAppDict 100 dict dup begin def
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+
+% This junk string is used by the show operators
+/PATsstr 1 string def
+/PATawidthshow { % cx cy cchar rx ry string
+ % Loop over each character in the string
+ { % cx cy cchar rx ry char
+ % Show the character
+ dup % cx cy cchar rx ry char char
+ PATsstr dup 0 4 -1 roll put % cx cy cchar rx ry char (char)
+ false charpath % cx cy cchar rx ry char
+ /clip load PATdraw
+ % Move past the character (charpath modified the
+ % current point)
+ currentpoint % cx cy cchar rx ry char x y
+ newpath
+ moveto % cx cy cchar rx ry char
+ % Reposition by cx,cy if the character in the string is cchar
+ 3 index eq { % cx cy cchar rx ry
+ 4 index 4 index rmoveto
+ } if
+ % Reposition all characters by rx ry
+ 2 copy rmoveto % cx cy cchar rx ry
+ } forall
+ pop pop pop pop pop % -
+ currentpoint
+ newpath
+ moveto
+} bind def
+/PATcg {
+ 7 dict dup begin
+ /lw currentlinewidth def
+ /lc currentlinecap def
+ /lj currentlinejoin def
+ /ml currentmiterlimit def
+ /ds [ currentdash ] def
+ /cc [ currentrgbcolor ] def
+ /cm matrix currentmatrix def
+ end
+} bind def
+% PATdraw - calculates the boundaries of the object and
+% fills it with the current pattern
+/PATdraw { % proc
+ save exch
+ PATpcalc % proc nw nh px py
+ 5 -1 roll exec % nw nh px py
+ newpath
+ PATfill % -
+ restore
+} bind def
+% PATfill - performs the tiling for the shape
+/PATfill { % nw nh px py PATfill -
+ PATDict /CurrentPattern get dup begin
+ setfont
+ % Set the coordinate system to Pattern Space
+ PatternGState PATsg
+ % Set the color for uncolored pattezns
+ PaintType 2 eq { PATDict /PColor get PATsc } if
+ % Create the string for showing
+ 3 index string % nw nh px py str
+ % Loop for each of the pattern sources
+ 0 1 Multi 1 sub { % nw nh px py str source
+ % Move to the starting location
+ 3 index 3 index % nw nh px py str source px py
+ moveto % nw nh px py str source
+ % For multiple sources, set the appropriate color
+ Multi 1 ne { dup PC exch get PATsc } if
+ % Set the appropriate string for the source
+ 0 1 7 index 1 sub { 2 index exch 2 index put } for pop
+ % Loop over the number of vertical cells
+ 3 index % nw nh px py str nh
+ { % nw nh px py str
+ currentpoint % nw nh px py str cx cy
+ 2 index oldshow % nw nh px py str cx cy
+ YStep add moveto % nw nh px py str
+ } repeat % nw nh px py str
+ } for
+ 5 { pop } repeat
+ end
+} bind def
+
+% PATkshow - kshow with the current pattezn
+/PATkshow { % proc string
+ exch bind % string proc
+ 1 index 0 get % string proc char
+ % Loop over all but the last character in the string
+ 0 1 4 index length 2 sub {
+ % string proc char idx
+ % Find the n+1th character in the string
+ 3 index exch 1 add get % string proc char char+1
+ exch 2 copy % strinq proc char+1 char char+1 char
+ % Now show the nth character
+ PATsstr dup 0 4 -1 roll put % string proc chr+1 chr chr+1 (chr)
+ false charpath % string proc char+1 char char+1
+ /clip load PATdraw
+ % Move past the character (charpath modified the current point)
+ currentpoint newpath moveto
+ % Execute the user proc (should consume char and char+1)
+ mark 3 1 roll % string proc char+1 mark char char+1
+ 4 index exec % string proc char+1 mark...
+ cleartomark % string proc char+1
+ } for
+ % Now display the last character
+ PATsstr dup 0 4 -1 roll put % string proc (char+1)
+ false charpath % string proc
+ /clip load PATdraw
+ neewath
+ pop pop % -
+} bind def
+% PATmp - the makepattern equivalent
+/PATmp { % patdict patmtx PATmp patinstance
+ exch dup length 7 add % We will add 6 new entries plus 1 FID
+ dict copy % Create a new dictionary
+ begin
+ % Matrix to install when painting the pattern
+ TilingType PATtcalc
+ /PatternGState PATcg def
+ PatternGState /cm 3 -1 roll put
+ % Check for multi pattern sources (Level 1 fast color patterns)
+ currentdict /Multi known not { /Multi 1 def } if
+ % Font dictionary definitions
+ /FontType 3 def
+ % Create a dummy encoding vector
+ /Encoding 256 array def
+ 3 string 0 1 255 {
+ Encoding exch dup 3 index cvs cvn put } for pop
+ /FontMatrix matrix def
+ /FontBBox BBox def
+ /BuildChar {
+ mark 3 1 roll % mark dict char
+ exch begin
+ Multi 1 ne {PaintData exch get}{pop} ifelse % mark [paintdata]
+ PaintType 2 eq Multi 1 ne or
+ { XStep 0 FontBBox aload pop setcachedevice }
+ { XStep 0 setcharwidth } ifelse
+ currentdict % mark [paintdata] dict
+ /PaintProc load % mark [paintdata] dict paintproc
+ end
+ gsave
+ false PATredef exec true PATredef
+ grestore
+ cleartomark % -
+ } bind def
+ currentdict
+ end % newdict
+ /foo exch % /foo newlict
+ definefont % newfont
+} bind def
+% PATpcalc - calculates the starting point and width/height
+% of the tile fill for the shape
+/PATpcalc { % - PATpcalc nw nh px py
+ PATDict /CurrentPattern get begin
+ gsave
+ % Set up the coordinate system to Pattern Space
+ % and lock down pattern
+ PatternGState /cm get setmatrix
+ BBox aload pop pop pop translate
+ % Determine the bounding box of the shape
+ pathbbox % llx lly urx ury
+ grestore
+ % Determine (nw, nh) the # of cells to paint width and height
+ PatHeight div ceiling % llx lly urx qh
+ 4 1 roll % qh llx lly urx
+ PatWidth div ceiling % qh llx lly qw
+ 4 1 roll % qw qh llx lly
+ PatHeight div floor % qw qh llx ph
+ 4 1 roll % ph qw qh llx
+ PatWidth div floor % ph qw qh pw
+ 4 1 roll % pw ph qw qh
+ 2 index sub cvi abs % pw ph qs qh-ph
+ exch 3 index sub cvi abs exch % pw ph nw=qw-pw nh=qh-ph
+ % Determine the starting point of the pattern fill
+ %(px, py)
+ 4 2 roll % nw nh pw ph
+ PatHeight mul % nw nh pw py
+ exch % nw nh py pw
+ PatWidth mul exch % nw nh px py
+ end
+} bind def
+
+% Save the original routines so that we can use them later on
+/oldfill /fill load def
+/oldeofill /eofill load def
+/oldstroke /stroke load def
+/oldshow /show load def
+/oldashow /ashow load def
+/oldwidthshow /widthshow load def
+/oldawidthshow /awidthshow load def
+/oldkshow /kshow load def
+
+% These defs are necessary so that subsequent procs don't bind in
+% the originals
+/fill { oldfill } bind def
+/eofill { oldeofill } bind def
+/stroke { oldstroke } bind def
+/show { oldshow } bind def
+/ashow { oldashow } bind def
+/widthshow { oldwidthshow } bind def
+/awidthshow { oldawidthshow } bind def
+/kshow { oldkshow } bind def
+/PATredef {
+ MyAppDict begin
+ {
+ /fill { /clip load PATdraw newpath } bind def
+ /eofill { /eoclip load PATdraw newpath } bind def
+ /stroke { PATstroke } bind def
+ /show { 0 0 null 0 0 6 -1 roll PATawidthshow } bind def
+ /ashow { 0 0 null 6 3 roll PATawidthshow }
+ bind def
+ /widthshow { 0 0 3 -1 roll PATawidthshow }
+ bind def
+ /awidthshow { PATawidthshow } bind def
+ /kshow { PATkshow } bind def
+ } {
+ /fill { oldfill } bind def
+ /eofill { oldeofill } bind def
+ /stroke { oldstroke } bind def
+ /show { oldshow } bind def
+ /ashow { oldashow } bind def
+ /widthshow { oldwidthshow } bind def
+ /awidthshow { oldawidthshow } bind def
+ /kshow { oldkshow } bind def
+ } ifelse
+ end
+} bind def
+false PATredef
+% Conditionally define setcmykcolor if not available
+/setcmykcolor where { pop } {
+ /setcmykcolor {
+ 1 sub 4 1 roll
+ 3 {
+ 3 index add neg dup 0 lt { pop 0 } if 3 1 roll
+ } repeat
+ setrgbcolor - pop
+ } bind def
+} ifelse
+/PATsc { % colorarray
+ aload length % c1 ... cn length
+ dup 1 eq { pop setgray } { 3 eq { setrgbcolor } { setcmykcolor
+ } ifelse } ifelse
+} bind def
+/PATsg { % dict
+ begin
+ lw setlinewidth
+ lc setlinecap
+ lj setlinejoin
+ ml setmiterlimit
+ ds aload pop setdash
+ cc aload pop setrgbcolor
+ cm setmatrix
+ end
+} bind def
+
+/PATDict 3 dict def
+/PATsp {
+ true PATredef
+ PATDict begin
+ /CurrentPattern exch def
+ % If it's an uncolored pattern, save the color
+ CurrentPattern /PaintType get 2 eq {
+ /PColor exch def
+ } if
+ /CColor [ currentrgbcolor ] def
+ end
+} bind def
+% PATstroke - stroke with the current pattern
+/PATstroke {
+ countdictstack
+ save
+ mark
+ {
+ currentpoint strokepath moveto
+ PATpcalc % proc nw nh px py
+ clip newpath PATfill
+ } stopped {
+ (*** PATstroke Warning: Path is too complex, stroking
+ with gray) =
+ cleartomark
+ restore
+ countdictstack exch sub dup 0 gt
+ { { end } repeat } { pop } ifelse
+ gsave 0.5 setgray oldstroke grestore
+ } { pop restore pop } ifelse
+ newpath
+} bind def
+/PATtcalc { % modmtx tilingtype PATtcalc tilematrix
+ % Note: tiling types 2 and 3 are not supported
+ gsave
+ exch concat % tilingtype
+ matrix currentmatrix exch % cmtx tilingtype
+ % Tiling type 1 and 3: constant spacing
+ 2 ne {
+ % Distort the pattern so that it occupies
+ % an integral number of device pixels
+ dup 4 get exch dup 5 get exch % tx ty cmtx
+ XStep 0 dtransform
+ round exch round exch % tx ty cmtx dx.x dx.y
+ XStep div exch XStep div exch % tx ty cmtx a b
+ 0 YStep dtransform
+ round exch round exch % tx ty cmtx a b dy.x dy.y
+ YStep div exch YStep div exch % tx ty cmtx a b c d
+ 7 -3 roll astore % { a b c d tx ty }
+ } if
+ grestore
+} bind def
+/PATusp {
+ false PATredef
+ PATDict begin
+ CColor PATsc
+ end
+} bind def
+
+% right30
+11 dict begin
+/PaintType 1 def
+/PatternType 1 def
+/TilingType 1 def
+/BBox [0 0 1 1] def
+/XStep 1 def
+/YStep 1 def
+/PatWidth 1 def
+/PatHeight 1 def
+/Multi 2 def
+/PaintData [
+ { clippath } bind
+ { 32 16 true [ 32 0 0 -16 0 16 ]
+ {<00030003000c000c0030003000c000c0030003000c000c00
+ 30003000c000c00000030003000c000c0030003000c000c0
+ 030003000c000c0030003000c000c000>}
+ imagemask } bind
+] def
+/PaintProc {
+ pop
+ exec fill
+} def
+currentdict
+end
+/P2 exch def
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+/pageheader {
+save
+newpath 0 221 moveto 0 0 lineto 356 0 lineto 356 221 lineto closepath clip newpath
+-194.8 344.2 translate
+1 -1 scale
+$F2psBegin
+10 setmiterlimit
+0 slj 0 slc
+ 0.06299 0.06299 sc
+} bind def
+/pagefooter {
+$F2psEnd
+restore
+} bind def
+%%EndProlog
+pageheader
+%
+% Fig objects follow
+%
+%
+% here starts figure with depth 50
+% Arc
+7.500 slw
+0 slc
+gs clippath
+3599 4000 m 3567 4148 l 3626 4161 l 3658 4013 l 3658 4013 l 3603 4124 l 3599 4000 l cp
+eoclip
+n 5449.3 4471.5 1878.7 -70.5453 -169.8379 arcn
+gs col0 s gr
+ gr
+
+% arrowhead
+0 slj
+n 3599 4000 m 3603 4124 l 3658 4013 l 3599 4000 l cp gs 0.00 setgray ef gr col0 s
+% Arc
+gs clippath
+4422 4004 m 4425 4155 l 4485 4154 l 4482 4003 l 4482 4003 l 4455 4124 l 4422 4004 l cp
+eoclip
+n 5539.0 4051.3 1087.6 -60.4713 175.3232 arcn
+gs col0 s gr
+ gr
+
+% arrowhead
+n 4422 4004 m 4455 4124 l 4482 4003 l 4422 4004 l cp gs 0.00 setgray ef gr col0 s
+% Arc
+gs clippath
+4986 4010 m 5012 4159 l 5072 4149 l 5046 4000 l 5046 4000 l 5037 4124 l 4986 4010 l cp
+eoclip
+n 5628.8 3967.5 613.5 -36.7999 163.6698 arcn
+gs col0 s gr
+ gr
+
+% arrowhead
+n 4986 4010 m 5037 4124 l 5046 4000 l 4986 4010 l cp gs 0.00 setgray ef gr col0 s
+% Arc
+135.000 slw
+gs clippath
+7736 3835 m 7756 3984 l 7907 3964 l 7887 3814 l 7841 3821 l 7828 3944 l 7782 3829 l cp
+eoclip
+n 6609.1 4056.9 1224.8 -93.9364 -4.5364 arc
+gs col0 s gr
+ gr
+
+% arrowhead
+7.500 slw
+n 7782 3829 m 7828 3944 l 7841 3821 l col0 s
+% Polyline
+n 3105 4140 m 6660 4140 l 6660 5085 l 3105 5085 l
+ cp gs col0 s gr
+% Polyline
+n 6660 4140 m 8730 4140 l 8730 5085 l 6660 5085 l
+ cp gs col7 0.50 shd ef gr gs col0 s gr
+% Polyline
+n 5805 2610 m 6345 2610 l 6345 3690 l 5805 3690 l
+ cp gs col0 s gr
+% Polyline
+n 5805 2835 m 6345 2835 l 6345 3015 l 5805 3015 l
+ cp gs col0 s gr
+% Polyline
+n 5805 3195 m 6345 3195 l 6345 3375 l 5805 3375 l
+ cp gs col0 s gr
+% Polyline
+n 5805 3510 m 6345 3510 l 6345 3690 l 5805 3690 l
+ cp gs col0 s gr
+% Polyline
+n 3510 4140 m 3780 4140 l 3780 5085 l 3510 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 234.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 4365 4140 m 4635 4140 l 4635 5085 l 4365 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 291.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 4905 4140 m 5265 4140 l 5265 5085 l 4905 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 327.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+/Times-Roman ff 190.50 scf sf
+5985 2115 m
+gs 1 -1 sc (API) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+5895 2340 m
+gs 1 -1 sc (Struct) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+7020 5400 m
+gs 1 -1 sc ( Estensione) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+6525 2655 m
+gs 1 -1 sc (dl_load\(api_p, id\);) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+3195 5400 m
+gs 1 -1 sc (Memoria indirizzabile programma gawk) col0 sh gr
+% here ends figure;
+pagefooter
+showpage
+%%Trailer
+end
+%EOF
diff --git a/doc/it/api-figura1.fig b/doc/it/api-figura1.fig
new file mode 100644
index 00000000..c2718c71
--- /dev/null
+++ b/doc/it/api-figura1.fig
@@ -0,0 +1,40 @@
+#FIG 3.2 Produced by xfig version 3.2.5c
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 5449.265 4471.471 6075 2700 4320 2970 3600 4140
+ 1 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 5538.971 4051.323 6075 3105 4725 3330 4455 4140
+ 1 1 1.00 60.00 120.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 5628.750 3967.500 6120 3600 5220 3510 5040 4140
+ 1 1 1.00 60.00 120.00
+5 1 0 10 0 7 50 -1 -1 0.000 0 0 1 0 6609.079 4056.868 6525 2835 7560 3285 7830 3960
+ 0 0 1.00 60.00 120.00
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3105 4140 6660 4140 6660 5085 3105 5085 3105 4140
+2 2 0 1 0 7 50 -1 10 0.000 0 0 -1 0 0 5
+ 6660 4140 8730 4140 8730 5085 6660 5085 6660 4140
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5805 2610 6345 2610 6345 3690 5805 3690 5805 2610
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5805 2835 6345 2835 6345 3015 5805 3015 5805 2835
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5805 3195 6345 3195 6345 3375 5805 3375 5805 3195
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5805 3510 6345 3510 6345 3690 5805 3690 5805 3510
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 3510 4140 3780 4140 3780 5085 3510 5085 3510 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 4365 4140 4635 4140 4635 5085 4365 5085 4365 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 4905 4140 5265 4140 5265 5085 4905 5085 4905 4140
+4 0 0 50 -1 0 12 0.0000 4 135 270 5985 2115 API\001
+4 0 0 50 -1 0 12 0.0000 4 135 540 5895 2340 Struct\001
+4 0 0 50 -1 0 12 0.0000 4 135 1170 7020 5400 Estensione\001
+4 0 0 50 -1 0 12 0.0000 4 180 1710 6525 2655 dl_load(api_p, id);\001
+4 0 0 50 -1 0 12 0.0000 4 165 3240 3195 5400 Memoria indirizzabile programma gawk\001
diff --git a/doc/it/api-figura1.pdf b/doc/it/api-figura1.pdf
new file mode 100644
index 00000000..f31e25a8
--- /dev/null
+++ b/doc/it/api-figura1.pdf
Binary files differ
diff --git a/doc/it/api-figura1.png b/doc/it/api-figura1.png
new file mode 100644
index 00000000..444c2976
--- /dev/null
+++ b/doc/it/api-figura1.png
Binary files differ
diff --git a/doc/it/api-figura1.txt b/doc/it/api-figura1.txt
new file mode 100644
index 00000000..630e18f0
--- /dev/null
+++ b/doc/it/api-figura1.txt
@@ -0,0 +1,24 @@
+ Struct (Struttura)
+ API
+ +---+
+ | |
+ +---+
+ +---------------| |
+ | +---+ dl_load(api_p, id);
+ | | | ___________________
+ | +---+ |
+ | +---------| | __________________ |
+ | | +---+ ||
+ | | | | ||
+ | | +---+ ||
+ | | +---| | ||
+ | | | +---+ \ || /
+ | | | \ /
+ v v v \/
++-------+-+---+-+---+-+------------------+--------------------+
+| |x| |x| |x| |OOOOOOOOOOOOOOOOOOOO|
+| |x| |x| |x| |OOOOOOOOOOOOOOOOOOOO|
+| |x| |x| |x| |OOOOOOOOOOOOOOOOOOOO|
++-------+-+---+-+---+-+------------------+--------------------+
+
+ Memoria indirizzabile programma gawk Estensione
diff --git a/doc/it/api-figura2.eps b/doc/it/api-figura2.eps
new file mode 100644
index 00000000..9920d3b9
--- /dev/null
+++ b/doc/it/api-figura2.eps
@@ -0,0 +1,517 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: api-figura2.fig
+%%Creator: fig2dev Version 3.2 Patchlevel 5e
+%%CreationDate: Wed Jun 29 11:02:52 2016
+%%BoundingBox: 0 0 356 173
+%Magnification: 1.0000
+%%EndComments
+%%BeginProlog
+/MyAppDict 100 dict dup begin def
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+
+% This junk string is used by the show operators
+/PATsstr 1 string def
+/PATawidthshow { % cx cy cchar rx ry string
+ % Loop over each character in the string
+ { % cx cy cchar rx ry char
+ % Show the character
+ dup % cx cy cchar rx ry char char
+ PATsstr dup 0 4 -1 roll put % cx cy cchar rx ry char (char)
+ false charpath % cx cy cchar rx ry char
+ /clip load PATdraw
+ % Move past the character (charpath modified the
+ % current point)
+ currentpoint % cx cy cchar rx ry char x y
+ newpath
+ moveto % cx cy cchar rx ry char
+ % Reposition by cx,cy if the character in the string is cchar
+ 3 index eq { % cx cy cchar rx ry
+ 4 index 4 index rmoveto
+ } if
+ % Reposition all characters by rx ry
+ 2 copy rmoveto % cx cy cchar rx ry
+ } forall
+ pop pop pop pop pop % -
+ currentpoint
+ newpath
+ moveto
+} bind def
+/PATcg {
+ 7 dict dup begin
+ /lw currentlinewidth def
+ /lc currentlinecap def
+ /lj currentlinejoin def
+ /ml currentmiterlimit def
+ /ds [ currentdash ] def
+ /cc [ currentrgbcolor ] def
+ /cm matrix currentmatrix def
+ end
+} bind def
+% PATdraw - calculates the boundaries of the object and
+% fills it with the current pattern
+/PATdraw { % proc
+ save exch
+ PATpcalc % proc nw nh px py
+ 5 -1 roll exec % nw nh px py
+ newpath
+ PATfill % -
+ restore
+} bind def
+% PATfill - performs the tiling for the shape
+/PATfill { % nw nh px py PATfill -
+ PATDict /CurrentPattern get dup begin
+ setfont
+ % Set the coordinate system to Pattern Space
+ PatternGState PATsg
+ % Set the color for uncolored pattezns
+ PaintType 2 eq { PATDict /PColor get PATsc } if
+ % Create the string for showing
+ 3 index string % nw nh px py str
+ % Loop for each of the pattern sources
+ 0 1 Multi 1 sub { % nw nh px py str source
+ % Move to the starting location
+ 3 index 3 index % nw nh px py str source px py
+ moveto % nw nh px py str source
+ % For multiple sources, set the appropriate color
+ Multi 1 ne { dup PC exch get PATsc } if
+ % Set the appropriate string for the source
+ 0 1 7 index 1 sub { 2 index exch 2 index put } for pop
+ % Loop over the number of vertical cells
+ 3 index % nw nh px py str nh
+ { % nw nh px py str
+ currentpoint % nw nh px py str cx cy
+ 2 index oldshow % nw nh px py str cx cy
+ YStep add moveto % nw nh px py str
+ } repeat % nw nh px py str
+ } for
+ 5 { pop } repeat
+ end
+} bind def
+
+% PATkshow - kshow with the current pattezn
+/PATkshow { % proc string
+ exch bind % string proc
+ 1 index 0 get % string proc char
+ % Loop over all but the last character in the string
+ 0 1 4 index length 2 sub {
+ % string proc char idx
+ % Find the n+1th character in the string
+ 3 index exch 1 add get % string proc char char+1
+ exch 2 copy % strinq proc char+1 char char+1 char
+ % Now show the nth character
+ PATsstr dup 0 4 -1 roll put % string proc chr+1 chr chr+1 (chr)
+ false charpath % string proc char+1 char char+1
+ /clip load PATdraw
+ % Move past the character (charpath modified the current point)
+ currentpoint newpath moveto
+ % Execute the user proc (should consume char and char+1)
+ mark 3 1 roll % string proc char+1 mark char char+1
+ 4 index exec % string proc char+1 mark...
+ cleartomark % string proc char+1
+ } for
+ % Now display the last character
+ PATsstr dup 0 4 -1 roll put % string proc (char+1)
+ false charpath % string proc
+ /clip load PATdraw
+ neewath
+ pop pop % -
+} bind def
+% PATmp - the makepattern equivalent
+/PATmp { % patdict patmtx PATmp patinstance
+ exch dup length 7 add % We will add 6 new entries plus 1 FID
+ dict copy % Create a new dictionary
+ begin
+ % Matrix to install when painting the pattern
+ TilingType PATtcalc
+ /PatternGState PATcg def
+ PatternGState /cm 3 -1 roll put
+ % Check for multi pattern sources (Level 1 fast color patterns)
+ currentdict /Multi known not { /Multi 1 def } if
+ % Font dictionary definitions
+ /FontType 3 def
+ % Create a dummy encoding vector
+ /Encoding 256 array def
+ 3 string 0 1 255 {
+ Encoding exch dup 3 index cvs cvn put } for pop
+ /FontMatrix matrix def
+ /FontBBox BBox def
+ /BuildChar {
+ mark 3 1 roll % mark dict char
+ exch begin
+ Multi 1 ne {PaintData exch get}{pop} ifelse % mark [paintdata]
+ PaintType 2 eq Multi 1 ne or
+ { XStep 0 FontBBox aload pop setcachedevice }
+ { XStep 0 setcharwidth } ifelse
+ currentdict % mark [paintdata] dict
+ /PaintProc load % mark [paintdata] dict paintproc
+ end
+ gsave
+ false PATredef exec true PATredef
+ grestore
+ cleartomark % -
+ } bind def
+ currentdict
+ end % newdict
+ /foo exch % /foo newlict
+ definefont % newfont
+} bind def
+% PATpcalc - calculates the starting point and width/height
+% of the tile fill for the shape
+/PATpcalc { % - PATpcalc nw nh px py
+ PATDict /CurrentPattern get begin
+ gsave
+ % Set up the coordinate system to Pattern Space
+ % and lock down pattern
+ PatternGState /cm get setmatrix
+ BBox aload pop pop pop translate
+ % Determine the bounding box of the shape
+ pathbbox % llx lly urx ury
+ grestore
+ % Determine (nw, nh) the # of cells to paint width and height
+ PatHeight div ceiling % llx lly urx qh
+ 4 1 roll % qh llx lly urx
+ PatWidth div ceiling % qh llx lly qw
+ 4 1 roll % qw qh llx lly
+ PatHeight div floor % qw qh llx ph
+ 4 1 roll % ph qw qh llx
+ PatWidth div floor % ph qw qh pw
+ 4 1 roll % pw ph qw qh
+ 2 index sub cvi abs % pw ph qs qh-ph
+ exch 3 index sub cvi abs exch % pw ph nw=qw-pw nh=qh-ph
+ % Determine the starting point of the pattern fill
+ %(px, py)
+ 4 2 roll % nw nh pw ph
+ PatHeight mul % nw nh pw py
+ exch % nw nh py pw
+ PatWidth mul exch % nw nh px py
+ end
+} bind def
+
+% Save the original routines so that we can use them later on
+/oldfill /fill load def
+/oldeofill /eofill load def
+/oldstroke /stroke load def
+/oldshow /show load def
+/oldashow /ashow load def
+/oldwidthshow /widthshow load def
+/oldawidthshow /awidthshow load def
+/oldkshow /kshow load def
+
+% These defs are necessary so that subsequent procs don't bind in
+% the originals
+/fill { oldfill } bind def
+/eofill { oldeofill } bind def
+/stroke { oldstroke } bind def
+/show { oldshow } bind def
+/ashow { oldashow } bind def
+/widthshow { oldwidthshow } bind def
+/awidthshow { oldawidthshow } bind def
+/kshow { oldkshow } bind def
+/PATredef {
+ MyAppDict begin
+ {
+ /fill { /clip load PATdraw newpath } bind def
+ /eofill { /eoclip load PATdraw newpath } bind def
+ /stroke { PATstroke } bind def
+ /show { 0 0 null 0 0 6 -1 roll PATawidthshow } bind def
+ /ashow { 0 0 null 6 3 roll PATawidthshow }
+ bind def
+ /widthshow { 0 0 3 -1 roll PATawidthshow }
+ bind def
+ /awidthshow { PATawidthshow } bind def
+ /kshow { PATkshow } bind def
+ } {
+ /fill { oldfill } bind def
+ /eofill { oldeofill } bind def
+ /stroke { oldstroke } bind def
+ /show { oldshow } bind def
+ /ashow { oldashow } bind def
+ /widthshow { oldwidthshow } bind def
+ /awidthshow { oldawidthshow } bind def
+ /kshow { oldkshow } bind def
+ } ifelse
+ end
+} bind def
+false PATredef
+% Conditionally define setcmykcolor if not available
+/setcmykcolor where { pop } {
+ /setcmykcolor {
+ 1 sub 4 1 roll
+ 3 {
+ 3 index add neg dup 0 lt { pop 0 } if 3 1 roll
+ } repeat
+ setrgbcolor - pop
+ } bind def
+} ifelse
+/PATsc { % colorarray
+ aload length % c1 ... cn length
+ dup 1 eq { pop setgray } { 3 eq { setrgbcolor } { setcmykcolor
+ } ifelse } ifelse
+} bind def
+/PATsg { % dict
+ begin
+ lw setlinewidth
+ lc setlinecap
+ lj setlinejoin
+ ml setmiterlimit
+ ds aload pop setdash
+ cc aload pop setrgbcolor
+ cm setmatrix
+ end
+} bind def
+
+/PATDict 3 dict def
+/PATsp {
+ true PATredef
+ PATDict begin
+ /CurrentPattern exch def
+ % If it's an uncolored pattern, save the color
+ CurrentPattern /PaintType get 2 eq {
+ /PColor exch def
+ } if
+ /CColor [ currentrgbcolor ] def
+ end
+} bind def
+% PATstroke - stroke with the current pattern
+/PATstroke {
+ countdictstack
+ save
+ mark
+ {
+ currentpoint strokepath moveto
+ PATpcalc % proc nw nh px py
+ clip newpath PATfill
+ } stopped {
+ (*** PATstroke Warning: Path is too complex, stroking
+ with gray) =
+ cleartomark
+ restore
+ countdictstack exch sub dup 0 gt
+ { { end } repeat } { pop } ifelse
+ gsave 0.5 setgray oldstroke grestore
+ } { pop restore pop } ifelse
+ newpath
+} bind def
+/PATtcalc { % modmtx tilingtype PATtcalc tilematrix
+ % Note: tiling types 2 and 3 are not supported
+ gsave
+ exch concat % tilingtype
+ matrix currentmatrix exch % cmtx tilingtype
+ % Tiling type 1 and 3: constant spacing
+ 2 ne {
+ % Distort the pattern so that it occupies
+ % an integral number of device pixels
+ dup 4 get exch dup 5 get exch % tx ty cmtx
+ XStep 0 dtransform
+ round exch round exch % tx ty cmtx dx.x dx.y
+ XStep div exch XStep div exch % tx ty cmtx a b
+ 0 YStep dtransform
+ round exch round exch % tx ty cmtx a b dy.x dy.y
+ YStep div exch YStep div exch % tx ty cmtx a b c d
+ 7 -3 roll astore % { a b c d tx ty }
+ } if
+ grestore
+} bind def
+/PATusp {
+ false PATredef
+ PATDict begin
+ CColor PATsc
+ end
+} bind def
+
+% right30
+11 dict begin
+/PaintType 1 def
+/PatternType 1 def
+/TilingType 1 def
+/BBox [0 0 1 1] def
+/XStep 1 def
+/YStep 1 def
+/PatWidth 1 def
+/PatHeight 1 def
+/Multi 2 def
+/PaintData [
+ { clippath } bind
+ { 32 16 true [ 32 0 0 -16 0 16 ]
+ {<00030003000c000c0030003000c000c0030003000c000c00
+ 30003000c000c00000030003000c000c0030003000c000c0
+ 030003000c000c0030003000c000c000>}
+ imagemask } bind
+] def
+/PaintProc {
+ pop
+ exec fill
+} def
+currentdict
+end
+/P2 exch def
+
+% crosshatch45
+11 dict begin
+/PaintType 1 def
+/PatternType 1 def
+/TilingType 1 def
+/BBox [0 0 1 1] def
+/XStep 1 def
+/YStep 1 def
+/PatWidth 1 def
+/PatHeight 1 def
+/Multi 2 def
+/PaintData [
+ { clippath } bind
+ { 20 20 true [ 20 0 0 -20 0 20 ]
+ {<8020004050102088201104400a02800401000a02
+ 8011044020882040501080200040501020882011
+ 04400a02800401000a0280110440208820405010>}
+ imagemask } bind
+] def
+/PaintProc {
+ pop
+ exec fill
+} def
+currentdict
+end
+/P6 exch def
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+/pageheader {
+save
+newpath 0 173 moveto 0 0 lineto 356 0 lineto 356 173 lineto closepath clip newpath
+-194.8 344.2 translate
+1 -1 scale
+$F2psBegin
+10 setmiterlimit
+0 slj 0 slc
+ 0.06299 0.06299 sc
+} bind def
+/pagefooter {
+$F2psEnd
+restore
+} bind def
+%%EndProlog
+pageheader
+%
+% Fig objects follow
+%
+%
+% here starts figure with depth 50
+% Arc
+7.500 slw
+0 slc
+gs clippath
+3662 4014 m 3567 4132 l 3613 4170 l 3708 4052 l 3708 4052 l 3610 4127 l 3662 4014 l cp
+eoclip
+n 5895.0 5917.5 2902.8 -37.7581 -142.2419 arcn
+gs col0 s gr
+ gr
+
+% arrowhead
+0 slj
+n 3662 4014 m 3610 4127 l 3708 4052 l 3662 4014 l cp gs 0.00 setgray ef gr col0 s
+% Polyline
+n 3105 4140 m 6660 4140 l 6660 5085 l 3105 5085 l
+ cp gs col0 s gr
+% Polyline
+n 6660 4140 m 8730 4140 l 8730 5085 l 6660 5085 l
+ cp gs col7 0.50 shd ef gr gs col0 s gr
+% Polyline
+n 3510 4140 m 3780 4140 l 3780 5085 l 3510 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 234.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 4365 4140 m 4635 4140 l 4635 5085 l 4365 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 291.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 4905 4140 m 5265 4140 l 5265 5085 l 4905 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 327.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 7965 4140 m 8370 4140 l 8370 5085 l 7965 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P6 [16 0 0 -16 531.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+/Courier-Bold ff 190.50 scf sf
+3420 2880 m
+gs 1 -1 sc (register_ext_func\({ "chdir", do_chdir, 1 }\);) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+6840 5400 m
+gs 1 -1 sc ( Estensione) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+3195 5400 m
+gs 1 -1 sc (Memoria indirizzabile programma gawk) col0 sh gr
+% here ends figure;
+pagefooter
+showpage
+%%Trailer
+end
+%EOF
diff --git a/doc/it/api-figura2.fig b/doc/it/api-figura2.fig
new file mode 100644
index 00000000..a8b5c47d
--- /dev/null
+++ b/doc/it/api-figura2.fig
@@ -0,0 +1,26 @@
+#FIG 3.2 Produced by xfig version 3.2.5c
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 5895.000 5917.500 8190 4140 5940 3015 3600 4140
+ 1 1 1.00 60.00 120.00
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3105 4140 6660 4140 6660 5085 3105 5085 3105 4140
+2 2 0 1 0 7 50 -1 10 0.000 0 0 -1 0 0 5
+ 6660 4140 8730 4140 8730 5085 6660 5085 6660 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 3510 4140 3780 4140 3780 5085 3510 5085 3510 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 4365 4140 4635 4140 4635 5085 4365 5085 4365 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 4905 4140 5265 4140 5265 5085 4905 5085 4905 4140
+2 2 0 1 0 7 50 -1 46 0.000 0 0 -1 0 0 5
+ 7965 4140 8370 4140 8370 5085 7965 5085 7965 4140
+4 0 0 50 -1 14 12 0.0000 4 180 3960 3420 2880 register_ext_func({ "chdir", do_chdir, 1 });\001
+4 0 0 50 -1 0 12 0.0000 4 135 1260 6840 5400 Estensione\001
+4 0 0 50 -1 0 12 0.0000 4 165 3240 3195 5400 Memoria indirizzabile programma gawk\001
diff --git a/doc/it/api-figura2.pdf b/doc/it/api-figura2.pdf
new file mode 100644
index 00000000..cadd4267
--- /dev/null
+++ b/doc/it/api-figura2.pdf
Binary files differ
diff --git a/doc/it/api-figura2.png b/doc/it/api-figura2.png
new file mode 100644
index 00000000..dbc46910
--- /dev/null
+++ b/doc/it/api-figura2.png
Binary files differ
diff --git a/doc/it/api-figura2.txt b/doc/it/api-figura2.txt
new file mode 100644
index 00000000..a030fb5a
--- /dev/null
+++ b/doc/it/api-figura2.txt
@@ -0,0 +1,12 @@
+ register_ext_func({ "chdir", do_chdir, 1 });
+
+ +--------------------------------------------+
+ | |
+ V |
++-------+-+---+-+---+-+------------------+--------------+-+---+
+| |x| |x| |x| |OOOOOOOOOOOOOO|X|OOO|
+| |x| |x| |x| |OOOOOOOOOOOOOO|X|OOO|
+| |x| |x| |x| |OOOOOOOOOOOOOO|X|OOO|
++-------+-+---+-+---+-+------------------+--------------+-+---+
+
+ Memoria indirizzabile programma gawk Estensione
diff --git a/doc/it/api-figura3.eps b/doc/it/api-figura3.eps
new file mode 100644
index 00000000..daa3ba76
--- /dev/null
+++ b/doc/it/api-figura3.eps
@@ -0,0 +1,526 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: api-figura3.fig
+%%Creator: fig2dev Version 3.2 Patchlevel 5e
+%%CreationDate: Wed Jun 29 11:05:29 2016
+%%BoundingBox: 0 0 356 170
+%Magnification: 1.0000
+%%EndComments
+%%BeginProlog
+/MyAppDict 100 dict dup begin def
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+
+% This junk string is used by the show operators
+/PATsstr 1 string def
+/PATawidthshow { % cx cy cchar rx ry string
+ % Loop over each character in the string
+ { % cx cy cchar rx ry char
+ % Show the character
+ dup % cx cy cchar rx ry char char
+ PATsstr dup 0 4 -1 roll put % cx cy cchar rx ry char (char)
+ false charpath % cx cy cchar rx ry char
+ /clip load PATdraw
+ % Move past the character (charpath modified the
+ % current point)
+ currentpoint % cx cy cchar rx ry char x y
+ newpath
+ moveto % cx cy cchar rx ry char
+ % Reposition by cx,cy if the character in the string is cchar
+ 3 index eq { % cx cy cchar rx ry
+ 4 index 4 index rmoveto
+ } if
+ % Reposition all characters by rx ry
+ 2 copy rmoveto % cx cy cchar rx ry
+ } forall
+ pop pop pop pop pop % -
+ currentpoint
+ newpath
+ moveto
+} bind def
+/PATcg {
+ 7 dict dup begin
+ /lw currentlinewidth def
+ /lc currentlinecap def
+ /lj currentlinejoin def
+ /ml currentmiterlimit def
+ /ds [ currentdash ] def
+ /cc [ currentrgbcolor ] def
+ /cm matrix currentmatrix def
+ end
+} bind def
+% PATdraw - calculates the boundaries of the object and
+% fills it with the current pattern
+/PATdraw { % proc
+ save exch
+ PATpcalc % proc nw nh px py
+ 5 -1 roll exec % nw nh px py
+ newpath
+ PATfill % -
+ restore
+} bind def
+% PATfill - performs the tiling for the shape
+/PATfill { % nw nh px py PATfill -
+ PATDict /CurrentPattern get dup begin
+ setfont
+ % Set the coordinate system to Pattern Space
+ PatternGState PATsg
+ % Set the color for uncolored pattezns
+ PaintType 2 eq { PATDict /PColor get PATsc } if
+ % Create the string for showing
+ 3 index string % nw nh px py str
+ % Loop for each of the pattern sources
+ 0 1 Multi 1 sub { % nw nh px py str source
+ % Move to the starting location
+ 3 index 3 index % nw nh px py str source px py
+ moveto % nw nh px py str source
+ % For multiple sources, set the appropriate color
+ Multi 1 ne { dup PC exch get PATsc } if
+ % Set the appropriate string for the source
+ 0 1 7 index 1 sub { 2 index exch 2 index put } for pop
+ % Loop over the number of vertical cells
+ 3 index % nw nh px py str nh
+ { % nw nh px py str
+ currentpoint % nw nh px py str cx cy
+ 2 index oldshow % nw nh px py str cx cy
+ YStep add moveto % nw nh px py str
+ } repeat % nw nh px py str
+ } for
+ 5 { pop } repeat
+ end
+} bind def
+
+% PATkshow - kshow with the current pattezn
+/PATkshow { % proc string
+ exch bind % string proc
+ 1 index 0 get % string proc char
+ % Loop over all but the last character in the string
+ 0 1 4 index length 2 sub {
+ % string proc char idx
+ % Find the n+1th character in the string
+ 3 index exch 1 add get % string proc char char+1
+ exch 2 copy % strinq proc char+1 char char+1 char
+ % Now show the nth character
+ PATsstr dup 0 4 -1 roll put % string proc chr+1 chr chr+1 (chr)
+ false charpath % string proc char+1 char char+1
+ /clip load PATdraw
+ % Move past the character (charpath modified the current point)
+ currentpoint newpath moveto
+ % Execute the user proc (should consume char and char+1)
+ mark 3 1 roll % string proc char+1 mark char char+1
+ 4 index exec % string proc char+1 mark...
+ cleartomark % string proc char+1
+ } for
+ % Now display the last character
+ PATsstr dup 0 4 -1 roll put % string proc (char+1)
+ false charpath % string proc
+ /clip load PATdraw
+ neewath
+ pop pop % -
+} bind def
+% PATmp - the makepattern equivalent
+/PATmp { % patdict patmtx PATmp patinstance
+ exch dup length 7 add % We will add 6 new entries plus 1 FID
+ dict copy % Create a new dictionary
+ begin
+ % Matrix to install when painting the pattern
+ TilingType PATtcalc
+ /PatternGState PATcg def
+ PatternGState /cm 3 -1 roll put
+ % Check for multi pattern sources (Level 1 fast color patterns)
+ currentdict /Multi known not { /Multi 1 def } if
+ % Font dictionary definitions
+ /FontType 3 def
+ % Create a dummy encoding vector
+ /Encoding 256 array def
+ 3 string 0 1 255 {
+ Encoding exch dup 3 index cvs cvn put } for pop
+ /FontMatrix matrix def
+ /FontBBox BBox def
+ /BuildChar {
+ mark 3 1 roll % mark dict char
+ exch begin
+ Multi 1 ne {PaintData exch get}{pop} ifelse % mark [paintdata]
+ PaintType 2 eq Multi 1 ne or
+ { XStep 0 FontBBox aload pop setcachedevice }
+ { XStep 0 setcharwidth } ifelse
+ currentdict % mark [paintdata] dict
+ /PaintProc load % mark [paintdata] dict paintproc
+ end
+ gsave
+ false PATredef exec true PATredef
+ grestore
+ cleartomark % -
+ } bind def
+ currentdict
+ end % newdict
+ /foo exch % /foo newlict
+ definefont % newfont
+} bind def
+% PATpcalc - calculates the starting point and width/height
+% of the tile fill for the shape
+/PATpcalc { % - PATpcalc nw nh px py
+ PATDict /CurrentPattern get begin
+ gsave
+ % Set up the coordinate system to Pattern Space
+ % and lock down pattern
+ PatternGState /cm get setmatrix
+ BBox aload pop pop pop translate
+ % Determine the bounding box of the shape
+ pathbbox % llx lly urx ury
+ grestore
+ % Determine (nw, nh) the # of cells to paint width and height
+ PatHeight div ceiling % llx lly urx qh
+ 4 1 roll % qh llx lly urx
+ PatWidth div ceiling % qh llx lly qw
+ 4 1 roll % qw qh llx lly
+ PatHeight div floor % qw qh llx ph
+ 4 1 roll % ph qw qh llx
+ PatWidth div floor % ph qw qh pw
+ 4 1 roll % pw ph qw qh
+ 2 index sub cvi abs % pw ph qs qh-ph
+ exch 3 index sub cvi abs exch % pw ph nw=qw-pw nh=qh-ph
+ % Determine the starting point of the pattern fill
+ %(px, py)
+ 4 2 roll % nw nh pw ph
+ PatHeight mul % nw nh pw py
+ exch % nw nh py pw
+ PatWidth mul exch % nw nh px py
+ end
+} bind def
+
+% Save the original routines so that we can use them later on
+/oldfill /fill load def
+/oldeofill /eofill load def
+/oldstroke /stroke load def
+/oldshow /show load def
+/oldashow /ashow load def
+/oldwidthshow /widthshow load def
+/oldawidthshow /awidthshow load def
+/oldkshow /kshow load def
+
+% These defs are necessary so that subsequent procs don't bind in
+% the originals
+/fill { oldfill } bind def
+/eofill { oldeofill } bind def
+/stroke { oldstroke } bind def
+/show { oldshow } bind def
+/ashow { oldashow } bind def
+/widthshow { oldwidthshow } bind def
+/awidthshow { oldawidthshow } bind def
+/kshow { oldkshow } bind def
+/PATredef {
+ MyAppDict begin
+ {
+ /fill { /clip load PATdraw newpath } bind def
+ /eofill { /eoclip load PATdraw newpath } bind def
+ /stroke { PATstroke } bind def
+ /show { 0 0 null 0 0 6 -1 roll PATawidthshow } bind def
+ /ashow { 0 0 null 6 3 roll PATawidthshow }
+ bind def
+ /widthshow { 0 0 3 -1 roll PATawidthshow }
+ bind def
+ /awidthshow { PATawidthshow } bind def
+ /kshow { PATkshow } bind def
+ } {
+ /fill { oldfill } bind def
+ /eofill { oldeofill } bind def
+ /stroke { oldstroke } bind def
+ /show { oldshow } bind def
+ /ashow { oldashow } bind def
+ /widthshow { oldwidthshow } bind def
+ /awidthshow { oldawidthshow } bind def
+ /kshow { oldkshow } bind def
+ } ifelse
+ end
+} bind def
+false PATredef
+% Conditionally define setcmykcolor if not available
+/setcmykcolor where { pop } {
+ /setcmykcolor {
+ 1 sub 4 1 roll
+ 3 {
+ 3 index add neg dup 0 lt { pop 0 } if 3 1 roll
+ } repeat
+ setrgbcolor - pop
+ } bind def
+} ifelse
+/PATsc { % colorarray
+ aload length % c1 ... cn length
+ dup 1 eq { pop setgray } { 3 eq { setrgbcolor } { setcmykcolor
+ } ifelse } ifelse
+} bind def
+/PATsg { % dict
+ begin
+ lw setlinewidth
+ lc setlinecap
+ lj setlinejoin
+ ml setmiterlimit
+ ds aload pop setdash
+ cc aload pop setrgbcolor
+ cm setmatrix
+ end
+} bind def
+
+/PATDict 3 dict def
+/PATsp {
+ true PATredef
+ PATDict begin
+ /CurrentPattern exch def
+ % If it's an uncolored pattern, save the color
+ CurrentPattern /PaintType get 2 eq {
+ /PColor exch def
+ } if
+ /CColor [ currentrgbcolor ] def
+ end
+} bind def
+% PATstroke - stroke with the current pattern
+/PATstroke {
+ countdictstack
+ save
+ mark
+ {
+ currentpoint strokepath moveto
+ PATpcalc % proc nw nh px py
+ clip newpath PATfill
+ } stopped {
+ (*** PATstroke Warning: Path is too complex, stroking
+ with gray) =
+ cleartomark
+ restore
+ countdictstack exch sub dup 0 gt
+ { { end } repeat } { pop } ifelse
+ gsave 0.5 setgray oldstroke grestore
+ } { pop restore pop } ifelse
+ newpath
+} bind def
+/PATtcalc { % modmtx tilingtype PATtcalc tilematrix
+ % Note: tiling types 2 and 3 are not supported
+ gsave
+ exch concat % tilingtype
+ matrix currentmatrix exch % cmtx tilingtype
+ % Tiling type 1 and 3: constant spacing
+ 2 ne {
+ % Distort the pattern so that it occupies
+ % an integral number of device pixels
+ dup 4 get exch dup 5 get exch % tx ty cmtx
+ XStep 0 dtransform
+ round exch round exch % tx ty cmtx dx.x dx.y
+ XStep div exch XStep div exch % tx ty cmtx a b
+ 0 YStep dtransform
+ round exch round exch % tx ty cmtx a b dy.x dy.y
+ YStep div exch YStep div exch % tx ty cmtx a b c d
+ 7 -3 roll astore % { a b c d tx ty }
+ } if
+ grestore
+} bind def
+/PATusp {
+ false PATredef
+ PATDict begin
+ CColor PATsc
+ end
+} bind def
+
+% right30
+11 dict begin
+/PaintType 1 def
+/PatternType 1 def
+/TilingType 1 def
+/BBox [0 0 1 1] def
+/XStep 1 def
+/YStep 1 def
+/PatWidth 1 def
+/PatHeight 1 def
+/Multi 2 def
+/PaintData [
+ { clippath } bind
+ { 32 16 true [ 32 0 0 -16 0 16 ]
+ {<00030003000c000c0030003000c000c0030003000c000c00
+ 30003000c000c00000030003000c000c0030003000c000c0
+ 030003000c000c0030003000c000c000>}
+ imagemask } bind
+] def
+/PaintProc {
+ pop
+ exec fill
+} def
+currentdict
+end
+/P2 exch def
+
+% crosshatch45
+11 dict begin
+/PaintType 1 def
+/PatternType 1 def
+/TilingType 1 def
+/BBox [0 0 1 1] def
+/XStep 1 def
+/YStep 1 def
+/PatWidth 1 def
+/PatHeight 1 def
+/Multi 2 def
+/PaintData [
+ { clippath } bind
+ { 20 20 true [ 20 0 0 -20 0 20 ]
+ {<8020004050102088201104400a02800401000a02
+ 8011044020882040501080200040501020882011
+ 04400a02800401000a0280110440208820405010>}
+ imagemask } bind
+] def
+/PaintProc {
+ pop
+ exec fill
+} def
+currentdict
+end
+/P6 exch def
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+/pageheader {
+save
+newpath 0 170 moveto 0 0 lineto 356 0 lineto 356 170 lineto closepath clip newpath
+-194.8 344.2 translate
+1 -1 scale
+$F2psBegin
+10 setmiterlimit
+0 slj 0 slc
+ 0.06299 0.06299 sc
+} bind def
+/pagefooter {
+$F2psEnd
+restore
+} bind def
+%%EndProlog
+pageheader
+%
+% Fig objects follow
+%
+%
+% here starts figure with depth 50
+% Arc
+7.500 slw
+0 slc
+gs clippath
+8019 4079 m 8138 4172 l 8175 4125 l 8056 4032 l 8056 4032 l 8132 4130 l 8019 4079 l cp
+eoclip
+n 6120.0 6627.7 3207.7 -129.1463 -50.8537 arc
+gs col0 s gr
+ gr
+
+% arrowhead
+0 slj
+n 8019 4079 m 8132 4130 l 8056 4032 l 8019 4079 l cp gs 0.00 setgray ef gr col0 s
+% Polyline
+n 3105 4140 m 6660 4140 l 6660 5085 l 3105 5085 l
+ cp gs col0 s gr
+% Polyline
+n 6660 4140 m 8730 4140 l 8730 5085 l 6660 5085 l
+ cp gs col7 0.50 shd ef gr gs col0 s gr
+% Polyline
+n 3510 4140 m 3780 4140 l 3780 5085 l 3510 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 234.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 4365 4140 m 4635 4140 l 4635 5085 l 4365 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 291.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 4905 4140 m 5265 4140 l 5265 5085 l 4905 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P2 [16 0 0 -8 327.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+% Polyline
+n 7965 4140 m 8370 4140 l 8370 5085 l 7965 5085 l
+ cp gs /PC [[1.00 1.00 1.00] [0.00 0.00 0.00]] def
+15.00 15.00 sc P6 [16 0 0 -16 531.00 276.00] PATmp PATsp ef gr PATusp gs col0 s gr
+/Courier-Bold ff 190.50 scf sf
+3240 3150 m
+gs 1 -1 sc ( chdir\("/path"\)) col0 sh gr
+/Courier-Bold ff 190.50 scf sf
+3330 3375 m
+gs 1 -1 sc (}) col0 sh gr
+/Courier-Bold ff 190.50 scf sf
+3375 2925 m
+gs 1 -1 sc (BEGIN {) col0 sh gr
+/Courier-Bold ff 190.50 scf sf
+6660 3150 m
+gs 1 -1 sc (\(*fnptr\)\(1\);) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+3150 5400 m
+gs 1 -1 sc (Memoria indirizzabile programma gawk) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+6930 5400 m
+gs 1 -1 sc ( Estensione) col0 sh gr
+% here ends figure;
+pagefooter
+showpage
+%%Trailer
+end
+%EOF
diff --git a/doc/it/api-figura3.fig b/doc/it/api-figura3.fig
new file mode 100644
index 00000000..fae92940
--- /dev/null
+++ b/doc/it/api-figura3.fig
@@ -0,0 +1,29 @@
+#FIG 3.2 Produced by xfig version 3.2.5c
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 6120.000 6627.656 4095 4140 6120 3420 8145 4140
+ 1 1 1.00 60.00 120.00
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3105 4140 6660 4140 6660 5085 3105 5085 3105 4140
+2 2 0 1 0 7 50 -1 10 0.000 0 0 -1 0 0 5
+ 6660 4140 8730 4140 8730 5085 6660 5085 6660 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 3510 4140 3780 4140 3780 5085 3510 5085 3510 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 4365 4140 4635 4140 4635 5085 4365 5085 4365 4140
+2 2 0 1 0 7 50 -1 42 0.000 0 0 -1 0 0 5
+ 4905 4140 5265 4140 5265 5085 4905 5085 4905 4140
+2 2 0 1 0 7 50 -1 46 0.000 0 0 -1 0 0 5
+ 7965 4140 8370 4140 8370 5085 7965 5085 7965 4140
+4 0 0 50 -1 14 12 0.0000 4 180 1620 3240 3150 chdir("/path")\001
+4 0 0 50 -1 14 12 0.0000 4 165 90 3330 3375 }\001
+4 0 0 50 -1 14 12 0.0000 4 165 630 3375 2925 BEGIN {\001
+4 0 0 50 -1 14 12 0.0000 4 180 1080 6660 3150 (*fnptr)(1);\001
+4 0 0 50 -1 0 12 0.0000 4 165 3240 3150 5400 Memoria indirizzabile programma gawk\001
+4 0 0 50 -1 0 12 0.0000 4 135 1260 6930 5400 Estensione\001
diff --git a/doc/it/api-figura3.pdf b/doc/it/api-figura3.pdf
new file mode 100644
index 00000000..07f406bd
--- /dev/null
+++ b/doc/it/api-figura3.pdf
Binary files differ
diff --git a/doc/it/api-figura3.png b/doc/it/api-figura3.png
new file mode 100644
index 00000000..26ca6cd6
--- /dev/null
+++ b/doc/it/api-figura3.png
Binary files differ
diff --git a/doc/it/api-figura3.txt b/doc/it/api-figura3.txt
new file mode 100644
index 00000000..02791df5
--- /dev/null
+++ b/doc/it/api-figura3.txt
@@ -0,0 +1,13 @@
+ BEGIN {
+ chdir("/path") (*fnptr)(1);
+ }
+ +--------------------------------------------+
+ | |
+ | V
++-------+-+---+-+---+-+------------------+--------------+-+---+
+| |x| |x| |x| |OOOOOOOOOOOOOO|X|OOO|
+| |x| |x| |x| |OOOOOOOOOOOOOO|X|OOO|
+| |x| |x| |x| |OOOOOOOOOOOOOO|X|OOO|
++-------+-+---+-+---+-+------------------+--------------+-+---+
+
+ Memoria indirizzabile programma gawk Estensione
diff --git a/doc/it/compila_originale.sh b/doc/it/compila_originale.sh
new file mode 100755
index 00000000..06d53b93
--- /dev/null
+++ b/doc/it/compila_originale.sh
@@ -0,0 +1,16 @@
+
+#
+# builds the PDF version of the Gawk manual,
+# in the current directory
+#
+echo "Building the pdf version of the gawk manual"
+echo "in directory:"
+pwd
+echo "Beware, it can take a long time!"
+if [ -f "gawktexi.in" ]
+then
+ gawk -f sidebar.awk gawktexi.in >gawk.texi
+fi
+# just in case, drop previous Index
+rm -f gawk.cps gawk.cp gawk.aux gawk.fn gawk.ky gawk.log gawk.pg
+texi2pdf gawk.texi
diff --git a/doc/it/compila_smallprint.sh b/doc/it/compila_smallprint.sh
new file mode 100755
index 00000000..dd8d57f4
--- /dev/null
+++ b/doc/it/compila_smallprint.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# eventuali file di lavoro da elaborazioni precedenti
+rm -f gawk-it-17x24.pdf gawk-it.toc gawk-it.aux gawk-it.cp gawk-it.texi 2>/dev/null
+
+sed '{
+ s/@example/@smallexample/g
+ s/@end example/@end smallexample/g
+ }' gawktexi.in > gawktexi-tmp.in
+
+awk -f sidebar.awk < gawktexi-tmp.in > gawk-it.texi
+
+texi2dvi -t "@set SMALLPRINT" -t "@set FOR_PRINT" -t @manuale -t "@include margini.texi" gawk-it.texi -o gawk-it-17x24.dvi
+
+dvipdfmx --dvipdfm -p 170mm,240mm gawk-it-17x24.dvi
+
+awk -f sidebar.awk < gawktexi.in > gawk-it.texi
+
+rm gawktexi-tmp.in
diff --git a/doc/it/epsf.tex b/doc/it/epsf.tex
new file mode 100644
index 00000000..847de77f
--- /dev/null
+++ b/doc/it/epsf.tex
@@ -0,0 +1,653 @@
+%%% -*-TeX-*-
+%%% ====================================================================
+%%% @TeX-file{
+%%% author = "Tom Rokicki",
+%%% version = "2.7.4",
+%%% date = "14 February 2011",
+%%% time = "15:44:06 MST",
+%%% filename = "epsf.tex",
+%%% address = "Tom Rokicki
+%%% Box 2081
+%%% Stanford, CA 94309
+%%% USA",
+%%% telephone = "+1 415 855 9989",
+%%% checksum = "29223 653 3100 27123",
+%%% email = "rokicki@cs.stanford.edu (Internet)",
+%%% codetable = "ISO/ASCII",
+%%% copyright = "This file is freely redistributable and
+%%% placed into the public domain by Tomas
+%%% Rokicki.",
+%%% keywords = "PostScript, TeX",
+%%% license = "public domain",
+%%% supported = "yes",
+%%% abstract = "This file contains macros to support the
+%%% inclusion of Encapsulated PostScript files
+%%% in TeX documents.",
+%%% docstring = "This file contains TeX macros to include an
+%%% Encapsulated PostScript graphic. It works
+%%% by finding the bounding box comment,
+%%% calculating the correct scale values, and
+%%% inserting a vbox of the appropriate size at
+%%% the current position in the TeX document.
+%%%
+%%% To use, simply use
+%%%
+%%% \input epsf % somewhere early on in your TeX file
+%%%
+%%% % then where you want to insert a vbox for a figure:
+%%% \epsfbox{filename.ps}
+%%%
+%%% Alternatively, you can supply your own
+%%% bounding box by
+%%%
+%%% \epsfbox[0 0 30 50]{filename.ps}
+%%%
+%%% This will not read in the file, and will
+%%% instead use the bounding box you specify.
+%%%
+%%% The effect will be to typeset the figure as
+%%% a TeX box, at the point of your \epsfbox
+%%% command. By default, the graphic will have
+%%% its `natural' width (namely the width of
+%%% its bounding box, as described in
+%%% filename.ps). The TeX box will have depth
+%%% zero.
+%%%
+%%% You can enlarge or reduce the figure by
+%%% using
+%%%
+%%% \epsfxsize = <dimen> \epsfbox{filename.ps}
+%%% or
+%%% \epsfysize = <dimen> \epsfbox{filename.ps}
+%%%
+%%% instead. Then the width of the TeX box will
+%%% be \epsfxsize and its height will be scaled
+%%% proportionately (or the height will be
+%%% \epsfysize and its width will be scaled
+%%% proportionately).
+%%%
+%%% The width (and height) is restored to zero
+%%% after each use, so \epsfxsize or \epsfysize
+%%% must be specified before EACH use of
+%%% \epsfbox.
+%%%
+%%% A more general facility for sizing is
+%%% available by defining the \epsfsize macro.
+%%% Normally you can redefine this macro to do
+%%% almost anything. The first parameter is
+%%% the natural x size of the PostScript
+%%% graphic, the second parameter is the
+%%% natural y size of the PostScript graphic.
+%%% It must return the xsize to use, or 0 if
+%%% natural scaling is to be used. Common uses
+%%% include:
+%%%
+%%% \epsfxsize % just leave the old value alone
+%%% 0pt % use the natural sizes
+%%% #1 % use the natural sizes
+%%% \hsize % scale to full width
+%%% 0.5#1 % scale to 50% of natural size
+%%% \ifnum #1 > \hsize \hsize \else #1\fi
+%%% % smaller of natural, hsize
+%%%
+%%% If you want TeX to report the size of the
+%%% figure (as a message on your terminal when
+%%% it processes each figure), use
+%%% `\epsfverbosetrue'.
+%%%
+%%% If you only want to get the bounding box
+%%% extents, without producing any output boxes
+%%% or \special{}, then use \epsfgetbb{filename}.
+%%% The bounding box corner coordinates are saved
+%%% in the macros \epsfllx, \epsflly, \epsfurx,
+%%% and \epsfury in PostScript units of big
+%%% points.
+%%%
+%%% Revision history:
+%%%
+%%% ---------------------------------------------
+%%% epsf.tex macro file:
+%%% Originally written by Tomas Rokicki of
+%%% Radical Eye Software, 29 Mar 1989.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Don Knuth, 3 Jan 1990.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Tomas Rokicki, 18 Jul 1990.
+%%% Accept bounding boxes with no space after
+%%% the colon.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 03 Dec 1991 [2.0].
+%%% Add version number and date typeout.
+%%%
+%%% Use \immediate\write16 instead of \message
+%%% to ensure output on new line.
+%%%
+%%% Handle nested EPS files.
+%%%
+%%% Handle %%BoundingBox: (atend) lines.
+%%%
+%%% Do not quit when blank lines are found.
+%%%
+%%% Add a few percents to remove generation of
+%%% spurious blank space.
+%%%
+%%% Move \special output to
+%%% \epsfspecial{filename} so that other macro
+%%% packages can input this one, then change
+%%% the definition of \epsfspecial to match
+%%% another DVI driver.
+%%%
+%%% Move size computation to \epsfsetsize which
+%%% can be called by the user; the verbose
+%%% output of the bounding box and scaled width
+%%% and height happens here.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 05 May 1992 [2.1].
+%%% Wrap \leavevmode\hbox{} around \vbox{} with
+%%% the \special so that \epsffile{} can be
+%%% used inside \begin{center}...\end{center}
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 09 Dec 1992 [2.2].
+%%% Introduce \epsfshow{true,false} and
+%%% \epsfframe{true,false} macros; the latter
+%%% suppresses the insertion of the PostScript,
+%%% and instead just creates an empty box,
+%%% which may be handy for rapid prototyping.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 14 Dec 1992 [2.3].
+%%% Add \epsfshowfilename{true,false}. When
+%%% true, and \epsfshowfalse is specified, the
+%%% PostScript file name will be displayed
+%%% centered in the figure box.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 20 June 1993 [2.4].
+%%% Remove non-zero debug setting of \epsfframemargin,
+%%% and change margin handling to preserve EPS image
+%%% size and aspect ratio, so that the actual
+%%% box is \epsfxsize+\epsfframemargin wide by
+%%% \epsfysize+\epsfframemargin high.
+%%% Reduce output of \epsfshowfilenametrue to
+%%% just the bare file name.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 13 July 1993 [2.5].
+%%% Add \epsfframethickness for control of
+%%% \epsfframe frame lines.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 02 July 1996 [2.6]
+%%% Add missing initialization \epsfatendfalse;
+%%% the lack of this resulted in the wrong
+%%% BoundingBox being picked up, mea culpa, sigh...
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 25 October 1996 [2.7]
+%%% Update to match changes in from dvips 5-600
+%%% distribution: new user-accessible macros:
+%%% \epsfclipon, \epsfclipoff, \epsfdrafton,
+%%% \epsfdraftoff, change \empty to \epsfempty.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 18 May 2002 [2.7.1]
+%%% Add write statements to echo input file
+%%% names. Prior to that change, an error in
+%%% such a file could be quite hard to track
+%%% down: a long list of TeX page numbers could
+%%% suddenly be followed by ``TeX buffer
+%%% capacity'' exceeded, without any indication
+%%% of the file that was responsible.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 16 May 2003 [2.7.2]
+%%% Supply two critical percent characters that
+%%% were mistakenly omitted in version 2.7.1,
+%%% and resulted in a small amount of spurious
+%%% horizontal space.
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, 14 Feb 2011 [2.7.3]
+%%% Add previously-missing \space in rwi
+%%% assignments (bug reported 14-Feb-2011 by
+%%% Stefan Rueger <s.rueger@open.ac.uk>).
+%%%
+%%% ---------------------------------------------
+%%% Revised by Nelson H. F. Beebe
+%%% <beebe@math.utah.edu>, Karl Berry
+%%% <karl@freefriends.org>, and Robin Fairbairns
+%%% <Robin.Fairbairns@cl.cam.ac.uk>,
+%%% 23 July 2005 [2.7.3]
+%%% Add critical \hbox{} wrapper in \epsfsetgraph
+%%% so that \epsfbox{} does not conflict with
+%%% LaTeX center environment when \epsfbox{} is
+%%% surrounded by other horizonal objects.
+%%% Improve macro readability by adding legal,
+%%% but invisible-in-typeset-output, spaces.
+%%% Ensure that verbose status reports come
+%%% inside (filename ...) list.
+%%%
+%%% ---------------------------------------------
+%%% The checksum field above contains a CRC-16
+%%% checksum as the first value, followed by
+%%% the equivalent of the standard UNIX wc
+%%% (word count) utility output of lines,
+%%% words, and characters. This is produced by
+%%% Robert Solovay's checksum utility.",
+%%% }
+%%% ====================================================================
+
+%\immediate \write16 {This is `epsf.tex' v2.0 <02 Dec 1991>}%
+%\immediate \write16 {This is `epsf.tex' v2.1 <05 May 1992>}%
+%\immediate \write16 {This is `epsf.tex' v2.2 <09 Dec 1992>}%
+%\immediate \write16 {This is `epsf.tex' v2.3 <14 Dec 1992>}%
+%\immediate \write16 {This is `epsf.tex' v2.4 <20 June 1993>}%
+%\immediate \write16 {This is `epsf.tex' v2.5 <13 July 1993>}%
+%\immediate \write16 {This is `epsf.tex' v2.6 <02 July 1996>}%
+%\immediate \write16 {This is `epsf.tex' v2.7 <25 October 1996>}%
+%\immediate \write16 {This is `epsf.tex' v2.7.1 <18 May 2002>}%
+%\immediate \write16 {This is `epsf.tex' v2.7.2 <16 May 2003>}%
+%\immediate \write16 {This is `epsf.tex' v2.7.3 <23 July 2005>}%
+\immediate \write16 {This is `epsf.tex' v2.7.4 <14 February 2011>}%
+%
+\newread \epsffilein % file to \read
+\newif \ifepsfatend % need to scan to LAST %%BoundingBox comment?
+\newif \ifepsfbbfound % success?
+\newif \ifepsfdraft % use draft mode?
+\newif \ifepsffileok % continue looking for the bounding box?
+\newif \ifepsfframe % frame the bounding box?
+\newif \ifepsfshow % show PostScript file, or just bounding box?
+\epsfshowtrue % default is to display PostScript file
+\newif \ifepsfshowfilename % show the file name if \epsfshowfalse specified?
+\newif \ifepsfverbose % report what you're making?
+\newdimen \epsfframemargin % margin between box and frame
+\newdimen \epsfframethickness % thickness of frame rules
+\newdimen \epsfrsize % vertical size before scaling
+\newdimen \epsftmp % register for arithmetic manipulation
+\newdimen \epsftsize % horizontal size before scaling
+\newdimen \epsfxsize % horizontal size after scaling
+\newdimen \epsfysize % vertical size after scaling
+\newdimen \pspoints % conversion factor
+%
+\pspoints = 1bp % Adobe points are `big'
+\epsfxsize = 0pt % default value, means `use natural size'
+\epsfysize = 0pt % ditto
+\epsfframemargin = 0pt % default value: frame box flush around picture
+\epsfframethickness = 0.4pt % TeX's default rule thickness
+%
+\def \epsfbox #1{%
+ \global \def \epsfllx {72}%
+ \global \def \epsflly {72}%
+ \global \def \epsfurx {540}%
+ \global \def \epsfury {720}%
+ \def \lbracket {[}%
+ \def \testit {#1}%
+ \ifx \testit \lbracket
+ \let \next = \epsfgetlitbb
+ \else
+ \let \next = \epsfnormal
+ \fi
+ \next{#1}%
+}%
+%
+% We use \epsfgetlitbb if the user specified an explicit bounding box,
+% and \epsfnormal otherwise. Because \epsfgetbb can be called
+% separately to retrieve the bounding box, we move the verbose
+% printing the bounding box extents and size on the terminal to
+% \epsfstatus. Therefore, when the user provided the bounding box,
+% \epsfgetbb will not be called, so we must call \epsfsetsize and
+% \epsfstatus ourselves.
+%
+\def \epsfgetlitbb #1#2 #3 #4 #5]#6{%
+ \epsfgrab #2 #3 #4 #5 .\\%
+ \epsfsetsize
+ \epsfstatus{#6}%
+ \epsfsetgraph{#6}%
+}%
+%
+\def \epsfnormal #1{%
+ \epsfgetbb{#1}%
+ \epsfsetgraph{#1}%
+}%
+%
+\def \epsfgetbb #1{%
+%
+% The first thing we need to do is to open the
+% PostScript file, if possible.
+%
+ \openin\epsffilein=#1
+ \immediate \write16 {(#1}%
+ \ifeof \epsffilein
+ \errmessage{Could not open file #1, ignoring it}%
+ \else %process the file
+ {% %start a group to contain catcode changes
+ % Make all special characters, except space, to be of type
+ % `other' so we process the file in almost verbatim mode
+ % (TeXbook, p. 344).
+ \chardef \other = 12%
+ \def \do ##1{\catcode`##1=\other}%
+ \dospecials
+ \catcode `\ = 10%
+ \epsffileoktrue %true while we are looping
+ \epsfatendfalse %[02-Jul-1996]: add forgotten initialization
+ \loop %reading lines from the EPS file
+ \read \epsffilein to \epsffileline
+ \ifeof \epsffilein %then no more input
+ \epsffileokfalse %so set completion flag
+ \else %otherwise process one line
+ \expandafter \epsfaux \epsffileline :. \\%
+ \fi
+ \ifepsffileok
+ \repeat
+ \ifepsfbbfound
+ \else
+ \ifepsfverbose
+ \immediate \write16 {No BoundingBox comment found in %
+ file #1; using defaults}%
+ \fi
+ \fi
+ }% %end catcode changes
+ \closein\epsffilein
+ \fi %end of file processing
+ \epsfsetsize %compute size parameters
+ \epsfstatus{#1}%
+ \immediate \write16 {)}%
+}%
+%
+% Clipping control:
+\def \epsfclipon {\def \epsfclipstring { clip}}%
+\def \epsfclipoff {\def \epsfclipstring {\ifepsfdraft \space clip\fi}}%
+\epsfclipoff % default for dvips is OFF
+%
+% The special that is emitted by \epsfsetgraph comes from this macro.
+% It is defined separately to allow easy customization by other
+% packages that first \input epsf.tex, then redefine \epsfspecial.
+% This macro is invoked in the lower-left corner of a box of the
+% width and height determined from the arguments to \epsffile, or
+% from the %%BoundingBox in the EPS file itself.
+%
+% This version is for dvips:
+\def \epsfspecial #1{%
+ \epsftmp=10\epsfxsize
+ \divide \epsftmp by \pspoints
+ \ifnum \epsfrsize = 0%
+ \relax
+ \special{PSfile=\ifepsfdraft psdraft.ps\else#1\fi\space
+ llx=\epsfllx\space
+ lly=\epsflly\space
+ urx=\epsfurx\space
+ ury=\epsfury\space
+ rwi=\number\epsftmp\space
+ \epsfclipstring
+ }%
+ \else
+ \epsfrsize=10\epsfysize
+ \divide \epsfrsize by \pspoints
+ \special{PSfile=\ifepsfdraft psdraft.ps\else#1\fi\space
+ llx=\epsfllx\space
+ lly=\epsflly\space
+ urx=\epsfurx\space
+ ury=\epsfury\space
+ rwi=\number\epsftmp\space
+ rhi=\number\epsfrsize
+ \epsfclipstring
+ }%
+ \fi
+}%
+%
+% \epsfframe macro adapted from the TeXbook, exercise 21.3, p. 223, 331.
+% but modified to set the box width to the natural width, rather
+% than the line width, and to include space for margins and rules
+\def \epsfframe #1%
+{%
+ % method for detecting latex suggested by Robin Fairbairns, May 2005.
+ \ifx \documentstyle \epsfundefined
+ \relax
+ \else
+% \leavevmode % so we can put this inside
+ % a latex centered environment
+ % The \leavevmode breaks under plain when this is inside a box,
+ % because it forces the figure to be the entire \hsize. On the
+ % other hand, we need the \leavevmode for it to work in LaTeX,
+ % because the {center} environment works by adjusting TeX's
+ % paragraph parameters.
+ %
+ % Compare the LaTeX sequence
+ % \begin{center}
+ % \epsfbox{tip.eps}q
+ % \end{center}
+ % (needs the \leavevmode to put the q right next to the image)
+ %
+ % with the plain TeX sequence:
+ % \leftline{\vbox{\epsfbox{tip.eps}}q}
+ % (had the q all the way over to the right, when \leavevmode was used)
+ \fi
+ %
+ \setbox0 = \hbox{#1}%
+ \dimen0 = \wd0 % natural width of argument
+ \advance \dimen0 by 2\epsfframemargin % plus width of 2 margins
+ \advance \dimen0 by 2\epsfframethickness % plus width of 2 rule lines
+ \relax
+ \hbox{%
+ \vbox
+ {%
+ \hrule height \epsfframethickness depth 0pt
+ \hbox to \dimen0
+ {%
+ \hss
+ \vrule width \epsfframethickness
+ \kern \epsfframemargin
+ \vbox {\kern \epsfframemargin \box0 \kern \epsfframemargin }%
+ \kern \epsfframemargin
+ \vrule width \epsfframethickness
+ \hss
+ }% end hbox
+ \hrule height 0pt depth \epsfframethickness
+ }% end vbox
+ }% end hbox
+ \relax
+}%
+%
+\def \epsfsetgraph #1%
+{%
+ %
+ % Make the vbox and stick in a \special that the DVI driver can
+ % parse. \vfil and \hfil are used to place the \special origin at
+ % the lower-left corner of the vbox. \epsfspecial can be redefined
+ % to produce alternate \special syntaxes.
+ %
+ \ifvmode \leavevmode \fi
+ \relax
+ \hbox{% so we can put this in \begin{center}...\end{center}
+ \ifepsfframe \expandafter \epsfframe \fi
+ {\vbox to\epsfysize
+ {%
+ \ifepsfshow
+ % output \special{} at lower-left corner of figure box
+ \vfil
+ \hbox to \epsfxsize{\epsfspecial{#1}\hfil}%
+ \else
+ \vfil
+ \hbox to\epsfxsize{%
+ \hss
+ \ifepsfshowfilename
+ {%
+ \epsfframemargin=3pt % local change of margin
+ \epsfframe{{\tt #1}}%
+ }%
+ \fi
+ \hss
+ }%
+ \vfil
+ \fi
+ }%
+ }}%
+ \relax
+ %
+ % Reset \epsfxsize and \epsfysize, as documented above.
+ %
+ \global \epsfxsize = 0pt
+ \global \epsfysize = 0pt
+}%
+%
+% Now we have to calculate the scale and offset values to use.
+% First we compute the natural sizes.
+%
+\def \epsfsetsize
+{%
+ \epsfrsize = \epsfury \pspoints
+ \advance \epsfrsize by -\epsflly \pspoints
+ \epsftsize = \epsfurx \pspoints
+ \advance \epsftsize by -\epsfllx \pspoints
+%
+% If `epsfxsize' is 0, we default to the natural size of the picture.
+% Otherwise we scale the graph to be \epsfxsize wide.
+%
+ \epsfxsize = \epsfsize{\epsftsize}{\epsfrsize}%
+ \ifnum \epsfxsize = 0
+ \ifnum \epsfysize = 0
+ \epsfxsize = \epsftsize
+ \epsfysize = \epsfrsize
+ \epsfrsize = 0pt
+%
+% We have a sticky problem here: TeX doesn't do floating point arithmetic!
+% Our goal is to compute y = rx/t. The following loop does this reasonably
+% fast, with an error of at most about 16 sp (about 1/4000 pt).
+%
+ \else
+ \epsftmp = \epsftsize
+ \divide \epsftmp by \epsfrsize
+ \epsfxsize = \epsfysize
+ \multiply \epsfxsize by \epsftmp
+ \multiply \epsftmp by \epsfrsize
+ \advance \epsftsize by -\epsftmp
+ \epsftmp = \epsfysize
+ \loop
+ \advance \epsftsize by \epsftsize
+ \divide \epsftmp by 2
+ \ifnum \epsftmp > 0
+ \ifnum \epsftsize < \epsfrsize
+ \else
+ \advance \epsftsize -\epsfrsize
+ \advance \epsfxsize \epsftmp
+ \fi
+ \repeat
+ \epsfrsize = 0pt
+ \fi
+ \else
+ \ifnum \epsfysize = 0
+ \epsftmp = \epsfrsize
+ \divide \epsftmp by \epsftsize
+ \epsfysize = \epsfxsize
+ \multiply \epsfysize by \epsftmp
+ \multiply \epsftmp by \epsftsize
+ \advance \epsfrsize by -\epsftmp
+ \epsftmp = \epsfxsize
+ \loop
+ \advance \epsfrsize by \epsfrsize
+ \divide \epsftmp by 2
+ \ifnum \epsftmp > 0
+ \ifnum \epsfrsize < \epsftsize
+ \else
+ \advance \epsfrsize by -\epsftsize
+ \advance \epsfysize by \epsftmp
+ \fi
+ \repeat
+ \epsfrsize = 0pt
+ \else
+ \epsfrsize = \epsfysize
+ \fi
+ \fi
+}%
+%
+% Issue some status messages if the user requested them
+%
+\def \epsfstatus #1{% arg = filename
+ \ifepsfverbose
+ \immediate \write16 {#1: BoundingBox:
+ llx = \epsfllx \space lly = \epsflly \space
+ urx = \epsfurx \space ury = \epsfury \space}%
+ \immediate \write16 {#1: scaled width = \the\epsfxsize \space
+ scaled height = \the\epsfysize}%
+ \fi
+}%
+%
+% We still need to define the tricky \epsfaux macro. This requires
+% a couple of magic constants for comparison purposes.
+%
+{\catcode`\%=12 \global \let \epsfpercent=%\global \def \epsfbblit {%BoundingBox}}%
+\global \def \epsfatend{(atend)}%
+%
+% So we're ready to check for `%BoundingBox:' and to grab the
+% values if they are found.
+%
+% If we find a line
+%
+% %%BoundingBox: (atend)
+%
+% then we ignore it, but set a flag to force parsing all of the
+% file, so the last %%BoundingBox parsed will be the one used. This
+% is necessary, because EPS files can themselves contain other EPS
+% files with their own %%BoundingBox comments.
+%
+% If we find a line
+%
+% %%BoundingBox: llx lly urx ury
+%
+% then we save the 4 values in \epsfllx, \epsflly, \epsfurx, \epsfury.
+% Then, if we have not previously parsed an (atend), we flag completion
+% and can stop reading the file. Otherwise, we must keep on reading
+% to end of file so that we find the values on the LAST %%BoundingBox.
+\long \def \epsfaux#1#2:#3\\%
+{%
+ \def \testit {#2}% % save second character up to just before colon
+ \ifx#1\epsfpercent % then first char is percent (quick test)
+ \ifx \testit \epsfbblit % then (slow test) we have %%BoundingBox
+ \epsfgrab #3 . . . \\%
+ \ifx \epsfllx\epsfatend % then ignore %%BoundingBox: (atend)
+ \global \epsfatendtrue
+ \else % else found %%BoundingBox: llx lly urx ury
+ \ifepsfatend % then keep parsing ALL %%BoundingBox lines
+ \else % else stop after first one parsed
+ \epsffileokfalse
+ \fi
+ \global \epsfbbfoundtrue
+ \fi
+ \fi
+ \fi
+}%
+%
+% Here we grab the values and stuff them in the appropriate definitions.
+%
+\def \epsfempty {}%
+\def \epsfgrab #1 #2 #3 #4 #5\\{%
+ \global \def \epsfllx {#1}\ifx \epsfllx\epsfempty
+ \epsfgrab #2 #3 #4 #5 .\\\else
+ \global \def \epsflly {#2}%
+ \global \def \epsfurx {#3}\global \def \epsfury {#4}\fi
+}%
+%
+% We default the epsfsize macro.
+%
+\def \epsfsize #1#2{\epsfxsize}%
+%
+% Finally, another definition for compatibility with older macros.
+%
+\let \epsffile = \epsfbox
+\endinput
diff --git a/doc/it/flusso-elaborazione.eps b/doc/it/flusso-elaborazione.eps
new file mode 100644
index 00000000..c9e4c938
--- /dev/null
+++ b/doc/it/flusso-elaborazione.eps
@@ -0,0 +1,420 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.12.8 (http://cairographics.org)
+%%CreationDate: Wed Dec 17 19:10:08 2014
+%%Pages: 1
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%BoundingBox: 0 -1 366 172
+%%EndComments
+%%BeginProlog
+save
+50 dict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+ 0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+ { globaldict begin /?pdfmark /pop load def /pdfmark
+ /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+ {
+ dup
+ type /stringtype eq
+ { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+ } forall
+ currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+ cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+ { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+ /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+ /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+ cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+11 dict begin
+/FontType 42 def
+/FontName /DejaVuSans def
+/PaintType 0 def
+/FontMatrix [ 1 0 0 1 0 0 ] def
+/FontBBox [ 0 0 0 0 ] def
+/Encoding 256 array def
+0 1 255 { Encoding exch /.notdef put } for
+Encoding 63 /question put
+Encoding 65 /A put
+Encoding 69 /E put
+Encoding 73 /I put
+Encoding 78 /N put
+Encoding 80 /P put
+Encoding 83 /S put
+Encoding 97 /a put
+Encoding 98 /b put
+Encoding 99 /c put
+Encoding 100 /d put
+Encoding 101 /e put
+Encoding 105 /i put
+Encoding 108 /l put
+Encoding 110 /n put
+Encoding 111 /o put
+Encoding 114 /r put
+Encoding 116 /t put
+Encoding 117 /u put
+Encoding 122 /z put
+Encoding 236 /igrave put
+/CharStrings 22 dict dup begin
+/.notdef 0 def
+/I 1 def
+/n 2 def
+/i 3 def
+/z 4 def
+/a 5 def
+/l 6 def
+/o 7 def
+/e 8 def
+/A 9 def
+/c 10 def
+/r 11 def
+/d 12 def
+/t 13 def
+/question 14 def
+/N 15 def
+/S 16 def
+/igrave 17 def
+/E 18 def
+/b 19 def
+/P 20 def
+/u 21 def
+end readonly def
+/sfnts [
+<0001000000090080000300106376742000691d3900000ddc000001fe6670676d7134766a0000
+0fdc000000ab676c7966478ea3590000009c00000d4068656164f79ac5e70000108800000036
+686865610cb80669000010c000000024686d747864c10d12000010e4000000606c6f63610000
+a9f000001144000000646d61787004850671000011a800000020707265703b07f100000011c8
+0000056800020066fe96046605a400030007001a400c04fb0006fb0108057f0204002fc4d4ec
+310010d4ecd4ec301311211125211121660400fc73031bfce5fe96070ef8f2720629000100c9
+0000019305d50003002eb700af02011c00040410fc4bb0105458b9000000403859ec31002fec
+3001400d30054005500560058f059f05065d13331123c9caca05d5fa2b00000100ba00000464
+047b001300364019030900030e0106870e11b80cbc0a010208004e0d09080b461410fcec32f4
+ec31002f3ce4f4c4ec1112173930b46015cf1502015d0111231134262322061511231133153e
+013332160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870460ae6564ef0002
+00c100000179061400030007002b400e06be04b100bc020501080400460810fc3cec3231002f
+e4fcec30400b1009400950096009700905015d1333112311331523c1b8b8b8b80460fba00614
+e90000010058000003db04600009009d401a081102030203110708074208a900bc03a9050803
+01000401060a10dc4bb00b544bb00c545b58b90006ffc038594bb0135458b9000600403859c4
+32c411393931002fecf4ec304b5358071005ed071005ed592201404205021602260247024907
+050b080f0b18031b082b08200b36033908300b400140024503400440054308570359085f0b60
+01600266036004600562087f0b800baf0b1b5d005d1321150121152135012171036afd4c02b4
+fc7d02b4fd650460a8fcdb93a80325000002007bffe3042d047b000a002500bc4027191f0b17
+090e00a91706b90e1120861fba1cb923b8118c170c001703180d09080b1f030814452610fcec
+ccd4ec323211393931002fc4e4f4fcf4ec10c6ee10ee11391139123930406e301d301e301f30
+20302130223f27401d401e401f402040214022501d501e501f50205021502250277027851d87
+1e871f8720872185229027a027f0271e301e301f30203021401e401f40204021501e501f5020
+5021601e601f60206021701e701f70207021801e801f80208021185d015d0122061514163332
+363d01371123350e01232226353436332135342623220607353e0133321602bedfac816f99b9
+b8b83fbc88accbfdfb0102a79760b65465be5af3f00233667b6273d9b4294cfd81aa6661c1a2
+bdc0127f8b2e2eaa2727fc00000100c100000179061400030022b7009702010800460410fcec
+31002fec30400d10054005500560057005f00506015d13331123c1b8b80614f9ec0000020071
+ffe30475047b000b0017004a401306b91200b90cb8128c1809120f51031215451810fcecf4ec
+310010e4f4ec10ee3040233f197b007b067f077f087f097f0a7f0b7b0c7f0d7f0e7f0f7f107f
+117b12a019f01911015d012206151416333236353426273200111000232200111000027394ac
+ab9593acac93f00112feeef0f1feef011103dfe7c9c9e7e8c8c7e99cfec8feecfeedfec70139
+011301140138000000020071ffe3047f047b0014001b00704024001501098608880515a90105
+b90c01bb18b912b80c8c1c1b1502081508004b02120f451c10fcecf4ecc4111239310010e4f4
+ece410ee10ee10f4ee1112393040293f1d701da01dd01df01d053f003f013f023f153f1b052c
+072f082f092c0a6f006f016f026f156f1b095d71015d0115211e0133323637150e0123200011
+1000333200072e0123220607047ffcb20ccdb76ac76263d06bfef4fec70129fce20107b802a5
+889ab90e025e5abec73434ae2a2c0138010a01130143feddc497b4ae9e000002001000000568
+05d50002000a00c2404100110100040504021105050401110a030a0011020003030a07110504
+06110505040911030a08110a030a4200030795010381090509080706040302010009050a0b10
+d4c4173931002f3ce4d4ec1239304b5358071005ed0705ed071005ed0705ed071008ed071005
+ed071005ed071008ed5922b2200c01015d40420f010f020f070f080f005800760070008c0009
+07010802060309041601190256015802500c67016802780176027c0372047707780887018802
+800c980299039604175d005d090121013301230321032302bcfeee0225fe7be50239d288fd5f
+88d5050efd1903aefa2b017ffe81000000010071ffe303e7047b0019003f401b00860188040e
+860d880ab91104b917b8118c1a07120d004814451a10fce432ec310010e4f4ec10fef4ee10f5
+ee30400b0f1b101b801b901ba01b05015d01152e0123220615141633323637150e0123220011
+100021321603e74e9d50b3c6c6b3509d4e4da55dfdfed6012d010655a20435ac2b2be3cdcde3
+2b2baa2424013e010e0112013a230000000100ba0000034a047b001100304014060b0700110b
+03870eb809bc070a06080008461210fcc4ec3231002fe4f4ecc4d4cc11123930b450139f1302
+015d012e012322061511231133153e0133321617034a1f492c9ca7b9b93aba85132e1c03b412
+11cbbefdb20460ae66630505000000020071ffe3045a06140010001c003840191ab9000e14b9
+05088c0eb801970317040008024711120b451d10fcecf4ec323231002fece4f4c4ec10c4ee30
+b6601e801ea01e03015d0111331123350e012322021110003332160114163332363534262322
+0603a2b8b83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b6025ef9eca8646101440108
+0108014461fe15cbe7e7cbcbe7e700010037000002f2059e0013003840190e05080f03a90011
+01bc08870a0b08090204000810120e461410fc3cc4fc3cc432393931002fecf43cc4ec321139
+3930b2af1501015d01112115211114163b01152322263511233533110177017bfe854b73bdbd
+d5a28787059efec28ffda0894e9a9fd202608f013e00000000020093000003b005f000030024
+0065402b241e0906040a1d13040014861388109517910083021d1a0d0905040a1e010d1c1a04
+1c05010300261a132510dc4bb00c5458b90013ffc03859c4fcecd4ec10ee1139391112391112
+3931002feef6fef4ee10cd11393917393001b679097a0a7a20035d2533152313233534363f01
+3e0135342623220607353e013332161514060f010e01070e01150187cbcbc5bf385a5a393383
+6c4fb3615ec167b8df485a582f27080606fefe01919a65825659355e31596e4643bc3938c29f
+4c8956562f3519153c340000000100c90000053305d500090079401e07110102010211060706
+4207020300af0805060107021c0436071c00040a10fcecfcec11393931002f3cec323939304b
+5358071004ed071004ed5922b21f0b01015d4030360238074802470769026607800207060109
+0615011a06460149065701580665016906790685018a0695019a069f0b105d005d1321011133
+1121011123c901100296c4fef0fd6ac405d5fb1f04e1fa2b04e1fb1f00010087ffe304a205f0
+0027007e403c0d0c020e0b021e1f1e080902070a021f1f1e420a0b1e1f0415010015a1149418
+9511049500942591118c281e0a0b1f1b0700221b190e2d071914222810dcc4ecfcece4111239
+393939310010e4f4e4ec10eef6ee10c6111739304b535807100eed11173907100eed11173959
+22b20f2901015db61f292f294f29035d01152e012322061514161f011e011514042122262735
+1e013332363534262f012e01353424333216044873cc5fa5b377a67ae2d7feddfee76aef807b
+ec72adbc879a7be2ca0117f569da05a4c53736807663651f192bd9b6d9e0302fd04546887e6e
+7c1f182dc0abc6e42600ffffffc7000001a6066610270016ff1d0000120600170000000100c9
+0000048b05d5000b002e401506950402950081089504ad0a05010907031c00040c10fcec32d4
+c4c431002fececf4ec10ee30b21f0d01015d132115211121152111211521c903b0fd1a02c7fd
+3902f8fc3e05d5aafe46aafde3aa0000000200baffe304a40614000b001c0038401903b90c0f
+09b918158c0fb81b971900121247180c06081a461d10fcec3232f4ec31002fece4f4c4ec10c6
+ee30b6601e801ea01e03015d013426232206151416333236013e013332001110022322262715
+23113303e5a79292a7a79292a7fd8e3ab17bcc00ffffcc7bb13ab9b9022fcbe7e7cbcbe7e702
+526461febcfef8fef8febc6164a80614000200c90000048d05d500080013003a401801951000
+95098112100a0802040005190d3f11001c09041410fcec32fcec11173931002ff4ecd4ec3040
+0b0f151f153f155f15af1505015d011133323635342623252132041514042b0111230193fe8d
+9a9a8dfe3801c8fb0101fefffbfeca052ffdcf92878692a6e3dbdde2fda8000200aeffe30458
+047b00130014003b401c030900030e0106870e118c0a01bc14b80c0d0908140b4e0208004615
+10fcecf439ec3231002fe4e432f4c4ec1112173930b46f15c01502015d131133111416333236
+3511331123350e0123222601aeb87c7c95adb8b843b175c1c801cf01ba02a6fd619f9fbea402
+7bfba0ac6663f003a800000100aa04f00289066600030031400901b400b3040344010410dcec
+310010f4ec30004bb009544bb00e545b58bd0004ffc000010004000400403811373859090123
+01016f011a99feba0666fe8a0176000200c100000179047b00030004002c400b04b800bf0204
+010800460510fcec3931002fece43040110404340444041006400650066006700608015d1333
+112313c1b8b85c0460fba0047b00013500b800cb00cb00c100aa009c01a600b8006600000071
+00cb00a002b20085007500b800c301cb0189022d00cb00a600f000d300aa008700cb03aa0400
+014a003300cb000000d9050200f4015400b4009c01390114013907060400044e04b4045204b8
+04e704cd0037047304cd04600473013303a2055605a60556053903c5021200c9001f00b801df
+007300ba03e9033303bc0444040e00df03cd03aa00e503aa0404000000cb008f00a4007b00b8
+0014016f007f027b0252008f00c705cd009a009a006f00cb00cd019e01d300f000ba018300d5
+009803040248009e01d500c100cb00f600830354027f00000333026600d300c700a400cd008f
+009a0073040005d5010a00fe022b00a400b4009c00000062009c0000001d032d05d505d505d5
+05f0007f007b005400a406b80614072301d300b800cb00a601c301ec069300a000d3035c0371
+03db0185042304a80448008f0139011401390360008f05d5019a061407230666017904600460
+0460047b009c00000277046001aa00e904600762007b00c5007f027b000000b4025205cd0066
+00bc00660077061000cd013b01850389008f007b0000001d00cd074a042f009c009c0000077d
+006f0000006f0335006a006f007b00ae00b2002d0396008f027b00f600830354063705f6008f
+009c04e10266008f018d02f600cd03440029006604ee00730000140000960000b70706050403
+0201002c2010b002254964b040515820c859212d2cb002254964b040515820c859212d2c2010
+0720b00050b00d7920b8ffff5058041b0559b0051cb0032508b0042523e120b00050b00d7920
+b8ffff5058041b0559b0051cb0032508e12d2c4b505820b0fd454459212d2cb002254560442d
+2c4b5358b00225b0022545445921212d2c45442d2cb00225b0022549b00525b005254960b020
+6368208a108a233a8a10653a2d00000100000002547a3935de785f0f3cf5001f080000000000
+c990133600000000c9901336f7d6fcae0d72095500000008000000010000000000010000076d
+fe1d00000de2f7d6fa510d7200010000000000000000000000000000001804cd0066025c00c9
+051200ba023900c10433005804e7007b023900c104e5007104ec00710579001004660071034a
+00ba0514007103230037043f009305fc00c9051400870239ffc7050e00c9051400ba04d300c9
+051200ae040000aa023900c100000000000000440000008c0000010400000154000002200000
+034c000003880000042c00000500000005fc00000694000007040000079c00000818000008f0
+0000099800000a9000000aa800000b0800000ba000000c2000000ca400000cf400000d400001
+000000180354002b0068000c000200100099000800000415021600080004b8028040fffbfe03
+fa1403f92503f83203f79603f60e03f5fe03f4fe03f32503f20e03f19603f02503ef8a4105ef
+fe03ee9603ed9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5e45305e59603e48a
+4105e45303e3e22f05e3fa03e22f03e1fe03e0fe03df3203de1403dd9603dcfe03db1203da7d
+03d9bb03d8fe03d68a4105d67d03d5d44705d57d03d44703d3d21b05d3fe03d21b03d1fe03d0
+fe03cffe03cefe03cd9603cccb1e05ccfe03cb1e03ca3203c9fe03c6851105c61c03c51603c4
+fe03c3fe03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe03ba1103b9862505b9fe
+03b8b7bb05b8fe03b7b65d05b7bb03b78004b6b52505b65d40ff03b64004b52503b4fe03b396
+03b2fe03b1fe03b0fe03affe03ae6403ad0e03acab2505ac6403abaa1205ab2503aa1203a98a
+4105a9fa03a8fe03a7fe03a6fe03a51203a4fe03a3a20e05a33203a20e03a16403a08a4105a0
+96039ffe039e9d0c059efe039d0c039c9b19059c64039b9a10059b19039a1003990a0398fe03
+97960d0597fe03960d03958a410595960394930e05942803930e0392fa039190bb0591fe0390
+8f5d0590bb039080048f8e25058f5d038f40048e25038dfe038c8b2e058cfe038b2e038a8625
+058a410389880b05891403880b03878625058764038685110586250385110384fe0383821105
+83fe0382110381fe0380fe037ffe0340ff7e7d7d057efe037d7d037c64037b5415057b25037a
+fe0379fe03780e03770c03760a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036efe03
+6c21036bfe036a1142056a530369fe03687d036711420566fe0365fe0364fe0363fe0362fe03
+613a0360fa035e0c035dfe035bfe035afe0359580a0559fa03580a035716190557320356fe03
+5554150555420354150353011005531803521403514a130551fe03500b034ffe034e4d10054e
+fe034d10034cfe034b4a13054bfe034a4910054a1303491d0d05491003480d0347fe03469603
+45960344fe0343022d0543fa0342bb03414b0340fe033ffe033e3d12053e14033d3c0f053d12
+033c3b0d053c40ff0f033b0d033afe0339fe033837140538fa033736100537140336350b0536
+1003350b03341e03330d0332310b0532fe03310b03302f0b05300d032f0b032e2d09052e1003
+2d09032c32032b2a25052b64032a2912052a25032912032827250528410327250326250b0526
+0f03250b0324fe0323fe03220f03210110052112032064031ffa031e1d0d051e64031d0d031c
+1142051cfe031bfa031a42031911420519fe031864031716190517fe031601100516190315fe
+0314fe0313fe031211420512fe0311022d05114203107d030f64030efe030d0c16050dfe030c
+0110050c16030bfe030a100309fe0308022d0508fe030714030664030401100504fe03401503
+022d0503fe0302011005022d0301100300fe0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b002b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
+2b2b2b2b2b2b2b1d00>
+] def
+/f-0-0 currentdict end definefont pop
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 -1 366 172
+%%EndPageSetup
+q 0 -1 366 173 rectclip q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 141.949 130.645 m 182.324 90.27 l 222.703 130.645 l 182.324 171.023 l 141.949
+ 130.645 l S
+Q q
+0 171.344 366 -172 re W n
+-0.5 172.531 m -0.5 -1.469 l 366.5 -1.469 l 366.5 172.531 l -0.5 172.531
+ l 130.297 127.812 m 139.809 127.812 l 139.809 131.59 l 130.297 131.59 l
+ 137.855 129.703 l 130.297 127.812 l W n
+q
+0 171.344 366 -172 re W n
+[ 1 0 0 1 0 -0.65625 ] concat
+ q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 87.84 130.359 m 138.863 130.359 l S
+ Q
+Q
+Q q
+0 g
+130.297 127.812 m 137.855 129.703 l 130.297 131.59 l 130.297 127.812 l f*
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 130.297 127.812 m 137.855 129.703 l 130.297 131.59 l 130.297 127.812 l S
+Q q
+0 171.344 366 -172 re W n
+-0.5 172.531 m -0.5 -1.469 l 366.5 -1.469 l 366.5 172.531 l -0.5 172.531
+ l 269.188 127.812 m 278.699 127.812 l 278.699 131.59 l 269.188 131.59 l
+ 276.746 129.703 l 269.188 127.812 l W n
+q
+0 171.344 366 -172 re W n
+[ 1 0 0 1 0 -0.65625 ] concat
+ q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 226.734 130.359 m 277.754 130.359 l S
+ Q
+Q
+Q q
+0 g
+269.188 127.812 m 276.746 129.703 l 269.188 131.59 l 269.188 127.812 l f*
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 269.188 127.812 m 276.746 129.703 l 269.188 131.59 l 269.188 127.812 l S
+4.945 149.543 m 2.336 149.543 0.223 147.43 0.223 144.82 c 0.223 114.145
+ l 0.223 111.535 2.336 109.418 4.945 109.418 c 79.969 109.418 l 82.574 109.418
+ 84.691 111.535 84.691 114.145 c 84.691 144.82 l 84.691 147.43 82.574 149.543
+ 79.969 149.543 c 4.945 149.543 l S
+285.312 149.543 m 282.703 149.543 280.59 147.43 280.59 144.82 c 280.59
+113.891 l 280.59 111.281 282.703 109.168 285.312 109.168 c 360.84 109.168
+ l 363.449 109.168 365.562 111.281 365.562 113.891 c 365.562 144.82 l 365.562
+ 147.43 363.449 149.543 360.84 149.543 c 285.312 149.543 l S
+Q q
+0 152.344 366 -132 re W n
+-95.199 152.273 m -95.199 20.82 l 457.016 20.82 l 457.016 152.273 l -95.199
+ 152.273 l 179.891 55.719 m 179.891 48.535 l 185.578 48.535 l 185.578 55.719
+ l 182.734 50.012 l 179.891 55.719 l W n
+q
+0 152.344 366 -132 re W n
+[ 1 0 0 1 0 -0.65625 ] concat
+ q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 182.734 88.453 m 182.734 49.906 l S
+ Q
+Q
+Q q
+21 171.344 293 -168 re W n
+21.961 170.488 m 21.961 3.996 l 313.367 3.996 l 313.367 170.488 l 21.961
+ 170.488 l 109.363 118.598 m 109.363 127.699 l 106.359 127.699 l 106.359
+ 118.598 l 107.859 125.832 l 109.363 118.598 l W n
+q
+21 171.344 293 -168 re W n
+[ 1 0 0 1 0 -0.65625 ] concat
+ q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 139.371 21.672 m 107.859 21.672 l 107.859 127.453 l S
+ Q
+Q
+Q q
+0 g
+109.57 118.301 m 107.684 125.859 l 105.793 118.301 l 109.57 118.301 l f*
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 109.57 118.301 m 107.684 125.859 l 105.793 118.301 l 109.57 118.301 l S
+BT
+10 0 0 10 4.1806 125.86455 Tm
+/f-0-0 1 Tf
+[(I)3(n)9(i)-14(z)-17(i)-13(a)-13(l)-13(i)-14(z)-17(z)-17(a)-12(z)-17(i)
+-14(o)-13(n)9(e)]TJ
+15.95277 1.22084 Td
+[(A)17(n)9(c)8(o)-13(r)-5(a)]TJ
+0.75418 -1.2125 Td
+[(d)10(a)-12(t)17(i)]TJ
+0.80832 -1.25 Td
+(?)Tj
+5.1 2.25 Td
+[(No)]TJ
+-3.89166 -6.45 Td
+[(S)10(\354)]TJ
+-4.27084 -5.57084 Td
+[(E)7(l)-14(a)-12(b)10(o)-14(r)-5(a)-12(z)-17(i)-14(o)-13(n)9(e)]TJ
+15.2625 11.0125 Td
+[(P)20(u)8(l)-13(i)-14(z)-17(i)-14(a)]TJ
+ET
+4.945 149.543 m 2.336 149.543 0.223 147.43 0.223 144.82 c 0.223 114.145
+ l 0.223 111.535 2.336 109.418 4.945 109.418 c 79.969 109.418 l 82.574 109.418
+ 84.691 111.535 84.691 114.145 c 84.691 144.82 l 84.691 147.43 82.574 149.543
+ 79.969 149.543 c 4.945 149.543 l S
+144.965 39.297 m 142.352 39.297 140.234 37.238 140.234 34.699 c 140.234
+ 4.848 l 140.234 2.309 142.352 0.25 144.965 0.25 c 220.035 0.25 l 222.648
+ 0.25 224.766 2.309 224.766 4.848 c 224.766 34.699 l 224.766 37.238 222.648
+ 39.297 220.035 39.297 c 144.965 39.297 l S
+180.824 49.602 m 182.715 42.043 l 184.605 49.602 l 180.824 49.602 l f*
+Q Q
+showpage
+%%Trailer
+end restore
+%%EOF
diff --git a/doc/it/flusso-elaborazione.fig b/doc/it/flusso-elaborazione.fig
new file mode 100644
index 00000000..50c9a209
--- /dev/null
+++ b/doc/it/flusso-elaborazione.fig
@@ -0,0 +1,37 @@
+#FIG 3.2 Produced by xfig version 3.2.5c
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+2 3 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4819 3540 5460 4181 6101 3540 5460 2899 4819 3540
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 3960 3555 4770 3555
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 6165 3555 6975 3555
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 5 0 0 5
+ 7020 3240 7020 3881 8369 3881 8369 3240 7020 3240
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 5490 4230 5490 5040
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 4905 5355 4275 5355 4275 3600
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3915 3870 3915 3330 1935 3330 1935 3870 3915 3870
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6345 5670 6345 4995 4950 4995 4950 5670 6345 5670
+4 0 0 50 -1 0 12 0.0000 4 135 450 5265 3885 ?\001
+4 0 0 50 -1 0 12 0.0000 4 135 180 6210 3465 No\001
+4 0 0 50 -1 0 12 0.0000 4 135 540 5265 3375 Ancora\001
+4 0 0 50 -1 0 12 0.0000 4 135 360 5265 3630 dati\001
+4 0 0 50 -1 0 12 0.0000 4 135 630 7290 3600 Pulizia\001
+4 0 0 50 -1 0 12 0.0000 4 135 1080 5130 5400 Elaborazione\001
+4 0 0 50 -1 0 12 0.0000 4 135 1440 2205 3645 Inizializzazione\001
+4 0 0 50 -1 0 12 0.0000 4 135 270 5535 4455 Si'\001
diff --git a/doc/it/flusso-elaborazione.pdf b/doc/it/flusso-elaborazione.pdf
new file mode 100644
index 00000000..e7fb8555
--- /dev/null
+++ b/doc/it/flusso-elaborazione.pdf
Binary files differ
diff --git a/doc/it/flusso-elaborazione.png b/doc/it/flusso-elaborazione.png
new file mode 100644
index 00000000..4dc95902
--- /dev/null
+++ b/doc/it/flusso-elaborazione.png
Binary files differ
diff --git a/doc/it/flusso-elaborazione.txt b/doc/it/flusso-elaborazione.txt
new file mode 100644
index 00000000..87a5b439
--- /dev/null
+++ b/doc/it/flusso-elaborazione.txt
@@ -0,0 +1,11 @@
+ _______
++------------------+ / Ancora\ No +---------+
+| Inizializzazione | -------> < dati > -------> | Pulizia |
++------------------+ ^ \ ? / +---------+
+ | +--+--+
+ | | Sì
+ | |
+ | V
+ | +--------------+
+ +--+ Elaborazione |
+ +--------------+
diff --git a/doc/it/gawktexi.in b/doc/it/gawktexi.in
new file mode 100644
index 00000000..678125e7
--- /dev/null
+++ b/doc/it/gawktexi.in
@@ -0,0 +1,45878 @@
+\language=30
+\input texinfo @c -*-texinfo-*-
+@c vim: filetype=texinfo
+@c %**start of header (This is for running Texinfo on a region.)
+@setfilename gawk-it.info
+@settitle Guida Utente di GNU Awk
+@documentlanguage it
+@c %**end of header (This is for running Texinfo on a region.)
+
+@dircategory Creazione e manipolazione di testi
+@direntry
+* Gawk: (gawk). Un linguaggio per scandire ed elaborare testi.
+@end direntry
+@dircategory Programmi di utilit@`a individuale
+@direntry
+* awk: (gawk)Avviare gawk. Scansione e processo di testi.
+@end direntry
+
+@c Enable better indexing, requires texindex from Texinfo 6 or later.
+@tex
+\global\usebracesinindexestrue
+@end tex
+
+@ifset FOR_PRINT
+@tex
+\gdef\xrefprintnodename#1{``#1''}
+@end tex
+@end ifset
+
+@ifclear FOR_PRINT
+@c With early 2014 texinfo.tex, restore PDF links and colors
+@tex
+\gdef\linkcolor{0.5 0.09 0.12} % Dark Red
+\gdef\urlcolor{0.5 0.09 0.12} % Also
+\global\urefurlonlylinktrue
+@end tex
+@end ifclear
+
+@ifnotdocbook
+@set BULLET @bullet{}
+@set MINUS @minus{}
+@end ifnotdocbook
+
+@ifdocbook
+@set BULLET
+@set MINUS
+@end ifdocbook
+
+@set xref-automatic-section-title
+
+@c The following information should be updated here only!
+@c This sets the edition of the document, the version of gawk it
+@c applies to and all the info about who's publishing this edition
+
+@c These apply across the board.
+@c Aggiornata alla versione del 3 marzo 2017
+@set UPDATE-MONTH gennaio 2017
+@set VERSION 4.1
+@set PATCHLEVEL 4
+
+@c added Italian hyphenation stuff
+@hyphenation{ven-go-no o-met-te-re o-met-ten-do}
+
+@set GAWKINETTITLE TCP/IP Internetworking with @command{gawk}
+@ifset FOR_PRINT
+@set TITLE Programmare efficacemente in awk
+@end ifset
+@ifclear FOR_PRINT
+@set TITLE GAWK: Programmare efficacemente in AWK
+@end ifclear
+@set SUBTITLE Una Guida Utente per GNU Awk
+@set EDITION 4.1
+
+@iftex
+@set DOCUMENT libro
+@set CHAPTER capitolo
+@set APPENDIX appendice
+@set SECTION sezione
+@set SECTIONS sezioni
+@set SUBSECTION sottosezione
+@ifclear SMALLPRINT
+@set DARKCORNER @inmargin{@image{lflashlight,1cm}, @image{rflashlight,1cm}}
+@end ifclear
+@ifset SMALLPRINT
+@set DARKCORNER @inmargin{@image{lflashlight,0.7cm}, @image{rflashlight,0.7cm}}
+@end ifset
+@set COMMONEXT (e.c.)
+@set PAGE pagina
+@end iftex
+@ifinfo
+@set DOCUMENT File Info
+@set CHAPTER nodo principale
+@set APPENDIX nodo principale
+@set SECTION nodo secondario
+@set SECTIONS nodi secondari
+@set SUBSECTION nodo
+@set DARKCORNER (a.b.)
+@set COMMONEXT (e.c.)
+@set PAGE videata
+@end ifinfo
+@ifhtml
+@set DOCUMENT Documento
+@set CHAPTER capitolo
+@set APPENDIX appendice
+@set SECTION sezione
+@set SECTIONS sezioni
+@set SUBSECTION sottosezione
+@set DARKCORNER (a.b.)
+@set COMMONEXT (e.c.)
+@set PAGE videata
+@end ifhtml
+@ifdocbook
+@set DOCUMENT libro
+@set CHAPTER capitolo
+@set APPENDIX appendice
+@set SECTION sezione
+@set SECTIONS sezioni
+@set SUBSECTION sottosezione
+@set DARKCORNER (a.b.)
+@set COMMONEXT (e.c.)
+@set PAGE pagina
+@end ifdocbook
+@ifxml
+@set DOCUMENT libro
+@set CHAPTER capitolo
+@set APPENDIX appendice
+@set SECTION sezione
+@set SECTIONS sezioni
+@set SUBSECTION sottosezione
+@set DARKCORNER (a.b.)
+@set COMMONEXT (e.c.)
+@set PAGE pagina
+@end ifxml
+@ifplaintext
+@set DOCUMENT libro
+@set CHAPTER capitolo
+@set APPENDIX appendice
+@set SECTION sezione
+@set SECTIONS sezioni
+@set SUBSECTION sottosezione
+@set DARKCORNER (a.b.)
+@set COMMONEXT (e.c.)
+@set PAGE pagina
+@end ifplaintext
+
+@ifdocbook
+@c empty on purpose
+@set PART1
+@set PART2
+@set PART3
+@set PART4
+@end ifdocbook
+
+@ifnotdocbook
+@set PART1 Parte I:@*
+@set PART2 Parte II:@*
+@set PART3 Parte III:@*
+@set PART4 Parte IV:@*
+@end ifnotdocbook
+
+@c some special symbols
+@iftex
+@set LEQ @math{@leq}
+@set PI @math{@pi}
+@end iftex
+@ifdocbook
+@set LEQ @inlineraw{docbook, &le;}
+@set PI @inlineraw{docbook, &pgr;}
+@end ifdocbook
+@ifnottex
+@ifnotdocbook
+@set LEQ <=
+@set PI @i{pi}
+@end ifnotdocbook
+@end ifnottex
+
+@ifnottex
+@ifnotdocbook
+@macro ii{text}
+@i{\text\}
+@end macro
+@end ifnotdocbook
+@end ifnottex
+
+@ifdocbook
+@macro ii{text}
+@inlineraw{docbook,<lineannotation>\text\</lineannotation>}
+@end macro
+@end ifdocbook
+
+@ifclear FOR_PRINT
+@set FN nome-file
+@set FFN Nome-file
+@c for Italian plurals {FN}s
+@set FNS nomi-file
+@set FFNS Nomi-file
+@set DF file-dati
+@set DDF File-dati
+@set PVERSION versione
+@end ifclear
+@ifset FOR_PRINT
+@set FN nome-file
+@set FFN Nome-File
+@c for Italian plurals {FN}s
+@set FNS nomi-file
+@set FFNS Nomi-file
+@set DF file-dati
+@set DDF File-dati
+@set PVERSION Versione
+@end ifset
+
+@c For HTML, spell out email addresses, to avoid problems with
+@c address harvesters for spammers.
+@ifhtml
+@macro EMAIL{real,spelled}
+``\spelled\''
+@end macro
+@end ifhtml
+@ifnothtml
+@macro EMAIL{real,spelled}
+@email{\real\}
+@end macro
+@end ifnothtml
+
+@c Indexing macros
+@ifinfo
+
+@macro cindexawkfunc{name}
+@cindex @code{\name\}
+@end macro
+
+@macro cindexgawkfunc{name}
+@cindex @code{\name\}
+@end macro
+
+@end ifinfo
+
+@ifnotinfo
+
+@macro cindexawkfunc{name}
+@cindex @code{\name\()}, funzione
+@end macro
+
+@macro cindexgawkfunc{name}
+@cindex @code{\name\()}, funzione (@command{gawk})
+@end macro
+@end ifnotinfo
+
+@ignore
+Some comments on the layout for TeX.
+1. Use at least texinfo.tex 2016-02-05.07.
+@end ignore
+
+@c merge the function and variable indexes into the concept index
+@ifinfo
+@synindex fn cp
+@synindex vr cp
+@end ifinfo
+@iftex
+@syncodeindex fn cp
+@syncodeindex vr cp
+@end iftex
+@ifxml
+@syncodeindex fn cp
+@syncodeindex vr cp
+@end ifxml
+@ifdocbook
+@synindex fn cp
+@synindex vr cp
+@end ifdocbook
+
+@c If "finalout" is commented out, the printed output will show
+@c black boxes that mark lines that are too long. Thus, it is
+@c unwise to comment it out when running a master in case there are
+@c overfulls which are deemed okay.
+
+@iftex
+@finalout
+@end iftex
+
+@copying
+@docbook
+<para>
+&ldquo;To boldly go where no man has gone before&rdquo;
+(&ldquo;Per arrivare l@`a dove nessun uomo @`e mai giunto prima&rdquo;)
+@`e un Marchio Registrato della Paramount Pictures Corporation.</para>
+
+<para>Titolo originale:</para>
+@b{Gawk: Effective AWK Programming}@*
+@i{A User's Guide for GNU Awk}
+
+<para>Published by:</para>
+<literallayout class="normal">Free Software Foundation
+51 Franklin Street, Fifth Floor -- Boston, MA 02110-1301 USA
+Tel.: +1-617-542-5942 Fax: +1-617-542-2652 Email: <email>gnu@@gnu.org</email>
+URL: <ulink url="http://www.gnu.org">http://www.gnu.org/</ulink></literallayout>
+
+<literallayout class="normal">Copyright &copy; 1989, 1991, 1992, 1993, 1996&ndash;2005, 2007, 2009&ndash;2017
+Free Software Foundation, Inc.
+All Rights Reserved.
+</literallayout>
+
+</para>Traduzione e revisione:<para>
+<literallayout class="normal">
+Antonio Giovanni Colombo -- <email>azc100(chiocciola)gmail(punto)com</email>
+Marco Curreli -- <email>marcocurreli(chiocciola)tiscali(punto)it</email>
+(Italian Linux Documentation Project (<ulink url="http://www.pluto.it/ildp">http://www.pluto.it/ildp/</ulink>)
+</literallayout>
+
+<para>Pubblicato da:</para>
+<literallayout class="normal">Free Software Foundation
+Email: <email>gnu@@gnu.org</email>
+URL: <ulink url="http://www.gnu.org">http://www.gnu.org/</ulink>
+
+e da:
+Italian Linux Documentation Project (ILDP)
+Email: <emailildp@@pluto.it
+URL: <ulink url="http://www.pluto.it/ildp">http://www.pluto.it/ildp/</ulink></literallayout>
+
+<literallayout class="normal">Copyright &copy; 2016
+Free Software Foundation, Inc.
+All Rights Reserved.
+</literallayout>
+@end docbook
+
+@ifnotdocbook
+@iftex
+Copyright @copyright{} 2017 -- Free Software Foundation, Inc.
+@end iftex
+@end ifnotdocbook
+@sp 2
+Questa @`e l'Edizione @value{EDITION} di @cite{@value{TITLE}: @value{SUBTITLE}},
+per la versione @value{VERSION}.@value{PATCHLEVEL} (o successiva)
+dell'implementazione GNU di AWK.
+@ifnottex
+@ifnotxml
+@ifnotdocbook
+(Titolo originale: @i{Gawk: Effective AWK Programming: A User's Guide for GNU Awk.)}
+@end ifnotdocbook
+@end ifnotxml
+@end ifnottex
+
+@`E garantito il permesso di copiare, distribuire e/o modificare questo
+documento seguendo i termini della Licenza per Documentazione Libera
+GNU, Versione 1.3 o ogni versione successiva pubblicata dalla Free
+Software Foundation; con le Sezioni Non Modificabili ``GNU General
+Public License'', con i testi di copertina ``Un Manuale GNU'', e con i
+testi di quarta di copertina come in (a) pi@`u avanti.
+@ifclear FOR_PRINT
+Una copia della licenza @`e acclusa nella sezione intitolata
+"Licenza per Documentazione Libera GNU".
+@end ifclear
+@ifset FOR_PRINT
+Una copia della licenza
+si pu@`o trovare in internet all'indirizzo
+@uref{http://www.gnu.org/software/gawk/manual/html_node/GNU-Free-Documentation-License.html,
+il sito web del Progetto GNU}.
+@end ifset
+
+@enumerate a
+@item
+Il testo di quarta di copertina della FSF @`e: ``@`E garantito il permesso di
+copiare e modificare questo manuale GNU.''
+@end enumerate
+@end copying
+
+@c Comment out the "smallbook" for technical review. Saves
+@c considerable paper. Remember to turn it back on *before*
+@c starting the page-breaking work.
+
+@c 4/2002: Karl Berry recommends commenting out this and the
+@c `@setchapternewpage odd', and letting users use `texi2dvi -t'
+@c if they want to waste paper.
+@c @smallbook
+
+
+@c Uncomment this for the release. Leaving it off saves paper
+@c during editing and review.
+@setchapternewpage odd
+
+@shorttitlepage GNU Awk
+@titlepage
+@title @value{TITLE}
+@subtitle @value{SUBTITLE}
+@subtitle Edizione @value{EDITION}
+@subtitle @value{UPDATE-MONTH}
+@author Arnold D. Robbins
+
+@ifnotdocbook
+@c Include the Distribution inside the titlepage environment so
+@c that headings are turned off. Headings on and off do not work.
+
+@page
+@vskip 0pt plus 1filll
+``To boldly go where no man has gone before''
+(``Per arrivare l@`a dove nessun uomo @`e mai giunto prima'')
+@`e un Marchio Registrato della Paramount Pictures Corporation. @*
+@c sorry, i couldn't resist
+@sp 1
+Titolo originale:@*
+@b{Gawk: Effective AWK Programming}@*
+@i{A User's Guide for GNU Awk}
+@sp 0
+Published by @strong{Free Software Foundation}@*
+51 Franklin Street, Fifth Floor -- Boston, MA 02110-1301 USA @*
+Tel.: +1-617-542-5942 -- Fax: +1-617-542-2652 -- Email: @email{gnu@@gnu.org} @*
+URL: @uref{http://www.gnu.org/}
+@sp 0
+@c This one is correct for gawk 3.1.0 from the FSF
+ISBN 1-882114-28-0
+@sp 0
+Copyright @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2017 @*
+Free Software Foundation, Inc.
+@sp 1
+Traduzione e revisione:@*
+Antonio Giovanni Colombo -- @email{azc100(chiocciola)gmail(punto)com}@*
+Marco Curreli -- @email{marcocurreli(chiocciola)tiscali(punto)it}@*
+(Italian Linux Documentation Project -- @uref{http://www.pluto.it/ildp})
+@sp 1
+Pubblicato da:
+Free Software Foundation@*
+Email: @email{gnu@@gnu.org}; URL: @uref{http://www.gnu.org/}
+
+e da:
+Italian Linux Documentation Project (ILDP)@*
+Email: @email{ildp@@pluto.it}; URL: @uref{http://www.pluto.it/ildp}
+
+@insertcopying
+@sp 1
+@end ifnotdocbook
+@end titlepage
+
+@c Thanks to Bob Chassell for directions on doing dedications.
+@iftex
+@headings off
+@page
+@w{ }
+@sp 9
+
+@ifclear SMALLPRINT
+@center @i{Ai miei genitori, per il loro amore, e per lo splendido esempio che mi hanno dato.}
+@sp 1
+@center @i{A mia moglie, Miriam, per avermi reso completo.
+Grazie per aver costruito la tua vita insieme a me.}
+@sp 1
+@center @i{Ai nostri figli, Chana, Rivka, Nachum e Malka, per aver arricchito le nostre vite in misura incalcolabile.}
+@end ifclear
+
+@ifset SMALLPRINT
+@center @i{Ai miei genitori, per il loro amore,}
+@center @i{ e per lo splendido esempio che mi hanno dato.}
+@sp 1
+@center @i{A mia moglie, Miriam, per avermi reso completo.} @*
+@center @i{ Grazie per aver costruito la tua vita insieme a me.}
+@sp 1
+@center @i{Ai nostri figli, Chana, Rivka, Nachum e Malka,}
+@center @i{per aver arricchito le nostre vite in misura incalcolabile.}
+@end ifset
+
+@sp 1
+@w{ }
+@page
+@w{ }
+@page
+@headings on
+@end iftex
+
+@docbook
+<dedication>
+<para>Ai miei genitori, per il loro amore, e per lo splendido
+esempio che mi hanno dato.</para>
+<para>A mia moglie Miriam, per avermi reso completo.
+Grazie per aver costruito la tua vita insieme con me.</para>
+<para>Ai nostri figli Chana, Rivka, Nachum e Malka,
+per aver arricchito le nostre vite in misura incalcolabile.</para>
+</dedication>
+@end docbook
+
+@iftex
+@headings off
+@evenheading @thispage@ @ @ @strong{@value{TITLE}} @| @|
+@oddheading @| @| @strong{@thischapter}@ @ @ @thispage
+@end iftex
+
+@ifnottex
+@ifnotxml
+@ifnotdocbook
+@node Top
+@top Introduzione Generale
+@c Preface node should come right after the Top
+@c node, in `unnumbered' sections, then the chapter, `What is gawk'.
+@c Licensing nodes are appendices, they're not central to AWK.
+
+Questo file documenta @command{awk}, un programma che si pu@`o usare per
+selezionare dei record determinati in un file ed eseguire azioni su di essi.
+
+@noindent
+Copyright dell'edizione originale @copyright{} 1989, 1991, 1992, 1993, 1996--2005, 2007, 2009--2017 @*
+Free Software Foundation, Inc.
+
+@noindent
+Copyright dell'edizione italiana @copyright{} 2016 -- Free Software Foundation, Inc.
+
+
+@insertcopying
+
+@end ifnotdocbook
+@end ifnotxml
+@end ifnottex
+
+@menu
+* Introduzione3:: Alcune parole gentili riguardo a questo
+ @value{DOCUMENT}.
+* Introduzione4:: Ulteriori parole gentili.
+* Prefazione:: Di cosa tratta questo @value{DOCUMENT};
+ breve storia e ringraziamenti.
+* Per iniziare:: Un'introduzione elementare all'uso di
+ @command{awk}. Come eseguire un programma
+ @command{awk}. Sintassi della riga di
+ comando.
+* Invocare Gawk:: Come eseguire @command{gawk}.
+* Espressioni regolari:: Tutto quel che c'@`e da sapere
+ sull'individuazione di stringhe tramite
+ espressioni regolari.
+* Leggere file:: Come leggere file e manipolare campi.
+* Stampare:: Come stampare usando @command{awk}.
+ Descrizione delle istruzioni @code{print} e
+ @code{printf}. @`E descritta inoltre la
+ ridirezione dell'output.
+* Espressioni:: Le espressioni sono i componenti elementari
+ delle istruzioni.
+* Criteri di ricerca e azioni:: Panoramica sui criteri di ricerca e sulle
+ azioni.
+* Vettori:: La descrizione e l'uso dei vettori. Sono
+ inoltre descritte le istruzioni di controllo
+ relative ai vettori.
+* Funzioni:: Funzioni predefinite e definite dall'utente.
+* Funzioni di libreria:: Una libreria di funzioni di @command{awk}.
+* Programmi di esempio:: Molti programmi @command{awk} con
+ spiegazioni dettagliate.
+* Funzionalit@`a avanzate:: Roba per utenti sofisticati, propria di
+ @command{gawk}.
+* Internazionalizzazione:: Come far s@`{@dotless{i}} che @command{gawk} parli la
+ vostra lingua.
+* Debugger:: Il debugger di @command{gawk}.
+* Calcolo con precisione arbitraria:: Calcolo con precisione arbitraria in
+ @command{gawk}.
+* Estensioni dinamiche:: Aggiungere nuove funzioni predefinite di
+ @command{gawk}.
+* Storia del linguaggio:: L'evoluzione del linguaggio @command{awk}.
+* Installazione:: Installare @command{gawk} in vari sistemi
+ operativi.
+* Note:: Note riguardo ad aggiunte a @command{gawk}
+ e possibili futuri sviluppi.
+* Concetti fondamentali:: Velocissima introduzione alla
+ programmazione.
+* Glossario:: Spiegazione di alcuni termini poco
+ familiari.
+* Copia:: Il vostro diritto a copiare e distribuire
+ @command{gawk}.
+* Licenza per Documentazione Libera GNU (FDL):: La licenza per questo
+ @value{DOCUMENT}.
+* Indice analitico:: Indice dei concetti e delle variabili.
+
+@detailmenu
+* Storia:: La storia di @command{gawk} e
+ @command{awk}.
+* Nomi:: Che nome usare per trovare
+ @command{awk}.
+* Questo manuale:: Uso di questo @value{DOCUMENT}.
+ Comprende esempi di file in input
+ utilizzabili.
+* Convenzioni:: Convenzioni tipografiche.
+* Storia del manuale:: Breve storia del progetto GNU e di
+ questo @value{DOCUMENT}.
+* Come contribuire:: Un aiuto per la salvezza del mondo.
+* Ringraziamenti:: Ringraziamenti.
+* Eseguire gawk:: Come eseguire programmi
+ @command{gawk}; comprende la sintassi
+ della riga di comando.
+* Monouso:: Eseguire un breve programma
+ @command{awk} di tipo usa-e-getta.
+* Leggere dal terminale:: Senza uso di file in input (input
+ immesso da tastiera).
+* Lunghi:: Mettere programmi @command{awk}
+ permanenti in file.
+* @dfn{Script} eseguibili:: Preparare programmi @command{awk}
+ da eseguire come @dfn{script}.
+* Commenti:: Aggiungere documentazione a programmi
+ @command{gawk}.
+* Protezione:: Ulteriore discussione di problemi
+ connessi alle protezioni nella shell.
+* Doppi apici in DOS:: Doppi apici in file .BAT Windows
+* File dati di esempio:: File di dati di esempio da usare nei
+ programmi @command{awk} illustrati in
+ questo @value{DOCUMENT}.
+* Molto semplice:: Un esempio molto semplice.
+* Due regole:: Un esempio meno semplice di programma
+ di una riga, che usa due regole.
+* Maggiore sofisticazione:: Un esempio pi@`u complesso.
+* Istruzioni/Righe:: Suddividere o riunire istruzioni
+ su [una o pi@`u] righe.
+* Altre funzionalit@`a:: Altre funzionalit@`a di @command{awk}.
+* Quando:: Quando usare @command{gawk} e quando
+ usare altre cose.
+* Sommario dell'introduzione:: Sommario dell'introduzione.
+* Riga di comando:: Come eseguire @command{awk}.
+* Opzioni:: Opzioni sulla riga di comando e loro
+ significato.
+* Altri argomenti:: Nomi dei file in input e assegnamento
+ di valori a variabili.
+* Specificare lo standard input:: Come specificare lo standard input
+ insieme ad altri file.
+* Variabili d'ambiente:: Le variabili d'ambiente usate da
+ @command{gawk}.
+* AWKPATH (Variabile):: Ricerca di programmi @command{awk}
+ in una lista di directory.
+* AWKLIBPATH (Variabile):: Ricerca di librerie condivise
+ @command{awk} in una lista di
+ directory.
+* Altre variabili d'ambiente:: Le variabili d'ambiente.
+* Codice di ritorno:: Il codice di ritorno all'uscita
+ da @command{gawk}.
+* Includere file:: Come includere altri file nel
+ proprio programma.
+* Caricare librerie condivise:: Caricare librerie condivise nel
+ proprio programma.
+* Parti obsolete:: Opzioni e/o funzionalit@`a obsolete.
+* Non documentato:: Opzioni e funzionalit@`a non documentate.
+* Sommario invocazione:: Sommario di come eseguire
+ @command{awk}.
+* Uso di @dfn{regexp}:: Come usare le espressioni regolari.
+* Sequenze di protezione:: Come scrivere caratteri non stampabili.
+* Operatori di espressioni regolari:: Operatori di espressioni regolari.
+* Espressioni tra parentesi quadre:: Cosa possono contenere @samp{[...]}.
+* Pi@`u lungo da sinistra:: Quanto @`e lungo il testo individuato.
+* Espressioni regolari calcolate:: Usare @dfn{regexp} dinamiche.
+* Operatori di @dfn{regexp} GNU:: Operatori propri del software GNU.
+* Maiuscolo-Minuscolo:: Fare confronti ignorando
+ maiuscolo/minuscolo.
+* Sommario espressioni regolari:: Sommario delle espressioni regolari.
+* Record:: Controllare come i dati sono suddivisi
+ in record.
+* awk divisione record:: Divisione dei record con @command{awk}
+ standard.
+* gawk divisione record:: Divisione dei record con @command{gawk}.
+* Campi:: Un'introduzione ai campi.
+* Campi non costanti:: Numeri di campo variabili.
+* Cambiare i campi:: Cambiare il contenuto di un campo.
+* Separatori di campo:: I separatori di campo, e come
+ cambiarli.
+* Separatori di campo di default:: Come di solito sono separati i campi.
+* Separare campi con @dfn{regexp}:: Usare @dfn{regexp} come separatori.
+* Campi di un solo carattere:: Fare di ogni carattere un campo
+ separato.
+* Separatori campo da riga di comando:: Impostare @code{FS} dalla riga di
+ comando.
+* Campo intera riga:: Fare di una riga intera un campo
+ solo.
+* Sommario sulla separazione campi:: Alcuni punti finali e una tavola di
+ sommario.
+* Dimensione costante:: Leggere campi di larghezza costante.
+* Separazione in base al contenuto:: Definire campi dal loro Contenuto.
+* Righe multiple:: Record su righe multiple
+* Getline:: Richiedere input usando @code{getline}.
+* Getline semplice:: Usare @code{getline} senza argomenti.
+* Getline variabile:: Usare @code{getline} in una variabile.
+* Getline file:: Usare @code{getline} da un file.
+* Getline variabile file:: Usare @code{getline} in una variabile
+ da un file.
+* Getline @dfn{pipe}:: Usare @code{getline} da una @dfn{pipe}.
+* Getline variabile @dfn{pipe}:: Usare @code{getline} in una variabile
+ da una @dfn{pipe}.
+* Getline coprocesso:: Usare @code{getline} da un coprocesso.
+* Getline variabile coprocesso:: Usare @code{getline} in una variabile
+ da un coprocesso.
+* Note su getline:: Cose importanti da sapere su
+ @code{getline}.
+* Sommario di getline:: Sommario delle varianti di
+ @code{getline}.
+* Timeout in lettura:: Leggere input entro un tempo limite.
+* Proseguire dopo errore in input:: Rielaborare input dopo certi errori.
+* Directory su riga di comando:: Cosa accade se si mette una directory
+ sulla riga di comando.
+* Sommario di Input:: Sommario di Input.
+* Esercizi su Input:: Esercizi.
+* Print:: L'istruzione @code{print}.
+* Esempi su print:: Semplici esempi di
+ istruzioni @code{print}.
+* Separatori di output:: I separatori di output e come
+ modificarli.
+* OFMT:: Controllare l'output di numeri con
+ @code{print}.
+* Printf:: L'istruzione @code{printf}.
+* Printf Fondamenti:: Sintassi dell'istruzione
+ @code{printf}.
+* Lettere di controllo:: Lettere di controllo del formato.
+* Modificatori di formato:: Modificatori specifiche di formato.
+* Esempi su printf:: Numerosi esempi.
+* Ridirezione:: Come ridirigere l'output a diversi
+ file e @dfn{pipe}.
+* FD speciali:: File speciali per I/O.
+* File speciali:: Interpretazione @value{FNS} in
+ @command{gawk}. @command{gawk}
+ permette di accedere a descrittori di
+ file ereditati.
+* Altri file ereditati:: Accedere ad altri file aperti con
+ @command{gawk}.
+* Reti speciali:: File speciali per comunicazioni con
+ la rete.
+* Avvertimenti speciali:: Cose a cui prestare attenzione.
+* Chiusura file e @dfn{pipe}:: Chiudere file in input e di output e
+ @dfn{pipe}.
+* Continuazione dopo errori:: Abilitare continuazione dopo errori
+ in output.
+* Sommario di Output:: Sommario di Output.
+* Esercizi su Output:: Esercizi.
+* Valori:: Costanti, variabili ed espressioni
+ regolari.
+* Costanti:: Costanti di tipo stringa, numeriche ed
+ espressioni regolari.
+* Costanti scalari:: Costanti numeriche e stringhe.
+* Numeri non-decimali:: Cosa sono i numeri ottali ed
+ esadecimali.
+* Costanti come espressioni regolari:: Costanti fornite tramite espressioni
+ regolari.
+* Usare le costanti @dfn{regexp}:: Quando e come usare una costante
+ specificata tramite espressioni
+ regolari
+* Costanti @dfn{regexp} normali:: Costanti @dfn{regexp} normali in
+ @command{awk}.
+* Costanti @dfn{regexp} forti:: Costanti @dfn{regexp} fortemente
+ tipizzate.
+* Variabili:: Le variabili permettono di
+ definire valori da usare in seguito.
+* Usare variabili:: Usare variabili nei propri programmi.
+* Opzioni di assegnamento:: Impostare variabili dalla riga di
+ comando, e un sommario della sintassi
+ della riga di comando.
+ Questo @`e un metodo di input avanzato.
+* Conversione:: La conversione di stringhe in numeri
+ e viceversa.
+* Stringhe e numeri:: Come @command{awk} converte tra
+ stringhe e numeri.
+* Localizzazione e conversioni:: Come la localizzazione pu@`o influire
+ sulle conversioni.
+* Tutti gli operatori:: Gli operatori di @command{gawk}.
+* Operatori aritmetici:: Operazioni aritmetiche (@samp{+},
+ @samp{-}, etc.)
+* Concatenazione:: Concatenazione di stringhe.
+* Operatori di assegnamento:: Cambiare il valore di una variabile
+ o di un campo.
+* Operatori di incremento:: Incrementare il valore numerico di una
+ variabile.
+* Valori e condizioni di verit@`a:: Determinare Vero/Falso.
+* Valori di verit@`a:: Cosa @`e ``vero'' e cosa @`e ``falso''.
+* Tipi di variabile e confronti:: Come alle variabili si assegna il tipo
+ e l'effetto che questo ha sul confronto
+ di numeri e stringhe con @samp{<}, etc.
+* Tipi di variabile:: Tipo stringa rispetto a tipo numero.
+* Operatori di confronto:: Gli operatori di confronto.
+* Confronto POSIX di stringhe:: Confronto tra stringhe usando le
+ regole POSIX.
+* Operatori booleani:: Combinare espressioni di confronto
+ usando operatori booleani @samp{||}
+ (``or''), @samp{&&} (``and'') e
+ @samp{!} (``not'').
+* Espressioni condizionali:: Le espressioni condizionali scelgono
+ una tra due sottoespressioni, a
+ seconda del valore di una terza
+ sottoespressione.
+* Chiamate di funzione:: Una chiamata di funzione @`e
+ un'espressione.
+* Precedenza:: Come si nidificano i vari operatori.
+* Localizzazioni:: Come la localizzazione influenza la
+ gestione dati.
+* Sommario delle espressioni:: Sommario delle espressioni.
+* Panoramica sui criteri di ricerca:: Come scrivere un criterio di ricerca.
+* @dfn{regexp} come criteri di ricerca:: Espressioni regolari come criteri
+ di ricerca.
+* Espressioni come criteri di ricerca:: Qualsiasi espressione pu@`o servire da
+ criterio di ricerca.
+* Intervalli:: Specificare intervalli di record con i
+ criteri di ricerca.
+* BEGIN/END:: Specificare regole di inizio e fine
+ programma.
+* Usare BEGIN/END:: Come e perch@'e usare regole BEGIN/END.
+* I/O e BEGIN/END:: Problemi di I/O nelle regole BEGIN/END.
+* BEGINFILE/ENDFILE:: Due condizioni speciali per controlli
+ avanzati.
+* Vuoto:: Il criterio di ricerca vuoto, che
+ corrisponde a ogni record.
+* Usare variabili di shell:: Come usare variabili di shell in
+ @command{awk}.
+* Panoramica sulle azioni:: Cosa costituisce un'azione.
+* Istruzioni:: Descrizione dettagliata delle varie
+ istruzioni di controllo.
+* Istruzione if:: Eseguire in maniera condizionale
+ istruzioni @command{awk}.
+* Istruzione while:: Eseguire il ciclo, finch@'e @`e
+ verificata una condizione.
+* Istruzione do:: Eseguire l'azione specificata, continuare
+ a eseguire il ciclo
+ finch@'e @`e verificata una condizione.
+* Istruzione for:: Un'altra istruzione iterativa, che
+ permette di specificare clausole
+ iniziali e di incremento.
+* Istruzione switch:: Valutazione di quale insieme di
+ istruzioni eseguire, a seconda del
+ valore assunto da una variabile.
+* Istruzione break:: Uscire subito dal ciclo pi@`u interno
+ in cui ci si trova.
+* Istruzione continue:: Andare alla fine del ciclo pi@`u interno
+ in cui ci si trova.
+* Istruzione next:: Smettere di elaborare il record
+ corrente.
+* Istruzione nextfile:: Smettere di elaborare il file
+ corrente.
+* Istruzione exit:: Interrompere l'esecuzione di @command{awk}.
+* Variabili predefinite:: Sommario delle variabili predefinite.
+* Variabili modificabili dall'utente:: Variabili predefinite modificabili per
+ controllare @command{awk}.
+* Variabili auto-assegnate:: Variabili predefinite con cui
+ @command{awk} fornisce informazioni.
+* ARGC e ARGV:: Modi di usare @code{ARGC} e
+ @code{ARGV}.
+* Sommario criteri e azioni:: Sommario criteri e azioni.
+* Fondamenti sui vettori:: Informazioni di base sui vettori.
+* Introduzione ai vettori:: Introduzione ai vettori.
+* Visitare elementi:: Come esaminare un elemento di un
+ vettore.
+* Impostare elementi:: Come cambiare un elemento di un
+ vettore.
+* Esempio di vettore:: Esempio semplice di vettore
+* Visitare un intero vettore:: Variazione dell'istruzione
+ @code{for}. Cicla attraverso gli
+ indici degli elementi contenuti in
+ un vettore.
+* Controllare visita:: Controllare l'ordine in cui i vettori
+ sono visitati.
+* Indici numerici di vettore:: Come usare numeri come indici in
+ @command{awk}.
+* Indici non inizializzati:: Usare variabili non inizializzate
+ come indici.
+* Cancellazione:: L'istruzione @code{delete} toglie un
+ elemento da un vettore.
+* Vettori multidimensionali:: Emulare vettori multidimensionali in
+ @command{awk}.
+* Visitare vettori multidimensionali:: Visitare vettori multidimensionali.
+* Vettori di vettori:: Vettori multidimensionali veri.
+* Sommario dei vettori:: Sommario dei vettori.
+* Funzioni predefinite:: Riepilogo delle funzioni predefinite.
+* Chiamare funzioni predefinite:: Come chiamare funzioni predefinite.
+* Funzioni numeriche:: Funzioni che trattano numeri, comprese
+ @code{int()}, @code{sin()}
+ e @code{rand()}.
+* Funzioni per stringhe:: Funzioni di manipolazione di stringhe,
+ come @code{split()}, @code{match()}
+ e @code{sprintf()}.
+* Dettagli ostici:: Pi@`u di quel che si vorrebbe sapere su
+ @samp{\} e @samp{&} con @code{sub()},
+ @code{gsub()}, e @code{gensub()}.
+* Funzioni di I/O:: Funzioni per i file e per i comandi
+ della shell.
+* Funzioni di tempo:: Funzione per gestire marcature temporali.
+* Funzioni a livello di bit:: Funzioni per operazioni di
+ manipolazione bit.
+* Funzioni per i tipi:: Funzioni per conoscere il tipo
+ di una variabile.
+* Funzioni di internazionalizzazione:: Funzioni per tradurre stringhe.
+* Funzioni definite dall'utente:: Descrizione dettagliata delle funzioni
+ definite dall'utente.
+* Sintassi delle definizioni:: Come scrivere definizioni e cosa
+ significano.
+* Esempio di funzione:: Un esempio di definizione di
+ funzione e spiegazione della stessa.
+* Precisazioni sulle funzioni:: Cose a cui prestare attenzione.
+* Chiamare una funzione:: Non usare spazi.
+* Campo di validit@`a variabili:: Variabili locali e globali.
+* Parametri per valore/riferimento:: Passaggio parametri.
+* Istruzione return:: Specificare il valore che una
+ funzione restituisce.
+* Variabili di tipo dinamico:: Come cambiare tipo a una variabile in
+ fase di esecuzione del programma.
+* Chiamate indirette:: Scegliere la funzione da chiamare in
+ fase di esecuzione del programma.
+* Sommario delle funzioni:: Sommario delle funzioni.
+* Nomi di variabili di libreria:: Che nomi @`e meglio dare alle variabili
+ private globali nelle funzioni di
+ libreria
+* Funzioni di tipo generale:: Funzioni di uso generale.
+* Funzione strtonum:: Da usare se non @`e disponibile la
+ funzione predefinita
+ @code{strtonum()}.
+* Funzione assert:: Una funzione per controllare
+ affermazioni in programmi
+ @command{awk}.
+* Funzione round:: Una funzione per eseguire
+ arrotondamenti se @code{sprintf()}
+ non lo fa correttamente.
+* Funzione random Cliff:: Il generatore Cliff di numeri casuali.
+* Funzioni ordinali:: Funzioni per usare caratteri come
+ numeri e viceversa.
+* Funzione join:: Una funzione per raccogliere un
+ vettore in una stringa.
+* Funzione getlocaltime:: Una funzione per ottenere data e
+ ora nel formato desiderato.
+* Funzione readfile:: Una funzione per leggere un file
+ intero in un colpo solo.
+* Apici alla shell:: Una funzione per passare stringhe
+ con apici alla shell.
+* Gestione File Dati:: Funzioni for gestire file dati
+ specificati sulla riga di comando,
+* Funzione filetrans:: Una funzione per gestire il passaggio
+ da un file in input al successivo.
+* Funzione rewind:: Una funzione per rileggere il file
+ di input.
+* Controllo di file:: Controllare che i file in input siano
+ accessibili.
+* File vuoti:: Controllare se i file in input sono
+ vuoti.
+* Ignorare assegnamenti di variabili:: Trattare assegnamenti di variabili
+ come nomi di file.
+* Funzione getopt:: Una funzione per trattare argomenti
+ presenti sulla riga di comando.
+* Funzioni Passwd:: Funzioni per ottenete informazioni
+ sull'utente [da /etc/passwd].
+* Funzioni Group:: Funzioni per ottenete informazioni
+ sul gruppo [da /etc/group].
+* Visitare vettori:: Una funzione per visitare vettori
+ di vettori.
+* Sommario funzioni di libreria:: Sommario funzioni di libreria.
+* Esercizi con le librerie:: Esercizi.
+* Eseguire esempi:: Come eseguire i programmi di esempio.
+* Cloni:: Cloni di programmi di utilit@`a comuni.
+* Programma cut:: Il programma di utilit@`a @command{cut}.
+* Programma egrep:: Il programma di utilit@`a @command{egrep}.
+* Programma id:: Il programma di utilit@`a @command{id}.
+* Programma split:: Il programma di utilit@`a @command{split}.
+* Programma tee:: Il programma di utilit@`a @command{tee}.
+* Programma uniq:: Il programma di utilit@`a @command{uniq}.
+* Programma wc:: Il programma di utilit@`a @command{wc}.
+* Programmi vari:: Alcuni interessanti programmi in
+ @command{awk}
+* Programma dupword:: Trovare parole duplicate in un
+ documento.
+* Programma alarm:: Un programma di sveglia.
+* Programma translate:: Un programma simile al comando di
+ utilit@`a @command{tr}.
+* Programma labels:: Stampare etichette per lettere.
+* Programma utilizzo parole:: Un programma per produrre un contatore
+ dell'utilizzo di parole in un testo.
+* Programma riordino diario:: Eliminare righe doppie da un file di
+ cronologia.
+* Programma extract:: Estrarre programmi da file sorgenti
+ Texinfo.
+* Programma sed semplice:: Un semplice editor di flusso.
+* Programma igawk:: Un programma per fornire ad
+ @command{awk} la possibilit@`a di
+ includere file.
+* Programma anagram:: Trovare anagrammi da una lista di
+ parole.
+* Programma signature:: La gente fa cose stupefacenti se ha
+ troppo tempo libero.
+* Sommario dei programmi:: Sommario dei programmi.
+* Esercizi sui programmi:: Esercizi.
+* Dati non decimali:: Consentire dati di input in base
+ diversa da 10.
+* Ordinamento di vettori:: Modi per controllare la visita di un
+ vettore e il suo ordinamento.
+* Controllare visita vettori:: Come usare PROCINFO["sorted_in"].
+* Funzioni di ordinamento di vettori:: Come usare @code{asort()} e
+ @code{asorti()}.
+* I/O bidirezionale:: Comunicazione nei due sensi con un
+ altro processo.
+* Reti TCP/IP:: Usare @command{gawk} per
+ programmazione di rete.
+* Profilare:: Profilare i propri programmi
+ @command{awk}.
+* Sommario funzionalit@`a avanzate:: Sommario funzionalit@`a avanzate.
+* I18N e L10N:: Internazionalizzazione e localiz.
+* Utilizzare @command{gettext}:: Come funziona GNU @code{gettext}.
+* I18N per programmatore:: Funzionalit@`a per il programmatore.
+* I18N per traduttore:: Funzionalit@`a per il traduttore.
+* Estrazione di stringhe:: Estrarre stringhe marcate.
+* Ordinamento di printf:: Riordinare argomenti @code{printf}
+ [nelle stringhe da tradurre].
+* Portabilit@`a nell'I18N:: Problemi di portabilit@`a a livello di
+ @command{awk}.
+* Esempio I18N:: Un semplice esempio di
+ internazionalizzazione.
+* Gawk internazionalizzato:: @command{gawk} stesso @`e
+ internazionalizzato.
+* Sommario I18N:: Sommario sull'internazionalizzazione.
+* Debugging:: Introduzione al debugger di
+ @command{gawk}.
+* Nozioni sul debug:: Generalit@`a sul debug.
+* Terminologia nel debug:: Concetti fondamentali sul debug.
+* Debug di Awk:: Il debug di @command{awk}.
+* Esempio di sessione di debug:: Esempio di sessione di debug di
+ @command{gawk}.
+* Invocazione del debugger:: Come avviare il debugger.
+* Trovare il bug:: Trovare il bug.
+* Lista dei comandi di debug:: I principali comandi di debug.
+* Controllo dei breakpoint:: Controllo dei punti d'interruzione.
+* Controllo esecuzione debugger:: Controllo di esecuzione.
+* Vedere e modificare dati:: Vedere e modificare dati.
+* Stack di esecuzione:: Lavorare con lo stack.
+* Informazioni sul debugger:: Ottenere informazioni sullo stato
+ del programma e del debugger.
+* Comandi vari del debugger:: Comandi vari del debugger.
+* Supporto per Readline:: Supporto per Readline.
+* Limitazioni:: Limitazioni.
+* Sommario sul debug:: Sommario sul debug.
+* Aritmetica del computer:: Una rapida introduzione alla matematica del
+ computer.
+* Definizioni matematiche:: Altre cose da sapere.
+* Funzionalit@`a MPFR:: Funzionalit@`a per il calcolo a
+ precisione arbitraria in @command{gawk}
+* Cautela col calcolo in VM:: Cose da sapere.
+* Inesattezza nei calcoli:: La matematica in virgola mobile non @`e
+ esatta.
+* Rappresentazioni inesatte:: Molti numeri non sono rappresentati
+ esattamente.
+* Confronti tra valori in VM:: Come confrontare valori in virgola mobile.
+* Gli errori si sommano:: Gli errori diventano sempre maggiori.
+* Ottenere la precisione:: Ottenere la precisione voluta.
+* Tentare di arrotondare:: Tentare di aggiungere bit di precisione e
+ arrotondare.
+* Impostare la precisione:: Impostare la precisione.
+* Impostare modi di arrotondare:: Impostare la modalit@`a di
+ arrotondamento.
+* Interi a precisione arbitraria:: Aritmetica dei numeri interi a precisione
+ arbitraria con @command{gawk}.
+* Problemi virgola mobile POSIX:: Confronto tra standard e uso corrente.
+* Sommario virgola mobile:: Sommario della trattazione della
+ virgola mobile.
+* Introduzione alle estensioni:: Cos'@`e un'estensione.
+* Licenza delle estensioni:: tipo di licenza delle estensioni.
+* Panoramica sul meccanismo delle estensioni:: Come funziona a grandi linee.
+* Descrizione dell'API delle estensioni:: Una descrizione completa dell'API.
+* Intro funzioni API delle estensioni:: Introduzione alle funzioni dell'API.
+* Tipi di dati generali:: I tipi di dati.
+* Funzioni di allocazione memoria:: Funzioni per allocare memoria.
+* Funzioni di costruzione:: Funzioni per creare valori.
+* Funzioni di registrazione:: Funzioni per registrare cose con
+ @command{gawk}.
+* Funzioni di estensione:: Registrare funzioni di estensione.
+* Funzioni di exit callback:: Registrare una exit di callback.
+* Stringa di versione Estensioni:: Registrare una stringa di versione.
+* Analizzatori di input:: Registrare un analizzatore di input.
+* Processori di output:: Registrare un processore di output.
+* Processori bidirezionali:: Registrare un processore
+ bidirezionale.
+* Stampare messaggi:: Stampare messaggi dalle estensioni.
+* Aggiornare @code{ERRNO}:: Funzioni per aggiornare @code{ERRNO}.
+* Richiedere valori:: Come ottenere un valore.
+* Accedere ai parametri:: Funzioni per acceder ai parametri.
+* Accedere alla tabella simboli:: Funzioni per accedere alle variabili
+ globali.
+* Tabella simboli per nome:: Accedere e aggiornare variabili per nome.
+* Tabella simboli tramite cookie:: Accedere alle variabili per ``cookie''.
+* Valori nascosti:: Creare e usare valori nascosti.
+* Manipolazione di vettori:: Funzioni per lavorare coi vettori.
+* Tipi di dati per i vettori:: Tipi dati per lavorare coi vettori.
+* Funzioni per i vettori:: Funzioni per lavorare coi vettori.
+* Appiattimento di vettori:: Come appiattire i vettori.
+* Creazione di vettori:: Come creare e popolare vettori.
+* Ridirezione API:: Come accedere alla ridirezioni e
+ modificarle.
+* Variabili dell'estensione API:: Variabili fornite dall'API.
+* Versione dell'estensione:: Informazioni sulla versione API.
+* Variabili informative di estens. API:: Variabili che forniscono informazioni
+ sull'invocazione di @command{gawk}.
+* Codice predefinito di un'estensione API:: Codice predefinito di interfaccia API.
+* Modifiche dalla versione API 1:: Modifiche dalla versione 1 dell'API.
+* Trovare le estensioni:: Come @command{gawk} trova le
+ estensioni compilate.
+* Esempio di estensione:: Esempio di codice C di un'estensione.
+* Descrizione interna file:: Quello che le nuove funzioni faranno.
+* Operazioni interne file:: Codice per gestire file all'interno.
+* Usare operazioni interne file:: Come usare un'estensione esterna.
+* Esempi di estensione:: Le estensioni di esempio incluse con
+ @command{gawk}.
+* Esempio di estensione funzioni file:: Funzioni relative ai file.
+* Esempio di estensione Fnmatch:: Un'interfaccia a @code{fnmatch()}.
+* Esempio di estensione Fork:: Un'interfaccia a @code{fork()} e
+ altre funzioni di processo.
+* Esempio di estensione Inplace:: Consentire modifica file input
+ nell'estensione.
+* Esempio di estensione Ord:: Conversioni di caratteri in valori
+ numerici e viceversa.
+* Esempio di estensione Readdir:: Un'interfaccia a @code{readdir()}.
+* Esempio di estensione Revout:: Invertire la stringa in output.
+* Esempio di estensione Rev2way:: Esempio di I/O bidirezionale.
+* Esempio di estensione Rwarray:: Scaricare e ricaricare un vettore.
+* Esempio di estensione Readfile:: Leggere un intero file in una stringa.
+* Esempio di estensione Time:: Un'interfaccia a @code{gettimeofday()}
+ e @code{sleep()}.
+* Esempio di estensione API Test:: Test per la API.
+* gawkextlib:: Il progetto @code{gawkextlib}.
+* Sommario delle estensioni:: Sommario delle estensioni.
+* Esercizi sulle estensioni:: Esercizi.
+* V7/SVR3.1:: Le principali differenze tra V7 e
+ System V Release 3.1.
+* SVR4:: Differenze minori tra System V
+ Release 3.1 e 4.
+* POSIX:: Nuove funzionalit@`a per lo standard
+ POSIX.
+* BTL:: Nuove funzionalit@`a dalla versione
+ di @command{awk} di Brian Kernighan.
+* POSIX/GNU:: Le estensioni in @command{gawk} non
+ previste in @command{awk} POSIX.
+* Storia delle funzionalit@`a:: Storia delle funzionalit@`a di
+ @command{gawk}.
+* Estensioni comuni:: Sommario Estensioni comuni.
+* Intervalli e localizzazione:: Come le localizzazioni influiscono
+ sugli intervalli delle espressioni
+ regolari.
+* Contributori:: I maggiori contributori a
+ @command{gawk}.
+* Sommario della storia:: Sommario della storia.
+* Distribuzione di Gawk:: Contenuto della distribuzione di
+ @command{gawk}.
+* Scaricare:: Come ottenere la distribuzione.
+* Scompattazione:: Come estrarre la distribuzione.
+* Contenuti della distribuzione:: Cosa c'@`e nella distribuzione.
+* Installazione Unix:: Installare @command{gawk} su
+ varie versioni di Unix.
+* Installazione veloce:: Compilare @command{gawk} sotto Unix.
+* File da usare a inizio sessione:: Funzioni di personalizzazione shell.
+* Ulteriori opzioni di configurazione:: Altre opzioni utilizzabili in fase
+ di compilazione.
+* Filosofia della configurazione:: Come si suppone che funzioni.
+* Installazione non-Unix:: Installazioni su altri Sistemi
+ Operativi.
+* Installazione su PC:: Installare e compilare
+ @command{gawk} su Microsoft Windows.
+* Installazione binaria su PC:: Installare una distribuzione pronta
+ all'uso.
+* Compilazione su PC:: Compilare @command{gawk} per
+ Windows32.
+* Uso su PC:: Eseguire @command{gawk} su Windows32.
+* Cygwin:: Compilare ed eseguire @command{gawk}
+ per Cygwin.
+* MSYS:: Usare @command{gawk} nell'ambiente
+ MSYS.
+* Installazione su VMS:: Installare @command{gawk} su VMS.
+* Compilazione su VMS:: Come compilare @command{gawk} su
+ VMS.
+* Estensioni dinamiche su VMS:: Compilare estensioni dinamiche
+ di @command{gawk} su VMS.
+* Dettagli installazione su VMS:: Come installare @command{gawk} su
+ VMS.
+* Esecuzione su VMS:: Come eseguire @command{gawk} su VMS.
+* GNV su VMS:: Il progetto GNV di VMS.
+* Vecchio Gawk su VMS:: Una versione non aggiornata arriva
+ con alcune versioni di VMS.
+* Bug:: Notificare problemi e bug.
+* Indirizzo Bug:: Dove notificare problemi.
+* Usenet:: Dove non notificare problemi.
+* Manutentori:: Manutentori di version non-*nix.
+* Altre versioni:: Altre implementazioni di
+ @command{awk} liberamente
+ disponibili.
+* Sommario dell'installazione:: Sommario dell'installazione.
+* Modalit@`a di compatibilit@`a:: Come inibire alcune estensioni di
+ @command{gawk}.
+* Aggiunte:: Fare aggiunte a @command{gawk}.
+* Accedere ai sorgenti:: Accedere al deposito sorgenti Git.
+* Aggiungere codice:: Aggiungere codice al programma
+ principale @command{gawk}.
+* Nuovi sistemi:: Rendere disponibile @command{gawk}
+ a un nuovo sistema operativo.
+* File derivati:: Perch@'e i file ancillari sono tenuti
+ nel deposito @command{git}.
+* Future estensioni:: Nuove funzionalit@`a che potranno
+ essere implementate in futuro.
+* Limitazioni dell'implementazione:: Alcune limitazioni
+ dell'implementazione.
+* Progetto delle estensioni:: Note di progetto sull'estensione API.
+* Problemi con le vecchie estensioni:: Problemi con la precedente
+ implementazione di estensioni.
+* Obiettivi delle estensioni:: Obiettivi del nuovo meccanismo.
+* Altre scelte progettuali per le estensioni:: Qualche altra scelta progettuale.
+* Futuri sviluppi delle estensioni:: Possibilit@`a di crescita futura.
+* Meccanismo delle vecchie estensioni:: Problemi con le vecchie estensioni.
+* Sommario delle note:: Sommario delle note di
+ implementazione.
+* Fondamenti ad alto livello:: Una visione dall'alto.
+* Fondamenti sui tipi di dati:: Una velocissima introduzione ai tipi
+ di dati.
+@end detailmenu
+@end menu
+
+@c dedication for Info file
+@ifinfo
+Ai miei genitori, per il loro amore, e per lo splendido
+esempio che mi hanno dato.
+@sp 1
+A mia moglie Miriam, per avermi reso completo.
+Grazie per aver costruito la tua vita insieme a me.
+@sp 1
+Ai nostri figli Chana, Rivka, Nachum e Malka,
+per aver arricchito le nostre vite in misura incalcolabile.
+@end ifinfo
+
+@ifset SMALLPRINT
+@fonttextsize 10
+@end ifset
+
+@summarycontents
+@contents
+
+@ifset SMALLPRINT
+@fonttextsize 11
+@end ifset
+
+@node Introduzione3
+@unnumbered Introduzione alla Terza Edizione
+
+@c This bit is post-processed by a script which turns the chapter
+@c tag into a preface tag, and moves this stuff to before the title.
+@c Bleah.
+@docbook
+ <prefaceinfo>
+ <author>
+ <firstname>Michael</firstname>
+ <surname>Brennan</surname>
+ <!-- can't put mawk into command tags. sigh. -->
+ <affiliation><jobtitle>Autore di mawk</jobtitle></affiliation>
+ </author>
+ <date>Marzo 2001</date>
+ </prefaceinfo>
+@end docbook
+
+Arnold Robbins e io siamo buoni amici. Ci siamo conosciuti
+@c 11 years ago
+nel 1990 per un insieme di
+circostanze---e per il nostro linguaggio di programmazione preferito, AWK.
+Tutto era iniziato un paio d'anni prima.
+Avevo appena iniziato un nuovo lavoro e avevo notato un computer Unix scollegato
+che giaceva in un angolo.
+Nessuno sapeva come usarlo, tanto meno io. Comunque,
+qualche giorno pi@`u tardi, stava funzionando, con
+me come @code{root} e solo e unico utente.
+Quel giorno, iniziai la transizione da statistico a programmatore Unix.
+
+In uno dei miei giri per biblioteche e librerie alla ricerca di libri sullo
+Unix, trovai il libro, dalla copertina grigia, su AWK, noto anche come @:
+Alfred V.@: Aho, Brian W.@: Kernighan e
+Peter J.@: Weinberger, @cite{The AWK Programming Language}, (Addison-Wesley,
+1988). Il semplice paradigma di programmazione di AWK
+---trovare un'espressione di ricerca nell'input e di conseguenza compiere
+un'azione---riduceva spesso
+complesse e tediose manipolazioni di dati a poche righe di codice. Ero
+entusiasta di cimentarmi nella programmazione in AWK.
+
+Ahim@`e, l'@command{awk} sul mio computer era una versione limitata del
+linguaggio descritto nel libro grigio. Scoprii che il mio computer aveva il
+``vecchio @command{awk}'' mentre il libro descriveva il ``nuovo
+@command{awk}.''
+Imparai che non era un caso isolato; la vecchia versione si rifiutava di farsi da
+parte o di cedere il suo nome. Se un sistema aveva un nuovo @command{awk},
+questo era chiamato invariabilmente @command{nawk}, e pochi sistemi lo avevano.
+Il miglior modo per ottenere un nuovo @command{awk} era quello di scaricare via
+@command{ftp} il codice sorgente di @command{gawk} da @code{prep.ai.mit.edu}.
+@command{gawk} era una versione del nuovo @command{awk} scritta da David Trueman
+e Arnold, e disponibile sotto la GNU General Public License.
+
+Per inciso, ora non @`e
+pi@`u cos@`{@dotless{i}} difficile trovare un nuovo @command{awk}. @command{gawk} viene
+fornito con GNU/Linux, e si possono scaricare i binari e il codice sorgente per
+quasi tutti i sistemi; mia moglie usa @command{gawk} nella sua stazione di lavoro VMS.
+
+Il mio sistema Unix non era inizialmente collegato a una presa di corrente; a
+maggior ragione non era collegato a una rete. Cos@`{@dotless{i}}, ignaro dell'esistenza di
+@command{gawk} e in generale della comunit@`a di Unix, e desiderando un nuovo
+@command{awk}, ne scrissi uno mio, chiamato @command{mawk}. Prima di aver
+finito, scoprii l'esistenza di @command{gawk},
+ma era troppo tardi per fermarmi, cos@`{@dotless{i}} alla fine inviai un messaggio
+a un newsgroup @code{comp.sources}.
+
+Qualche giorno dopo ricevetti un cordiale messaggio di posta elettronica
+da Arnold che si presentava.
+Propose di scambiarci progetti e algoritmi, e
+alleg@`o una bozza dello standard POSIX, che mi permise di
+aggiornare @command{mawk} per includere le estensioni al linguaggio
+aggiunte dopo la pubblicazione di @cite{The AWK Programming Language}.
+
+Francamente, se i nostri ruoli fossero stati
+invertiti, io non sarei stato cos@`{@dotless{i}} disponibile e probabilmente non ci
+saremmo mai incontrati. Sono felice che l'incontro sia avvenuto.
+Lui @`e un vero esperto tra gli esperti di AWK e una persona squisita.
+Arnold mette a disposizione della Free Software Foundation parti significative
+della sua esperienza e del suo tempo.
+
+Questo libro @`e il manuale di riferimento di @command{gawk}, ma sostanzialmente
+@`e un libro sulla programmazione in AWK che
+interesser@`a un vasto pubblico.
+@`E un riferimento completo al linguaggio AWK come definito dalla versione del
+1987 di Bell Laboratories e codificato nelle POSIX Utilities
+standard del 1992.
+
+D'altra parte, un programmatore AWK alle prime armi pu@`o studiare
+una quantit@`a di programmi pratici che permettono di apprezzare
+la potenza dei concetti di base di AWK:
+flusso di controllo guidato dai dati, ricerca di corrispondenze tramite
+espressioni regolari e vettori associativi.
+Chi desidera qualcosa di nuovo pu@`o provare l'interfaccia di @command{gawk}
+verso i protocolli di rete attraverso i file speciali @file{/inet}.
+
+I programmi in questo libro evidenziano come un programma AWK sia
+generalmente molto pi@`u piccolo e veloce da sviluppare
+di uno equivalente scritto in C.
+Di conseguenza, @`e spesso conveniente creare un prototipo di un
+algoritmo o di un progetto in AWK per arrivare a eseguirlo in breve tempo e
+scoprire prima i problemi che possono presentarsi. Spesso, l'efficienza di
+questa versione iniziale interpretata @`e sufficiente e il prototipo
+AWK diventa il prodotto finale.
+
+Il nuovo comando @command{pgawk} (profiling @command{gawk}) produce
+conteggi sull'esecuzione delle istruzioni del programma.
+Recentemente ho fatto un tentativo con un algoritmo che, a fronte di
+@ifnotdocbook
+@math{n}
+@end ifnotdocbook
+@ifdocbook
+@i{n}
+@end ifdocbook
+righe di input, produceva il risultato in un tempo
+@tex
+$\sim\! Cn^2$,
+@end tex
+@ifnottex
+@ifnotdocbook
+~ C n^2,
+@end ifnotdocbook
+@end ifnottex
+@docbook
+<emphasis>&sim; Cn<superscript>2</superscript></emphasis>
+@end docbook
+mentre in teoria
+avrebbe dovuto terminare in un tempo
+@tex
+$\sim\! Cn\log n$.
+@end tex
+@ifnottex
+@ifnotdocbook
+~ C n log n.
+@end ifnotdocbook
+@end ifnottex
+@docbook
+<emphasis>&sim; Cn log n</emphasis>
+@end docbook
+Dopo qualche minuto di attenta lettura
+del profilo in @file{awkprof.out}, ho ricondotto il problema a
+una singola riga di codice. @command{pgawk} @`e una gradita integrazione
+ai miei strumenti di programmatore.
+
+Arnold ha condensato in questo libro oltre un decennio di esperienza nell'uso di
+programmi AWK e nello sviluppo di @command{gawk}. Se si vuole usare
+AWK o imparare ad usarlo, @`e consigliabile leggere questo libro.
+
+@ifnotdocbook
+@cindex Brennan, Michael
+@display
+Michael Brennan
+Autore di @command{mawk}
+Marzo 2001
+@end display
+@end ifnotdocbook
+
+@node Introduzione4
+@unnumbered Introduzione alla Quarta Edizione
+
+@c This bit is post-processed by a script which turns the chapter
+@c tag into a preface tag, and moves this stuff to before the title.
+@c Bleah.
+@docbook
+ <prefaceinfo>
+ <author>
+ <firstname>Michael</firstname>
+ <surname>Brennan</surname>
+ <!-- can't put mawk into command tags. sigh. -->
+ <affiliation><jobtitle>Autore di mawk</jobtitle></affiliation>
+ </author>
+ <date>Ottobre 2014</date>
+ </prefaceinfo>
+@end docbook
+
+Ci sono cose che non cambiano. Tredici anni fa scrivevo:
+``Se si vuole usare AWK o imparare ad usarlo, @`e consigliabile
+leggere questo libro.''
+Era vero allora e rimane vero anche oggi.
+
+Imparare a usare un linguaggio di programmazione richiede qualcosa di pi@`u
+che padroneggiarne la sintassi. Occorre comprendere come
+usare le funzionalit@`a del linguaggio per risolvere problemi pratici di
+programmazione. Uno dei punti pi@`u importanti di questo libro @`e che
+fornisce molti esempi che mostrano come utilizzare AWK.
+
+Altre cose, invece, cambiano. I nostri computer sono diventati molto pi@`u
+veloci e la loro memoria @`e molto pi@`u estesa.
+Per questa ragione, la velocit@`a di esecuzione e l'uso efficiente della
+memoria, caratteristiche di un linguaggio di livello elevato, hanno minore
+rilevanza.
+Scrivere un programma prototipo in AWK per poi riscriverlo in C per
+migliorare l'utilizzo delle risorse capita sempre meno, perch@'e sempre pi@`u
+spesso il prototipo @`e abbastanza veloce anche per essere messo in produzione.
+
+Naturalmente, ci sono tipi di calcoli che sono effettuati pi@`u agevolmente
+da programmi scritti in C o C++.
+Con @command{gawk} 4.1 e successive versioni, non @`e necessario
+decidere se scrivere un programma in AWK oppure in C/C++. Si pu@`o scrivere
+buona parte del programma in AWK e le parti che richiedono
+specificamente il C/C++ possono essere scritte in C/C++ e quindi il tutto
+pu@`o essere eseguito come un programma unico, con il modulo @command{gawk}
+che carica dinamicamente il modulo C/C++ in fase di esecuzione.
+@c Chapter 16
+@iftex
+Il
+@end iftex
+@ref{Estensioni dinamiche},
+spiega la procedura in gran
+dettaglio, e, come prevedibile, riporta molti esempi che sono di aiuto per
+approfondire anche gli aspetti pi@`u complessi.
+
+@`E per me un piacere programmare in AWK ed @`e stato divertente (ri)leggere
+questo libro. Penso che sar@`a lo stesso per voi.
+
+@ifnotdocbook
+@cindex Brennan, Michael
+@display
+Michael Brennan
+Autore di @command{mawk}
+Ottobre 2014
+@end display
+@end ifnotdocbook
+@node Prefazione
+@unnumbered Prefazione
+@c I saw a comment somewhere that the preface should describe the book itself,
+@c and the introduction should describe what the book covers.
+@c
+@c 12/2000: Chuck wants the preface & intro combined.
+
+@c This bit is post-processed by a script which turns the chapter
+@c tag into a preface tag, and moves this stuff to before the title.
+@c Bleah.
+@docbook
+ <prefaceinfo>
+ <author>
+ <firstname>Arnold</firstname>
+ <surname>Robbins</surname>
+ <affiliation><jobtitle>Nof Ayalon</jobtitle></affiliation>
+ <affiliation><jobtitle>Israel</jobtitle></affiliation>
+ </author>
+ <date>Febbraio 2015</date>
+ </prefaceinfo>
+@end docbook
+
+Lavorando con file di testo capita di dover eseguire alcuni tipi ripetitivi di
+operazioni. Si potrebbe voler estrarre alcune righe e scartare il resto, o fare
+modifiche laddove siano verificate certe condizioni, lasciando inalterato il
+resto del file. Questi compiti risultano spesso pi@`u agevoli usando
+@command{awk}. Il programma di utilit@`a @command{awk} interpreta un linguaggio
+di programmazione specializzato che rende facile eseguire semplici attivit@`a
+di riformattazione di dati.
+
+@cindex Brian Kernighan, @command{awk} di
+L'implementazione GNU di @command{awk} @`e chiamata @command{gawk}; se
+invocato con le opzioni o con le variabili d'ambiente appropriate,
+(@pxref{Opzioni}), @`e pienamente
+compatibile con le specifiche
+POSIX@footnote{Lo standard POSIX 2008 @`e accessibile in rete all'indirizzo
+@w{@url{http://www.opengroup.org/onlinepubs/9699919799/}.}}
+del linguaggio @command{awk}
+e con la versione Unix di @command{awk} mantenuta
+da Brian Kernighan.
+Ci@`o implica che tutti i programmi
+@command{awk} scritti correttamente dovrebbero funzionare con @command{gawk}.
+Perci@`o nella maggior parte dei casi non si distingue tra @command{gawk} e
+altre implementazioni di @command{awk}.
+
+@cindex @command{awk}, POSIX e, si veda anche POSIX @command{awk}
+@cindex @command{awk}, POSIX e
+@cindex POSIX, @command{awk} e
+@cindex @command{gawk}, @command{awk} e
+@cindex @command{awk}, @command{gawk} e
+@cindex @command{awk}, uso di
+Usando @command{awk} potete:
+
+@itemize @value{BULLET}
+@item
+Gestire piccole basi di dati personali
+
+@item
+Generare rapporti
+
+@item
+Validare dati
+
+@item
+Produrre indici ed effettuare altre operazioni per la preparazione di documenti
+
+@item
+Sperimentare algoritmi che possono essere adattati in seguito ad altri
+linguaggi per computer
+@end itemize
+
+@cindex @command{awk}, si veda anche @command{gawk}
+@cindex @command{gawk}, si veda anche @command{awk}
+@cindex @command{gawk}, uso di
+Inoltre,
+@command{gawk}
+fornisce strumenti che rendono facile:
+
+@itemize @value{BULLET}
+@item
+Estrarre frammenti di dati per l'elaborazione
+
+@item
+Ordinare dati
+
+@item
+Effettuare semplici comunicazioni di rete
+
+@item
+Creare il profilo di esecuzione ed effettuare il debug
+di programmi @command{awk}.
+
+@item
+Estendere il linguaggio con funzioni scritte in C o C++.
+@end itemize
+
+Questo @value{DOCUMENT} spiega il linguaggio @command{awk} e come lo si pu@`o
+usare efficacemente. @`E richiesta una familiarit@`a coi comandi di sistema
+di base, come @command{cat} e @command{ls},@footnote{Questi programmi di
+utilit@`a sono disponibili sui sistemi conformi a POSIX, come pure sui sistemi
+tradizionali basati su Unix. Se si usa qualche altro sistema operativo, si
+deve comunque avere familiarit@`a con i concetti di ridirezione I/O e di
+@dfn{pipe}.} cos@`{@dotless{i}} come con le funzionalit@`a di base della shell, come la
+ridirezione, l'input/output (I/O) e le @dfn{pipe}.
+
+@cindex GNU @command{awk}, si veda @command{gawk}
+Implementazioni del linguaggio @command{awk} sono disponibili per diversi
+sistemi operativi di computer. Questo @value{DOCUMENT}, oltre a descrivere il
+linguaggio @command{awk} in generale, descrive anche la specifica
+implementazione di @command{awk} chiamata @command{gawk} (che sta per
+``GNU @command{awk}''). @command{gawk} funziona su una vasta gamma di sistemi
+Unix, dai PC basati su architettura Intel fino
+a sistemi di potenza molto maggiore.
+@command{gawk} @`e stato portato anche su Mac OS X,
+Microsoft Windows
+(tutte le versioni),
+e OpenVMS.@footnote{Qualche altro sistema operativo obsoleto su cui
+@command{gawk} era stato portato non @`e pi@`u mantenuto e il codice specifico
+per quei sistemi @`e stato rimosso.}
+
+@menu
+* Storia:: La storia di @command{gawk} e
+ @command{awk}.
+* Nomi:: Che nome usare per trovare
+ @command{awk}.
+* Questo manuale:: Uso di questo @value{DOCUMENT}.
+ Comprende esempi di file in input
+ utilizzabili.
+* Convenzioni:: Convenzioni tipografiche.
+* Storia del manuale:: Breve storia del Progetto GNU e di
+ questo @value{DOCUMENT}.
+@ifset FOR_PRINT
+* Aggiornamenti:: Come tenersi al corrente.
+@end ifset
+* Come contribuire:: Un aiuto per la salvezza del mondo.
+* Ringraziamenti:: Ringraziamenti.
+@end menu
+
+@node Storia
+@unnumberedsec La storia di @command{gawk} e @command{awk}
+@cindex ricetta per un linguaggio di programmazione
+@cindex linguaggio di programmazione, ricetta per un
+@cindex programmazione, ricetta per un linguaggio di
+@sidebar Ricetta per un linguaggio di programmazione
+
+@multitable {2 parti di} {1 parte di @code{egrep}} {1 parte di @code{snobol}}
+@item @tab 1 parte di @code{egrep} @tab 1 parte di @code{snobol}
+@item @tab 2 parti di @code{ed} @tab 3 parti di C
+@end multitable
+
+Mescolare bene tutte le parti usando @code{lex} e @code{yacc}.
+Preparare una concisa documentazione e distribuire.
+
+Dopo otto anni, aggiungere un'altra parte di @code{egrep} e altre due
+parti di C. Documentare molto bene e distribuire.
+@end sidebar
+
+@cindex Aho, Alfred
+@cindex Weinberger, Peter
+@cindex Kernighan, Brian
+@cindex @command{awk}, storia di
+Il nome @command{awk} deriva dalle iniziali dei suoi progettisti: Alfred V.@:
+Aho, Peter J.@: Weinberger e Brian W.@: Kernighan. La versione originale di
+@command{awk} fu scritta nel 1977 negli AT&T Bell Laboratories.
+Nel 1985, una nuova versione rese il linguaggio di programmazione
+pi@`u potente, introducendo le funzioni definite dall'utente, flussi di input
+multipli ed espressioni regolari calcolate.
+Questa nuova versione ebbe larga diffusione con Unix System V
+Release 3.1 (1987).
+La versione in System V Release 4 (1989) ha aggiunto alcune nuove funzionalit@`a
+e ha fatto pulizia nel comportamento di alcuni degli ``punti oscuri'' del
+linguaggio. Le specifiche per @command{awk} nello standard POSIX Command
+Language and Utilities ha in seguito reso pi@`u chiaro il linguaggio. Sia i
+progettisti di @command{gawk} che quelli dell'originale @command{awk} dei Bell
+Laboratories hanno collaborato alla formulazione delle specifiche POSIX.
+
+@cindex Rubin, Paul
+@cindex Fenlason, Jay
+@cindex Trueman, David
+Paul Rubin ha scritto @command{gawk}, nel 1986.
+Jay Fenlason l'ha completata, seguendo i consigli di Richard Stallman.
+Anche John Woods ha fornito parti del codice. Nel 1988 e 1989, David Trueman,
+col mio aiuto, ha rivisto completamente @command{gawk} per la compatibilit@`a
+col pi@`u recente @command{awk}.
+Intorno al 1994, sono divenuto il manutentore principale.
+Lo sviluppo corrente @`e incentrato sulla correzione degli errori, sul
+miglioramento delle prestazioni, sulla conformit@`a agli standard e,
+occasionalmente, su nuove funzionalit@`a.
+
+Nel maggio 1997, J@"urgen Kahrs avvert@`{@dotless{i}} la necessit@`a di un accesso alla
+rete da @command{awk}, e con un piccolo aiuto da parte mia, cominci@`o ad
+aggiungere funzionalit@`a a @command{gawk} per fare questo. A quel tempo,
+lui scrisse anche il grosso di
+@cite{@value{GAWKINETTITLE}}
+(un documento separato, disponibile come parte della distribuzione
+@command{gawk}). Il suo codice alla fine venne integrato nella distribuzione
+principale di @command{gawk} con la versione 3.1 di @command{gawk}.
+
+John Haque ha riscritto la parte interna di @command{gawk}, mentre metteva a
+punto un debugger a livello di @command{awk}. Questa versione divenne
+disponibile come @command{gawk} versione 4.0 nel 2011.
+
+@xref{Contributori}
+per un elenco completo di quelli che hanno fornito contributi importanti a
+@command{gawk}.
+
+@node Nomi
+@unnumberedsec Una rosa, con ogni altro nome...
+
+@cindex @command{awk}, nuovo e vecchio
+Il linguaggio @command{awk} si @`e evoluto nel corso degli anni. Tutti i
+dettagli si trovano in @ref{Storia del linguaggio}.
+Il linguaggio descritto in questo @value{DOCUMENT}
+viene spesso citato come ``nuovo @command{awk}''.
+Per analogia, la versione originale di @command{awk} @`e citata
+come ``vecchio @command{awk}.''
+
+Su molti sistemi di uso corrente, eseguendo il programma di utilit@`a
+@command{awk}, si invoca qualche versione del nuovo
+@command{awk}.@footnote{Solo i sistemi Solaris usano ancora un
+vecchio @command{awk} per il programma di utilit@`a predefinito
+@command{awk}. Una versione pi@`u moderna di @command{awk} si trova
+nella directory @file{/usr/xpg6/bin} su questi sistemi.} Se
+il comando @command{awk} nel sistema in uso @`e il vecchio, il
+risultato che vedrete per il programma di test che segue @`e
+del tipo:
+
+@example
+$ @kbd{awk 1 /dev/null}
+@error{} awk: syntax error near line 1
+@error{} awk: bailing out near line 1
+@end example
+
+@noindent
+Se questo @`e il caso, dovreste cercare una versione del nuovo @command{awk},
+o semplicemente installare @command{gawk}!
+
+All'interno di questo @value{DOCUMENT}, quando si fa riferimento a
+funzionalit@`a del linguaggio che dovrebbe essere disponibile in ogni
+implementazione completa di @command{awk} POSIX, viene usato il termine
+@command{awk}. Quando si fa riferimento a una funzionalit@`a specifica
+dell'implementazione GNU, viene usato i termine @command{gawk}.
+
+@node Questo manuale
+@unnumberedsec Uso di questo @value{DOCUMENT}
+@cindex @command{awk}, descrizione dei termini
+
+Il termine @command{awk} si riferisce sia a uno specifico programma sia al
+linguaggio che si usa per dire al programma stesso cosa deve fare. Quando dobbiamo
+essere precisi, chiamiamo il linguaggio ``il linguaggio @command{awk},''
+e il programma ``l'utilit@`a @command{awk}.''
+Questo @value{DOCUMENT} spiega
+sia come scrivere programmi nel linguaggio @command{awk} che come
+eseguire l'utilit@`a @command{awk}.
+Il termine ``programma @command{awk}'' si riferisce a un programma scritto
+dall'utente nel linguaggio di programmazione @command{awk}.
+
+@cindex @command{gawk}, @command{awk} e
+@cindex @command{awk}, @command{gawk} e
+@cindex POSIX @command{awk}
+In primo luogo, questo @value{DOCUMENT} spiega le funzionalit@`a di @command{awk}
+come definite nello standard POSIX, e lo fa nel contesto dell'implementazione
+@command{gawk}. Oltre a questo, cerca anche di descrivere le differenze
+significative tra @command{gawk}
+e altre
+@ifclear FOR_PRINT
+implementazioni @command{awk}.@footnote{Tutte queste differenze
+si trovano nell'indice alla
+voce ``differenze tra @command{awk} e @command{gawk}.''}
+@end ifclear
+@ifset FOR_PRINT
+implementazioni @command{awk}.
+@end ifset
+Infine, vien fatta rilevare ogni funzionalit@`a di @command{gawk} non
+inclusa nello standard POSIX per @command{awk}.
+
+@ifnotinfo
+Questo @value{DOCUMENT} ha il difficile compito di essere tanto una guida
+introduttiva che un manuale di riferimento. I neofiti possono
+tranquillamente saltare i dettagli che sembrano loro troppo complessi.
+Possono anche ignorare i molti riferimenti incrociati, preparati avendo in
+mente gli utenti esperti e per le versioni Info e
+@uref{http://www.gnu.org/software/gawk/manual/, HTML}
+del @value{DOCUMENT}.
+@end ifnotinfo
+
+Ci sono dei riquadri
+sparsi in tutto il @value{DOCUMENT}.
+Aggiungono una spiegazione pi@`u completa su punti importanti, ma che
+probabilmente non sono di interesse in sede di prima lettura.
+@ifclear FOR_PRINT
+Si trovano tutti nell'indice analitico, alla voce ``sidebar.'' @c non c'e riquadro nell'indice analitico
+@end ifclear
+
+La maggior parte delle volte, gli esempi usano programmi @command{awk} completi.
+Alcune delle @value{SECTIONS} pi@`u avanzate mostrano solo la parte del programma
+@command{awk} che illustra il concetto che si sta descrivendo.
+
+Sebbene questo @value{DOCUMENT} sia destinato soprattutto alle persone che non
+hanno una precedente conoscenza di @command{awk}, esso contiene anche tante
+informazioni che anche gli esperti di @command{awk} troveranno utili.
+In particolare, dovrebbero essere d'interesse la descrizione di POSIX
+@command{awk} e i programmi di esempio
+@ifnottex
+in
+@end ifnottex
+@iftex
+nel
+@end iftex
+@ref{Funzioni di libreria} e
+@ifnotdocbook
+@ifnottex
+in
+@end ifnottex
+@end ifnotdocbook
+@iftex
+nel
+@end iftex
+@ref{Programmi di esempio}.
+
+Questo @value{DOCUMENT} @`e suddiviso in diverse parti, come segue:
+
+@c FULLXREF ON
+
+@itemize @value{BULLET}
+@item
+La Parte I descrive il linguaggio @command{awk} e il programma @command{gawk}
+nel dettaglio.
+Inizia con le nozioni di base, e continua con tutte le caratteristiche di
+@command{awk}. Contiene i seguenti capitoli:
+
+@c nested
+@itemize @value{MINUS}
+@item
+@ref{Per iniziare},
+fornisce le nozioni minime indispensabili per iniziare a usare @command{awk}.
+
+@item
+@ref{Invocare Gawk},
+descrive come eseguire @command{gawk}, il significato delle sue
+opzioni da riga di comando e come trovare i file sorgenti del programma
+@command{awk}.
+
+@item
+@ref{Espressioni regolari},
+introduce le espressioni regolari in generale, e in particolare le variet@`a
+disponibili in @command{awk} POSIX e @command{gawk}.
+
+@item
+@ref{Leggere file},
+descrive come @command{awk} legge i dati inseriti dall'utente.
+Introduce i concetti di record e campi, e anche il
+comando @code{getline}.
+Contiene una prima descrizione della ridirezione I/O, e una breve descrizione
+dell'I/O di rete.
+
+@item
+@ref{Stampare},
+descrive come i programmi @command{awk} possono produrre output con
+@code{print} e @code{printf}.
+
+@item
+@ref{Espressioni},
+descrive le espressioni, che sono i componenti elementari di base
+per portare a termine la maggior parte delle operazioni in un programma.
+
+@item
+@ref{Criteri di ricerca e azioni},
+descrive come scrivere espressioni di ricerca per individuare corrispondenze nei
+record, le azioni da eseguire quando si @`e trovata una corrispondenza
+in un record, e le variabili predefinite di @command{awk} e
+@command{gawk}.
+
+@item
+@ref{Vettori},
+tratta dell'unica struttura di dati di @command{awk}: il vettore associativo.
+Vengono trattati anche l'eliminazione di elementi del vettore e di interi
+vettori, e l'ordinamento dei vettori in @command{gawk}.
+Il @value{CHAPTER} descrive inoltre come @command{gawk} fornisce vettori di
+vettori.
+
+@item
+@ref{Funzioni},
+descrive le funzioni predefinite fornite da @command{awk} e
+@command{gawk}, e spiega come definire funzioni personalizzate. Viene
+anche spiegato come @command{gawk} permetta di invocare funzioni in
+maniera indiretta.
+@end itemize
+
+@item
+La Parte II illustra come usare @command{awk} e @command{gawk} per la
+risoluzione di problemi. Qui ci sono molti programmi da leggere e da cui imparare.
+Questa parte contiene i seguenti capitoli:
+
+@c nested
+@itemize @value{MINUS}
+@item
+@ref{Funzioni di libreria},
+fornisce diverse funzioni pensate per
+essere usate dai programmi scritti in @command{awk}.
+
+@item
+@ref{Programmi di esempio},
+fornisce molti programmi @command{awk} di esempio.
+@end itemize
+
+La lettura di questi due capitoli permette di capire come
+@command{awk} pu@`o risolvere problemi pratici.
+
+@item
+La Parte III si concentra sulle funzionalit@`a specifiche di @command{gawk}.
+Contiene i seguenti capitoli:
+
+@c nested
+@itemize @value{MINUS}
+@item
+@ref{Funzionalit@`a avanzate},
+descrive diverse funzionalit@`a avanzate.
+Di particolare rilevanza sono
+la capacit@`a di controllare l'ordine di visita dei vettori,
+quella di instaurare comunicazioni bidirezionali con altri processi,
+di effettuare connessioni di rete TCP/IP, e di
+profilare i propri programmi @command{awk}.
+
+@item
+@ref{Internazionalizzazione},
+descrive funzionalit@`a speciali per tradurre i messaggi
+di programma in diverse lingue in fase di esecuzione.
+
+@item
+@ref{Debugger}, descrive il debugger di @command{gawk}.
+
+@item
+@ref{Calcolo con precisione arbitraria},
+illustra le capacit@`a di calcolo avanzate.
+
+@item
+@ref{Estensioni dinamiche},
+descrive come aggiungere nuove variabili e
+funzioni a @command{gawk} scrivendo estensioni in C o C++.
+@end itemize
+
+@item
+@ifclear FOR_PRINT
+La Parte IV contiene le appendici, il Glossario, e due licenze relative,
+rispettivamente, al codice sorgente di @command{gawk} e a questo
+@value{DOCUMENT}. Contiene le seguenti appendici:
+@end ifclear
+
+@ifset FOR_PRINT
+La Parte IV contiene le seguenti appendici,
+che includono la Licenza per Documentazione Libera GNU:
+@end ifset
+
+@itemize @value{MINUS}
+@item
+@ref{Storia del linguaggio},
+descrive l'evoluzione del linguaggio @command{awk} dalla sua prima versione
+fino a oggi. Descrive anche come @command{gawk}
+ha acquisito nuove funzionalit@`a col passare del tempo.
+
+@item
+@ref{Installazione},
+descrive come ottenere @command{gawk}, come compilarlo
+sui sistemi compatibili con POSIX,
+e come compilarlo e usarlo su diversi sistemi
+non conformi allo standard POSIX. Spiega anche come segnalare gli errori
+di @command{gawk} e dove si possono ottenere altre implementazioni
+di @command{awk} liberamente disponibili.
+
+@ifset FOR_PRINT
+@item
+@ref{Copia},
+presenta la licenza applicabile al codice sorgente @command{gawk}.
+@end ifset
+
+@ifclear FOR_PRINT
+@item
+@ref{Note},
+descrive come disabilitare le estensioni @command{gawk},
+come contribuire scrivendo del nuovo codice per @command{gawk},
+e alcune possibili direzioni per il futuro sviluppo di @command{gawk}.
+
+@item
+@ref{Concetti fondamentali},
+fornisce del materiale di riferimento a livello elementare per chi
+sia completamente digiuno di programmazione informatica.
+
+Il @ref{Glossario}, definisce quasi tutti i termini significativi
+usati all'interno di questo @value{DOCUMENT}. Se si incontrano termini
+coi quali non si ha familiarit@`a, questo @`e il posto dove cercarli.
+
+@item
+@ref{Copia}, e
+@ref{Licenza per Documentazione Libera GNU (FDL)},
+presentano le licenze che si applicano, rispettivamente, al codice sorgente
+di @command{gawk} e a questo @value{DOCUMENT}.
+@end ifclear
+@end itemize
+@end itemize
+
+@ifset FOR_PRINT
+La versione di questo @value{DOCUMENT} distribuita con @command{gawk}
+contiene ulteriori appendici e altro materiale.
+Per ragioni di spazio, per questa edizione a stampa abbiamo tralasciato alcune
+delle appendici. Si possono trovare in rete ai seguenti indirizzi:
+
+@itemize @value{BULLET}
+@item
+@uref{http://www.gnu.org/software/gawk/manual/html_node/Notes.html,
+L'appendice sulle note di implementazione}
+descrive come disabilitare le estensioni @command{gawk}, come contribuire
+scrivendo del nuovo codice per @command{gawk}, dove reperire informazioni
+su alcune possibili future direzioni dello sviluppo di @command{gawk}, e
+sulle decisioni di progetto che hanno influito sulle estensioni API.
+
+@item
+@uref{http://www.gnu.org/software/gawk/manual/html_node/Basic-Concepts.html,
+L'appendice sui concetti fondamentali}
+fornisce del materiale di riferimento a livello elementare per chi sia completamente a
+digiuno di programmazione informatica.
+
+@item
+@uref{http://www.gnu.org/software/gawk/manual/html_node/Glossary.html,
+Il Glossario}
+definisce la maggior parte, se non tutti, i termini significativi usati
+nel corso del libro. Se si incontrano termini con cui non si ha familiarit@`a,
+questo @`e il posto dove cercarli.
+
+@item
+@uref{http://www.gnu.org/software/gawk/manual/html_node/GNU-Free-Documentation-License.html, la licenza GNU FDL}
+@`e la licenza che vale per questo @value{DOCUMENT}.
+@end itemize
+
+@c ok not to use CHAPTER / SECTION here
+Alcuni dei capitoli hanno sezioni con esercizi; queste sono anche
+state omesse dall'edizione a stampa ma sono disponibili online.
+@end ifset
+
+@c FULLXREF OFF
+
+@node Convenzioni
+@unnumberedsec Convenzioni tipografiche
+
+@cindex Texinfo
+Questo @value{DOCUMENT} @`e scritto in @uref{http://www.gnu.org/software/texinfo/, Texinfo},
+il linguaggio di formattazione della documentazione GNU. Viene usato un unico
+file sorgente Texinfo per produrre sia la versione a stampa della documentazione
+sia quella online.
+@ifnotinfo
+A causa di ci@`o, le convenzioni tipografiche
+sono leggermente diverse da quelle presenti in altri libri che potete aver letto.
+@end ifnotinfo
+@ifinfo
+Questo @value{SECTION} documenta brevemente le convenzioni tipografiche usate in Texinfo.
+@end ifinfo
+
+Gli esempi da immettere sulla riga di comando sono preceduti dai
+comuni prompt di shell primario e secondario, @samp{$} e @samp{>}.
+L'input che si inserisce viene mostrato @kbd{in questo modo}.
+@c 8/2014: @print{} is stripped from the texi to make docbook.
+@ifclear FOR_PRINT
+L'output del comando @`e preceduto dal glifo ``@print{}'', che
+in genere rappresenta lo standard output del comando.
+@end ifclear
+@ifset FOR_PRINT
+L'output del comando, normalmente il suo standard output, @`e stampato
+@code{in questo modo}.
+@end ifset
+Messaggi di errore e altri output sullo standard error del comando sono
+preceduti dal glifo ``@error{}''. Per esempio:
+
+@example
+$ @kbd{echo ciao su stdout}
+@print{} ciao su stdout
+$ @kbd{echo salve su stderr 1>&2}
+@error{} salve su stderr
+@end example
+
+@ifnotinfo
+Nel testo, quasi tutto ci@`o che riguarda la programmazione,
+per esempio i nomi dei comandi,
+appare in @code{questo font}. I frammenti
+di codice appaiono nello stesso font e tra apici, @samp{in questo modo}.
+Ci@`o che viene sostituito dall'utente o dal programmatore
+appare in @var{questo font}.
+Le opzioni sono stampate cos@`{@dotless{i}}: @option{-f}.
+I @value{FNS} sono indicati in questo modo: @file{/percorso/al/file}.
+@ifclear FOR_PRINT
+Certe cose sono
+evidenziate @emph{in questo modo}, e se un punto dev'essere reso in modo pi@`u
+marcato, viene evidenziato @strong{in questo modo}.
+@end ifclear
+La prima occorrenza di un
+nuovo termine @`e usualmente la sua @dfn{definizione} e appare nello stesso
+font della precedente occorrenza di ``definizione'' in questa frase.
+@end ifnotinfo
+
+I caratteri che si battono sulla tastiera sono scritti come @kbd{questi}. In
+particolare, ci sono caratteri speciali chiamati ``caratteri di controllo''.
+Questi sono caratteri che vengono battuti tenendo premuti il tasto
+@kbd{CONTROL} e un altro tasto contemporaneamente.
+Per esempio, @kbd{Ctrl-d} @`e battuto premendo e tenendo premuto il tasto
+@kbd{CONTROL}, poi premendo il tasto @kbd{d} e infine rilasciando entrambi i
+tasti.
+
+Per amor di brevit@`a, in questo @value{DOCUMENT}, la versione di Brian
+Kernighan di @command{awk} sar@`a citata come ``BWK @command{awk}.''
+(@xref{Altre versioni} per informazioni su questa e altre versioni.)
+
+@ifset FOR_PRINT
+@quotation NOTA
+Note interessanti sono stampate in questo modo.
+@end quotation
+
+@quotation ATTENZIONE
+Note di avviso o raccomandazioni di cautela sono stampate in questo modo.
+@end quotation
+@end ifset
+
+@c fakenode --- for prepinfo
+@unnumberedsubsec Angoli Bui
+@cindex Kernighan, Brian
+@quotation
+@i{Gli angoli bui sono essenzialmente frattali---per quanto vengano
+illuminati, ce n'@`e sempre uno pi@`u piccolo e pi@`u buio.}
+@author Brian Kernighan
+@end quotation
+
+@cindex a.b., si veda angolo buio
+@cindex angolo buio
+Fino allo standard POSIX (e @cite{@value{TITLE}}),
+molte caratteristiche di @command{awk} erano poco documentate o
+non documentate affatto. Le descrizioni di queste caratteristiche
+(chiamate spesso ``angoli bui'') sono segnalate in questo @value{DOCUMENT} con
+@iftex
+il disegno di una torcia elettrica nel margine, come mostrato qui.
+@value{DARKCORNER}
+@end iftex
+@ifnottex
+``(a.b.)''.
+@end ifnottex
+@ifclear FOR_PRINT
+Appaiono anche nell'indice sotto la voce ``angolo buio.''
+@end ifclear
+
+Ma come osservato nella citazione d'apertura, ogni trattazione degli
+angoli bui @`e per definizione incompleta.
+
+@cindex e.c., si veda estensioni comuni
+Estensioni al linguaggio standard di @command{awk} disponibili in pi@`u di una
+implementazione di @command{awk} sono segnate
+@ifclear FOR_PRINT
+``@value{COMMONEXT},'' ed elencate nell'indice sotto ``estensioni comuni''
+e ``comuni, estensioni''.
+@end ifclear
+@ifset FOR_PRINT
+``@value{COMMONEXT}'' per ``estensioni comuni.''
+@end ifset
+
+@node Storia del manuale
+@unnumberedsec Breve storia del Progetto GNU e di questo @value{DOCUMENT}
+
+@cindex FSF (Free Software Foundation)
+@cindex Free Software Foundation (FSF)
+@cindex Stallman, Richard
+La Free Software Foundation (FSF) @`e un'organizzazione senza scopo di lucro
+dedita alla produzione e distribuzione di software liberamente distribuibile.
+@`E stata fondata da Richard M.@: Stallman, l'autore della prima versione
+dell'editor Emacs. GNU Emacs @`e oggi la versione di Emacs pi@`u largamente usata.
+
+@cindex Progetto GNU
+@cindex GNU, Progetto
+@cindex GPL (General Public License)
+@cindex General Public License, si veda GPL
+@cindex documentazione, online
+Il Progetto GNU@footnote{GNU sta per ``GNU's Not Unix.''}
+@`e un progetto della Free Software
+Foundation in continuo sviluppo per creare un ambiente per computer completo, liberamente
+distribuibile, conforme allo standard POSIX.
+La FSF usa la GNU General Public License (GPL) per assicurare che
+il codice sorgente del loro software sia sempre
+disponibile all'utente finale.
+@ifclear FOR_PRINT
+Una copia della GPL @`e inclusa
+@ifnotinfo
+in questo @value{DOCUMENT}
+@end ifnotinfo
+per la consultazione
+(@pxref{Copia}).
+@end ifclear
+La GPL si applica al codice sorgente in linguaggio C per @command{gawk}.
+Per saperne di pi@`u sulla FSF e sul Progetto GNU,
+si veda @uref{http://www.gnu.org, la pagina principale del Progetto GNU}.
+Questo @value{DOCUMENT} si pu@`o leggere anche dal
+@uref{http://www.gnu.org/software/gawk/manual/, sito di GNU}.
+
+@ifclear FOR_PRINT
+Una shell, un editor (Emacs), compilatori ottimizzanti C, C++ e
+Objective-C altamente portabili, un debugger simbolico e dozzine di grandi e
+piccoli programmi di utilit@`a (come @command{gawk}), sono stati completati e
+sono liberamente disponibili. Il kernel del sistema operativo GNU (noto come
+HURD), @`e stato rilasciato ma @`e ancora allo stato di sviluppo iniziale.
+
+@cindex Linux
+@cindex GNU/Linux
+@cindex sistemi operativi basati su BSD
+In attesa che il sistema operativo GNU venga pi@`u completatamente
+sviluppato, si dovrebbe prendere in considerazione l'uso di GNU/Linux, un
+sistema operativo liberamente distribuibile e basato su Unix disponibile
+per Intel, Power Architecture,
+Sun SPARC, IBM S/390, e altri
+sistemi.@footnote{La terminologia ``GNU/Linux'' @`e spiegata
+nel @ref{Glossario}.}
+Molte distribuzioni GNU/Linux sono
+scaricabili da internet.
+@end ifclear
+
+@ifnotinfo
+Il @value{DOCUMENT} @`e realmente libero---almeno, l'informazione che contiene
+@`e libera per chiunque---. Il codice sorgente del @value{DOCUMENT}, leggibile
+elettronicamente, viene fornito con @command{gawk}.
+@ifclear FOR_PRINT
+(Dare un'occhiata alla Free Documentation
+License in @ref{Licenza per Documentazione Libera GNU (FDL)}.)
+@end ifclear
+@end ifnotinfo
+
+@cindex Close, Diane
+Il @value{DOCUMENT} in s@'e ha gi@`a avuto parecchie edizioni in passato.
+Paul Rubin ha scritto la prima bozza di @cite{The GAWK Manual};, che era
+lunga una quarantina di pagine.
+Diane Close e Richard Stallman l'hanno migliorata arrivando alla
+versione che era
+lunga una novantina di pagine, e descriveva solo la versione originale
+``vecchia'' di @command{awk}.
+Ho iniziato a lavorare con quella versione nell'autunno del 1988.
+Mentre ci stavo lavorando,
+la FSF ha pubblicato parecchie versioni preliminari, numerate 0.@var{x}).
+Nel 1996, l'edizione 1.0 fu rilasciata assieme a @command{gawk} 3.0.0.
+La FSF ha pubblicato le prime due edizioni col
+titolo @cite{GAWK: The GNU Awk User's Guide}.
+@ifset FOR_PRINT
+SSC ha pubblicato due edizioni del @value{DOCUMENT} col
+titolo @cite{Effective awk Programming}, e O'Reilly ha pubblicato
+la terza edizione nel 2001
+@end ifset
+
+Questa edizione mantiene la struttra di base delle edizioni precedenti.
+Per l'edizione FSF 4.0, il contenuto era stato accuratamente rivisto
+e aggiornato. Tutti i riferimenti a versioni di @command{gawk} anteriori alla
+versione 4.0 sono stati eliminati.
+Di particolare interesse in quella edizione era l'aggiunta del @ref{Debugger}.
+
+Per l'edizione FSF
+@ifclear FOR_PRINT
+@value{EDITION},
+@end ifclear
+@ifset FOR_PRINT
+@value{EDITION}
+(la quarta edizione, come pubblicata da O'Reilly),
+@end ifset
+il contenuto @`e stato riorganizzato in parti,
+e le aggiunte pi@`u importanti sono
+@iftex
+il
+@end iftex
+@ref{Calcolo con precisione arbitraria}, e
+@iftex
+il
+@end iftex
+@ref{Estensioni dinamiche}.
+
+Questo @value{DOCUMENT} continuer@`a certamente ad evolversi. Se si trovano
+errori nel @value{DOCUMENT}, si prega di segnalarli! @xref{Bug}
+per informazioni su come inviare le segnalazione di problemi elettronicamente.
+@ifset FOR_PRINT
+@node Restare aggiornati
+@unnumberedsec Come restare aggiornati
+
+Potreste avere una versione di @command{gawk} pi@`u recente di quella
+descritta qui. Per vedere cosa @`e cambiato,
+dovreste prima guardare il file @file{NEWS} nella distribuzione di
+@command{gawk}, che fornisce un sommario ad alto livello dei
+cambiamenti in ciascuna versione.
+
+You can then look at the @uref{http://www.gnu.org/software/gawk/manual/,
+online version} of this @value{DOCUMENT} to read about any new features.
+@end ifset
+
+@ifclear FOR_PRINT
+@node Come contribuire
+@unnumberedsec Come collaborare
+
+Come manutentore di GNU @command{awk}, un tempo pensai che sarei stato in grado
+di gestire una raccolta di programmi @command{awk} pubblicamente disponibili e
+avevo anche esortato a collaborare. Rendere disponibili le cose su Internet
+aiuta a contenere la distribuzione @command{gawk} entro dimensioni gestibili.
+
+L'iniziale raccolta di materiale, come questo, @`e tuttora disponibile
+su @uref{ftp://ftp.freefriends.org/arnold/Awkstuff}.
+
+Chi fosse @emph{seriamente} interessato a contribuire nell'implementazione
+di un sito Internet dedicato ad argomenti riguardanti il
+linguaggio @command{awk}, @`e pregato di contattarmi.
+
+@ignore
+Nella speranza di
+fare qualcosa di pi@`u esteso, acquisii il dominio @code{awk.info}.
+
+Tuttavia, mi accorsi che non potevo dedicare abbastanza tempo per la gestione
+del codice inviato dai collaboratori: l'archivio non cresceva e il dominio
+rimase in disuso per diversi anni.
+
+Alla fine del 2008, un volontario si assunse il compito di mettere a punto
+un sito web collegato ad @command{awk}---@uref{http://awk.info}---e fece un
+lavoro molto ben fatto.
+
+Se qualcuno ha scritto un programma @command{awk} interessante, o un'estensione
+a @command{gawk} che vuole condividere col resto del mondo, @`e invitato a
+consultare la pagina @uref{http://awk.info/?contribute} per sapere come
+inviarlo per contribuire al sito web.
+
+Mentre scrivo, questo sito @`e in cerca di un responsabile; se qualcuno @`e
+interessato mi contatti.
+@end ignore
+
+@ignore
+Altri collegamenti:
+
+http://www.reddit.com/r/linux/comments/dtect/composing_music_in_awk/
+@end ignore
+@end ifclear
+
+@node Ringraziamenti
+@unnumberedsec Ringraziamenti
+
+La bozza iniziale di @cite{The GAWK Manual} riportava i seguenti ringraziamenti:
+
+@quotation
+Molte persone devono essere ringraziate per la loro assistenza nella produzione
+di questo manuale. Jay Fenlason ha contribuito con molte idee e programmi di
+esempio. Richard Mlynarik e Robert Chassell hanno fatto utili osservazioni
+sulle bozze di questo manuale. Lo scritto
+@cite{A Supplemental Document for AWK} di John W.@: Pierce, del
+Chemistry Department di UC San Diego, fa il punto su diverse questioni rilevanti
+sia per l'implementazione di @command{awk} che per questo manuale, che
+altrimenti ci sarebbero sfuggite.
+@end quotation
+
+@cindex Stallman, Richard
+Vorrei ringraziare Richard M.@: Stallman, per la sua visione di un mondo
+migliore e per il suo coraggio nel fondare la FSF e nel dare inizio al
+Progetto GNU.
+
+@ifclear FOR_PRINT
+Edizioni precedenti di questo @value{DOCUMENT} riportavano i seguenti
+ringraziamenti:
+@end ifclear
+@ifset FOR_PRINT
+La precedente edizione di questo @value{DOCUMENT} riportava
+i seguenti ringraziamenti:
+@end ifset
+
+@quotation
+Le seguenti persone (in ordine alfabetico)
+hanno inviato commenti utili riguardo alle diverse
+versioni di questo libro:
+Rick Adams,
+Dr.@: Nelson H.F. Beebe,
+Karl Berry,
+Dr.@: Michael Brennan,
+Rich Burridge,
+Claire Cloutier,
+Diane Close,
+Scott Deifik,
+Christopher (``Topher'') Eliot,
+Jeffrey Friedl,
+Dr.@: Darrel Hankerson,
+Michal Jaegermann,
+Dr.@: Richard J.@: LeBlanc,
+Michael Lijewski,
+Pat Rankin,
+Miriam Robbins,
+Mary Sheehan,
+e
+Chuck Toporek.
+
+@cindex Berry, Karl
+@cindex Chassell, Robert J.@:
+@c @cindex Texinfo
+Robert J.@: Chassell ha dato preziosissimi consigli
+sull'uso di Texinfo.
+Merita anche un particolare ringraziamento per avermi
+convinto a @emph{non} dare a questo @value{DOCUMENT}
+il titolo @cite{How to Gawk Politely}. [Un gioco di parole in inglese che pu@`o
+significare sia
+@cite{Come usare Gawk educatamente}
+che @cite{Come curiosare educatamente}].
+Karl Berry ha aiutato in modo significativo con la parte @TeX{} di Texinfo.
+
+@cindex Hartholz, Marshall
+@cindex Hartholz, Elaine
+@cindex Schreiber, Bert
+@cindex Schreiber, Rita
+Vorrei ringraziare Marshall ed Elaine Hartholz di Seattle e il Dr.@: Bert e Rita
+Schreiber di Detroit per i lunghi periodi di vacanza trascorsi in tutta
+tranquillit@`a in casa loro, che mi hanno permesso di fare importanti progressi
+nella scrittura di questo @value{DOCUMENT} e con lo stesso @command{gawk}.
+
+@cindex Hughes, Phil
+Phil Hughes di SSC
+ha contribuito in modo molto importante prestandomi il suo portatile col sistema
+GNU/Linux, non una volta, ma due, il che mi ha permesso di fare tantissimo lavoro
+mentre ero fuori casa.
+
+@cindex Trueman, David
+David Trueman merita un riconoscimento speciale; ha fatto un lavoro da sentinella
+durante lo sviluppo di @command{gawk} affinch@'e funzioni bene e senza errori.
+Sebbene non sia pi@`u impegnato con @command{gawk},
+lavorare con lui a questo progetto @`e stato un vero piacere.
+
+@cindex Drepper, Ulrich
+@cindex GNITS mailing list
+@cindex mailing list, GNITS
+Gli intrepidi membri della lista GNITS, con una particolare menzione per Ulrich
+Drepper, hanno fornito un aiuto prezioso e commenti per il progetto
+delle funzionalit@`a di internazionalizzazione.
+
+Chuck Toporek, Mary Sheehan, e Claire Cloutier della O'Reilly & Associates hanno
+fornito un'assistenza editoriale rilevante per questo @value{DOCUMENT} per la
+versione 3.1 di @command{gawk}.
+@end quotation
+
+@cindex Beebe, Nelson H.F.@:
+@cindex Buening, Andreas
+@cindex Collado, Manuel
+@cindex Colombo, Antonio
+@cindex Davies, Stephen
+@cindex Deifik, Scott
+@cindex Demaille, Akim
+@cindex G., Daniel Richard
+@cindex Hankerson, Darrel
+@cindex Jaegermann, Michal
+@cindex Kahrs, J@"urgen
+@cindex Kasal, Stepan
+@cindex Malmberg, John E.
+@cindex Pitts, Dave
+@cindex Ramey, Chet
+@cindex Rankin, Pat
+@cindex Schorr, Andrew
+@cindex Vinschen, Corinna
+@cindex Zaretskii, Eli
+
+Dr.@: Nelson Beebe,
+Andreas Buening,
+Dr.@: Manuel Collado,
+Antonio Colombo,
+Stephen Davies,
+Scott Deifik,
+Akim Demaille,
+Daniel Richard G.,
+Darrel Hankerson,
+Michal Jaegermann,
+J@"urgen Kahrs,
+Stepan Kasal,
+John Malmberg,
+Dave Pitts,
+Chet Ramey,
+Pat Rankin,
+Andrew Schorr,
+Corinna Vinschen,
+ed Eli Zaretskii
+(in ordine alfabetico)
+costituiscono l'attuale ``gruppo di lavoro sulla portabilit@`a'' di
+@command{gawk}. Senza il loro duro lavoro e il loro aiuto,
+@command{gawk} non sarebbe stato neanche lontanamente il buon programma che @`e
+oggi. @`E stato e continua a essere un piacere lavorare con questo gruppo
+di ottimi collaboratori.
+
+Notevoli contributi di codice e documentazione sono arrivati da
+parecchie persone. @xref{Contributori} per l'elenco completo.
+
+@ifset FOR_PRINT
+@cindex Oram, Andy
+Grazie ad Andy Oram della O'Reilly Media per aver iniziato
+la quarta edizione e per il suo aiuto in corso d'opera.
+Grazie a Jasmine Kwityn per il suo lavoro di revisione.
+@end ifset
+
+Grazie a Michael Brennan per le Prefazioni.
+
+@cindex Duman, Patrice
+@cindex Berry, Karl
+Grazie a Patrice Dumas per il nuovo programma @command{makeinfo}.
+Grazie a Karl Berry, che continua a lavorare per tenere
+aggiornato il linguaggio di marcatura Texinfo.
+
+@cindex Kernighan, Brian
+@cindex Brennan, Michael
+@cindex Day, Robert P.J.@:
+Robert P.J.@: Day, Michael Brennan e Brian Kernighan hanno gentilmente
+fatto da revisiori per l'edizione 2015 di questo @value{DOCUMENT}. Le loro
+osservazioni hanno contribuito a migliorare la stesura finale.
+
+Vorrei ringraziare Brian Kernighan per la sua preziosa assistenza durante
+la fase di collaudo e di debug di @command{gawk} e
+per l'aiuto in corso d'opera e i consigli nel chiarire diversi punti sul
+linguaggio. Non avremmo proprio fatto un cos@`{@dotless{i}} buon lavoro su @command{gawk} e
+sulla sua documentazione senza il suo aiuto.
+
+Brian @`e un fuoriclasse sia come programmatore che come autore di manuali
+tecnici. @`E mio dovere ringraziarlo (una volta di pi@`u) per la sua costante
+amicizia e per essere stato per me un modello da seguire ormai da quasi
+30 anni! Averlo come revisiore @`e per me un privilegio eccitante, ma @`e
+stata anche un'esperienza che mi ha fatto sentire molto piccolo@enddots{}
+
+@cindex Robbins, Miriam
+@cindex Robbins, Jean
+@cindex Robbins, Harry
+@cindex D-o
+Devo ringraziare la mia meravigliosa moglie, Miriam, per la sua pazienza nel
+corso delle molte versioni di questo progetto, per la correzione delle bozze e
+per aver condiviso con me il computer.
+Vorrei ringraziare i miei genitori per il loro amore, e per la gentilezza con cui
+mi hanno cresciuto ed educato.
+Infine, devo riconoscere la mia gratitudine a D-o, per le molte opportunit@`a
+che mi ha offerto, e anche per i doni che mi ha elargito, con cui trarre
+vantaggio da quelle opportunit@`a.
+@ifnotdocbook
+@sp 2
+@noindent
+Arnold Robbins @*
+Nof Ayalon @*
+Israel @*
+Febbraio 2015
+@end ifnotdocbook
+
+@ifnotinfo
+@part @value{PART1}Il Linguaggio @command{awk}
+@end ifnotinfo
+
+@ifdocbook
+@part Il Linguaggio @command{awk}
+
+La Parte I descrive il linguaggio @command{awk} e il programma @command{gawk}
+nel dettaglio. Inizia con le nozioni di base, e continua con tutte le
+funzionalit@`a di @command{awk}. Sono incluse anche molte, ma non tutte, le
+funzionalit@`a di @command{gawk}. Questa parte contiene i
+seguenti capitoli:
+
+@itemize @value{BULLET}
+@item
+@ref{Per iniziare}
+
+@item
+@ref{Invocare Gawk}
+
+@item
+@ref{Espressioni regolari}
+
+@item
+@ref{Leggere file}
+
+@item
+@ref{Stampare}
+
+@item
+@ref{Espressioni}
+
+@item
+@ref{Modelli e azioni}
+
+@item
+@ref{Vettori}
+
+@item
+@ref{Funzioni}
+@end itemize
+@end ifdocbook
+@node Per iniziare
+@chapter Per iniziare con @command{awk}
+@c @cindex @dfn{script}, definizione di
+@c @cindex rule, definizione di
+@c @cindex program, definizione di
+@c @cindex basic function of @command{awk}
+@cindex @command{awk}, funzione di
+
+Il compito fondamentale di @command{awk} @`e quello di ricercare righe (o
+altre unit@`a di testo) in file che corrispondano a certi criteri di ricerca.
+Quando una riga corrisponde a uno dei criteri, @command{awk} esegue su
+quella riga le azioni specificate per quel criterio. @command{awk} continua
+a elaborare righe in input in questo modo, finch@'e non raggiunge la fine delle
+righe nei file in input.
+
+@cindex @command{awk}, uso di
+@cindex linguaggi di programmazione@comma{} guidati-dai-dati/procedurali
+@cindex @command{awk}, programmi
+I programmi scritti in @command{awk} sono differenti dai programmi scritti
+nella maggior parte degli altri linguaggi,
+poich@'e i programmi @command{awk} sono @dfn{guidati dai dati} (ovvero,
+richiedono di descrivere i dati sui quali si vuole operare, e in seguito
+che cosa fare una volta che tali dati siano stati individuati).
+La maggior parte degli altri linguaggi sono @dfn{procedurali}; si deve
+descrivere, in maniera molto dettagliata, ogni passo che il programma
+deve eseguire. Lavorando con linguaggi procedurali, solitamente @`e
+molto pi@`u difficile descrivere chiaramente i dati che il programma
+deve elaborare.
+Per questa ragione i programmi @command{awk} sono spesso piacevolmente
+facili da leggere e da scrivere.
+
+@cindex programma, definizione di
+@cindex regola, definizione di
+Quando si esegue @command{awk}, va specificato un
+@dfn{programma} @command{awk} che
+dice ad @command{awk} cosa fare. Il programma consiste di una serie di
+@dfn{regole} (pu@`o anche contenere @dfn{definizioni di funzioni},
+una funzionalit@`a avanzata che per ora ignoreremo;
+@pxref{Funzioni definite dall'utente}). Ogni regola specifica un
+criterio di ricerca e un'azione da effettuare
+una volta che viene trovato un record corrispondente.
+
+Sintatticamente, una regola consiste in un @dfn{criterio di ricerca}, seguito
+da una @dfn{azione}.
+L'azione @`e racchiusa tra parentesi graffe per separarla dal criterio di
+ricerca.
+Per separare regole, basta andare a capo. Quindi un programma
+@command{awk} ha una struttura simile a questa:
+
+@example
+@var{criterio} @{ @var{azione} @}
+@var{criterio} @{ @var{azione} @}
+@dots{}
+@end example
+
+@menu
+* Eseguire gawk:: Come iniziare a eseguire programmi
+ @command{gawk}; comprende la sintassi
+ della riga di comando.
+* File dati di esempio:: File di dati di esempio da usare nei
+ programmi @command{awk} illustrati in
+ questo @value{DOCUMENT}.
+* Molto semplice:: Un esempio molto semplice.
+* Due regole:: Un esempio meno semplice di programma
+ di una riga, che usa due regole.
+* Maggiore sofisticazione:: Un esempio pi@`u complesso.
+* Istruzioni/Righe:: Suddividere o riunire istruzioni
+ su [una o pi@`u] righe.
+* Altre funzionalit@`a:: Altre funzionalit@`a di @command{awk}.
+* Quando:: Quando usare @command{gawk} e quando
+ usare altre cose.
+* Sommario dell'introduzione:: Sommario dell'introduzione.
+@end menu
+
+@node Eseguire gawk
+@section Come iniziare a eseguire programmi @command{gawk}
+
+@cindex programmi @command{awk}, eseguire
+Ci sono vari modi di eseguire un programma @command{awk}. Se il programma @`e
+corto, @`e pi@`u facile includerlo nel comando con cui si invoca @command{awk},
+cos@`{@dotless{i}}:
+
+@example
+awk '@var{programma}' @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@cindex riga di comando, formati
+Quando il programma @`e lungo, di solito @`e meglio metterlo in un file
+ed eseguirlo con un comando come questo:
+
+@example
+awk -f @var{file-di-programma} @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} si occupa di entrambe queste modalit@`a insieme
+a parecchie varianti di ciascuna di esse.
+
+@menu
+* Monouso:: Eseguire un breve programma
+ @command{awk} di tipo usa-e-getta.
+* Leggere dal terminale:: Senza uso di file in input (input
+ immesso da tastiera).
+* Lunghi:: Mettere programmi @command{awk}
+ permanenti in file.
+* @dfn{Script} eseguibili:: Preparare programmi @command{awk}
+ da eseguire come @dfn{script}.
+* Commenti:: Aggiungere documentazione a programmi
+ @command{gawk}.
+* Protezione:: Ulteriore discussione di problemi
+ connessi all'uso di apici nella shell.
+@end menu
+
+@node Monouso
+@subsection Eseguire un breve programma @command{awk} usa-e-getta
+
+Una volta acquisita familiarit@`a con @command{awk}, capiter@`a spesso di
+preparare semplici
+programmi nel momento in cui servono. In questo caso si pu@`o scrivere
+il programma come primo argomento del comando @command{awk}, cos@`{@dotless{i}}:
+
+@example
+awk '@var{programma}' @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@noindent
+dove @var{programma} consiste in una serie di criteri di ricerca e di
+azioni, come descritto precedentemente.
+
+@cindex apice singolo (@code{'})
+@cindex @code{'} (apice singolo)
+Questo formato di comando chiede alla @dfn{shell}, ossia all'interpretatore
+dei comandi, di richiamare @command{awk} e di usare il @var{programma} per
+trattare record nei file in input.
+Il @var{programma} @`e incluso tra apici in modo che
+la shell non interpreti qualche carattere destinato ad @command{awk} come
+carattere speciale
+della shell. Gli apici fanno inoltre s@`{@dotless{i}} che la shell tratti tutto il
+@var{programma} come un solo argomento per @command{awk}, e permettono che
+@var{programma} sia pi@`u lungo di una riga.
+
+@cindex shell, @dfn{script}
+@cindex programmi @command{awk}, eseguire, da @dfn{script} di shell
+Questo formato @`e utile anche per eseguire programmi @command{awk} di
+dimensioni piccole o medie da @dfn{script} di shell, perch@'e non richiede
+un file separato che contenga il programma @command{awk}. Uno @dfn{script}
+di shell @`e pi@`u affidabile, perch@'e non ci sono altri file che possono
+venirsi a trovare fuori posto.
+
+Pi@`u avanti in questo capitolo,
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ifdocbook
+@value{SECTION}
+@end ifdocbook
+@ref{Molto semplice},
+si vedranno esempi di parecchi programmi,
+brevi, scritti sulla riga di comando.
+
+@node Leggere dal terminale
+@subsection Senza uso di file in input (input immesso da tastiera)
+
+@cindex standard input
+@cindex input, standard
+@cindex file in input, eseguire @command{awk} senza usarli
+Si pu@`o anche eseguire @command{awk} senza indicare alcun file in input. Se
+si immette la seguente riga di comando:
+
+@example
+awk '@var{programma}'
+@end example
+
+@noindent
+@command{awk} prende come input del @var{programma} lo @dfn{standard input},
+che di solito significa qualsiasi cosa venga immesso dalla tastiera.
+Ci@`o prosegue finch@'e non si segnala una fine-file battendo @kbd{Ctrl-d}.
+(In sistemi operativi non-POSIX, il carattere di fine-file pu@`o essere diverso.)
+
+@cindex input, file in, si veda file in input
+@cindex file in input, eseguire @command{awk} senza usarli
+@cindex programmi @command{awk}, eseguire, senza file in input
+Per esempio, il seguente programma stampa un consiglio da amico
+(dalla @cite{Guida galattica per gli autostoppisti} di Douglas Adams ),
+per non lasciarsi spaventare dalle complessit@`a della programmazione per
+computer:
+
+@example
+$ @kbd{awk 'BEGIN @{ print "Non v\47allarmate!" @}'}
+@print{} Non v'allarmate!
+@end example
+
+@command{awk} esegue le istruzioni associate a @code{BEGIN} prima di leggere
+qualsiasi input. Se non ci sono altre istruzioni nel proprio programma, come
+in questo caso, @command{awk} si ferma, invece di tentare di leggere input che
+non sa come elaborare.
+Il @samp{\47} @`e un modo straordinario (spiegato pi@`u avanti) per inserire un
+apice singolo nel programma, senza dover ricorrere a fastidiosi meccanismi
+di protezione della shell.
+
+@quotation NOTA
+Se si usa Bash come shell, si dovrebbe digitare il comando @samp{set +H} prima
+eseguire questo programma interattivamente, per non avere una cronologia dei
+comandi nello stile della C shell, che tratta il @samp{!} come un carattere
+speciale. Si raccomanda di inserire quel comando nel proprio file di
+personalizzazione della shell.
+@end quotation
+
+Il seguente semplice programma @command{awk}
+emula il comando @command{cat}; ovvero copia qualsiasi cosa si
+batta sulla tastiera nel suo standard output (perch@'e succede @`e spiegato fra
+poco):
+
+@example
+$ @kbd{awk '@{ print @}'}
+@kbd{Ora @`e il tempo per tutti gli uomini buoni}
+@print{} Ora @`e il tempo per tutti gli uomini buoni
+@kbd{di venire in aiuto al loro paese.}
+@print{} di venire in aiuto al loro paese.
+@kbd{Or sono sedici lustri e sette anni, ...}
+@print{} Or sono sedici lustri e sette anni, ...
+@kbd{Cosa, io preoccupato?}
+@print{} Cosa, io preoccupato?
+@kbd{Ctrl-d}
+@end example
+
+@node Lunghi
+@subsection Eseguire programmi lunghi
+
+@cindex programmi @command{awk}, eseguire
+@cindex programmi @command{awk}, lunghi
+@cindex file, programmi @command{awk} in
+Talora i programmi @command{awk} sono molto lunghi. In tali situazioni
+conviene mettere il programma in un file separato. Per dire ad
+@command{awk} di usare quel file come programma, digitare:
+
+@example
+awk -f @var{file-sorgente} @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@cindex @option{-f}, opzione
+@cindex riga di comando, opzione @option{-f}
+L'opzione @option{-f} dice al comando @command{awk} di ottenere il programma
+@command{awk} dal file @var{file-sorgente} (@pxref{Opzioni}).
+Ogni @value{FN} pu@`o essere usato come @var{file-sorgente}. Per esempio, si
+potrebbe mettere il programma:
+
+@example
+BEGIN @{ print \"Non v'allarmate!\" @}
+@end example
+
+@noindent
+nel file @file{consiglio}. Allora questo comando:
+
+@example
+awk -f consiglio
+@end example
+
+@noindent
+@`e equivalente al comando:
+
+@example
+awk 'BEGIN @{ print \"Non v\47allarmate!\" @}'
+@end example
+
+@cindex protezione, nella riga di comando di @command{gawk}
+@noindent
+Questo @`e gi@`a stato spiegato prima
+(@pxref{Leggere dal terminale}).
+Si noti che normalmente non serve mettere apici singoli nel @value{FN} che si
+fornisce con @option{-f}, perch@'e di solito i @value{FNS} non contengono
+caratteri che sono speciali per la shell. Si noti che in @file{consiglio},
+il programma @command{awk} non ha dei doppi apici che lo delimitano. I
+doppi apici sono necessari solo per programmi scritti direttamente sulla riga
+di comando di @command{awk}.
+(Inoltre, se il programma si trova in un file, @`e possibile usare un apice
+singolo all'interno del programma, invece del magico @samp{\47}.)
+
+@cindex apice singolo (@code{'}), nella riga di comando di @command{gawk}
+@cindex @code{'} (apice singolo), nella riga di comando di @command{gawk}
+Per identificare chiaramente un file di programma @command{awk} come tale,
+si pu@`o aggiungere il suffisso @file{.awk} al @value{FN}. Ci@`o non
+cambia l'esecuzione del programma @command{awk} ma semplifica
+la ``manutenzione''.
+
+@node @dfn{Script} eseguibili
+@subsection Programmi @command{awk} da eseguire come @dfn{script}
+@cindex programmi @command{awk}
+@cindex @code{#} (cancelletto), @code{#!} (@dfn{script} eseguibili)
+@cindex Unix, @dfn{script} @command{awk} e
+@cindex cancelletto (@code{#}), @code{#!} (@dfn{script} eseguibili)
+
+Una volta familiarizzato con @command{awk}, si potrebbero scrivere
+@dfn{script} che richiamano @command{awk}, usando il meccanismo di
+@dfn{script} @samp{#!}. Ci@`o @`e
+possibile in molti sistemi operativi.@footnote{Il meccanismo @samp{#!}
+funziona nei sistemi
+GNU/Linux, in quelli basati su BSD e nei sistemi Unix a pagamento.}
+Per esempio, si potrebbe modificare il file @file{consiglio} e farlo divenire:
+
+@example
+#! /bin/awk -f
+
+BEGIN @{ print \"Non v'allarmate!\" @}
+@end example
+
+@noindent
+Dopo aver reso eseguibile questo file (con il comando @command{chmod}),
+digitare semplicemente @samp{consiglio}
+al prompt della shell e il sistema si preparer@`a a eseguire @command{awk}
+come se si fosse digitato @samp{awk -f consiglio}:
+
+@example
+$ @kbd{chmod +x consiglio}
+$ @kbd{consiglio}
+@print{} Non v'allarmate!
+@end example
+
+@noindent
+(Si suppone che la directory corrente sia tra quelle contenute nella variabile
+che indica il "percorso" di ricerca [solitamente @code{$PATH}]. In caso
+contrario si potrebbe aver bisogno di digitare @samp{./consiglio} nella
+shell.)
+
+@dfn{Script} @command{awk} autocontenuti sono utili se si vuol scrivere un
+programma che gli utenti possono richiamare senza dover essere informati che
+il programma @`e scritto in @command{awk}.
+
+@sidebar Comprendere @samp{#!}
+@cindex portabilit@`a, @code{#!} (@dfn{script} eseguibili)
+
+@command{awk} @`e un linguaggio @dfn{interpretato}. Ci@`o significa che il
+comando @command{awk} legge il programma dell'utente e poi elabora i dati
+secondo le istruzioni contenute nel programma (diversamente da un linguaggio
+@dfn{compilato} come il C, dove il programma viene prima compilato in codice
+macchina che @`e eseguito direttamente dal processore del sistema). Il
+programma di utilit@`a @command{awk} @`e perci@`o chiamato @dfn{interpretatore}.
+Molti linguaggi moderni sono interpretati.
+
+La riga che inizia con @samp{#!} lista l'intero @value{FN} di un
+interpretatore
+da richiamare, con degli argomenti facoltativi che saranno passati a
+quell'interpretatore sulla riga di comando. Il sistema operativo quindi
+richiama l'interpretatore con gli argomenti dati e con l'intera lista di
+argomenti con cui era stato invocato il programma. Il primo argomento nella
+lista @`e l'intero @value{FN} del programma @command{awk}. Il resto della lista
+degli argomenti contiene opzioni per @command{awk}, oppure @value{DF}, o
+entrambi. (Si noti che in molti sistemi @command{awk} pu@`o essere trovato in
+@file{/usr/bin} invece che in @file{/bin}.)
+
+Alcuni sistemi limitano la lunghezza del nome del programma interpretarore a
+32 caratteri. Spesso, si pu@`o rimediare utilizzando un collegamento simbolico.
+
+Non si dovrebbero mettere altri argomenti oltre al primo nella riga @samp{#!}
+dopo il percorso del comando @command{awk}. Non funziona. Il sistema
+operativo tratta il resto della riga come un argomento solo, e lo passa ad
+@command{awk}.
+Cos@`{@dotless{i}} facendo il comportamento sar@`a poco chiaro; con ogni probabilit@`a un
+messaggio di errore di qualche tipo da @command{awk}.
+
+@cindex variabili @code{ARGC}/@code{ARGV}, portabilit@`a e
+@cindex portabilit@`a, variabile @code{ARGV}
+Infine, il valore di @code{ARGV[0]}
+(@pxref{Variabili predefinite})
+pu@`o variare a seconda del sistema operativo.
+Alcuni sistemi ci mettono @samp{awk}, altri il nome completo del percorso
+di @command{awk} (ad. es. @file{/bin/awk}), e altri ancora mettono il nome
+dello @dfn{script} dell'utente (@samp{consiglio}). @value{DARKCORNER}
+Non bisogna fidarsi del valore di @code{ARGV[0]}
+per ottenere il nome del proprio @dfn{script}.
+@end sidebar
+
+@node Commenti
+@subsection Documentare programmi @command{gawk}.
+@cindex @code{#} (cancelletto), commentare
+@cindex cancelletto (@code{#}), commentare
+@cindex commentare
+@cindex programmi @command{awk}, documentazione
+
+Un @dfn{commento} @`e del testo incluso in un programma per aiutare le
+persone che lo leggeranno; non @`e parte del programma eseguibile vero e
+proprio. I commenti possono spiegare cosa fa il programma e come funziona.
+Quasi tutti i linguaggi di programmazione possono contenere commenti, poich@'e
+i programmi sono solitamente difficili da comprendere senza di essi.
+
+Nel linguaggio @command{awk}, un commento inizia con il segno del
+cancelletto (@samp{#}) e continua fino alla fine della riga.
+Il @samp{#} non deve necessariamente essere il primo carattere della riga.
+Il linguaggio @command{awk} ignora il resto di una riga dopo il carattere
+cancelletto.
+Per esempio, potremmo mettere quel che segue in @file{consiglio}:
+
+@example
+# Questo programma stampa uno scherzoso consiglio amichevole.
+# Aiuta a far passare la paura del computer agli utenti novelli.
+BEGIN @{ print "Non v'allarmate!" @}
+@end example
+
+Si possono mettere dei commenti nei programmi @command{awk} usa-e-getta da
+digitare direttamente da tastiera, ma ci@`o solitmanete non serve molto; il
+fine di un commento @`e di aiutare l'utente o qualcun altro a comprendere il
+programma, quando lo rilegge in un secondo tempo.
+
+@cindex protezione, per piccoli programmi awk
+@cindex apice singolo (@code{'}), vs.@: apostrofo
+@cindex @code{'} (apice singolo), vs.@: apostrofo
+@quotation ATTENZIONE
+Come detto in
+@ref{Monouso},
+si possono includere programmi di dimensioni da piccole a medie tra apici
+singoli, per mantenere compatti i propri @dfn{script} di shell
+autocontenuti. Nel far questo, @emph{non} bisogna inserire un apostrofo
+(ossia un apice singolo) in un commento, (o in qualsiasi altra parte del
+vostro programma). La shell interpreta gli apici singoli come delimitatori
+di chiusura dell'intero programma. Di conseguenza, solitamente la shell
+emette un messaggio riguardo ad apici presenti in numero dispari, e se
+@command{awk} viene comunque eseguito, @`e probabile che stampi strani
+messaggi di errori di sintassi.
+Per esempio, nel caso seguente:
+
+@example
+$ @kbd{awk 'BEGIN @{ print "Ciao" @} # un'idea brillante'}
+>
+@end example
+
+La shell considera il secondo apice singolo come delimitatore del testo
+precedente, e trova che un nuovo testo tra apici ha inizio verso la fine
+della riga di comando. A causa di ci@`o emette una richiesta secondaria di
+input, e si mette in attesa di ulteriore input.
+Con il comando @command{awk} Unix, se si chiude l'ulteriore stringa tra
+apici singoli il risultato @`e il seguente:
+
+@example
+$ @kbd{awk '@{ print "Ciao" @} # un'idea brillante'}
+> @kbd{'}
+@error{} awk: fatale: non riesco ad aprire file `brillante'
+@error{} in lettura (File o directory non esistente)
+@end example
+
+@cindex @code{\} (barra inversa)
+@cindex barra inversa (@code{\})
+Mettere una barra inversa prima dell'apice singolo in @samp{un'idea} non
+risolverebbe, poich@'e le barre inverse non sono speciali all'interno di apici
+singoli.
+La prossima @value{SUBSECTION} descrive le regole di protezione della shell.
+@end quotation
+
+@node Protezione
+@subsection Uso di apici nella shell.
+@cindex shell, uso di apici, regole per
+
+@menu
+* Doppi apici in DOS:: Passaggio di apici in file .BAT Windows.
+@end menu
+
+Per programmi @command{awk} di lunghezza da corta a media spesso conviene
+digitare il programma sulla riga di comando @command{awk}.
+La maniera migliore per farlo @`e racchiudere l'intero programma tra apici
+singoli.
+Questo vale sia che si digiti il programma interattivamente su
+richiesta della shell, sia che lo si scriva come parte di uno @dfn{script}
+di shell di maggiori dimensioni:
+
+@example
+awk '@var{testo del programma}' @var{input-file1} @var{input-file2} @dots{}
+@end example
+
+@cindex shell, uso di apici, regole per
+@cindex Bourne shell, uso di apici, regole per la
+Quando si lavora con la shell, non guasta avere una conoscenza
+di base sulle regole per l'uso di apici nella shell. Le regole
+seguenti valgono solo per shell in stile Bourne (come Bash, la
+Bourne-Again shell). Se si usa la C shell, si avranno regole differenti.
+
+Prima di immergerci nelle regole, introduciamo un concetto che ricorre
+in tutto questo @value{DOCUMENT}, che @`e quello della stringa @dfn{null},
+o vuota.
+
+La stringa nulla @`e una variabile, di tipo carattere, che non ha un valore.
+In altre parole, @`e vuota. Nei programmi @command{awk} si scrive cos@`{@dotless{i}}:
+@code{""}. Nella shell la si pu@`o scrivere usando apici sia singoli
+che doppi: @code{""} oppure @code{''}. Sebbena la stringa nulla non contenga
+alcun carattere, essa esiste lo stesso. Si consideri questo comando:
+
+@example
+$ @kbd{echo ""}
+@end example
+
+@noindent
+Qui, il comando @command{echo} riceve un solo argomento, anche se
+quell'argomento non contiene alcun carattere. Nel resto di questo
+@value{DOCUMENT}, usiamo indifferentemente i termini @dfn{stringa nulla}
+e @dfn{stringa vuota}. Ora, proseguiamo con le regole relative agli apici:
+
+
+@itemize @value{BULLET}
+@item
+Elementi tra apici possono essere concatenati con elementi non tra apici.
+La shell converte il tutto in un singolo argomento da passare
+al comando.
+
+@item
+Mettere una barra inversa (@samp{\}) prima di qualsiasi singolo carattere
+lo protegge. La shell toglie la barra inversa e passa il carattere
+protetto al comando.
+
+@item
+@cindex @code{\} (barra inversa), nei comandi di shell
+@cindex barra inversa (@code{\}), nei comandi di shell
+@cindex apice singolo (@code{'}), nei comandi di shell
+@cindex @code{'} (apice singolo), nei comandi di shell
+Gli apici singoli proteggono qualsiasi cosa sia inclusa tra un apice di
+apertura e uno di chiusura.
+La shell non interpreta il testo protetto, il quale viene passato cos@`{@dotless{i}} com'@`e
+al comando.
+@`E @emph{impossibile} inserire un apice singolo in un testo racchiuso fra
+apici singoli. Potete trovare in
+@ref{Commenti}
+un esempio di cosa succede se si prova a farlo.
+
+@item
+@cindex doppio apice (@code{"}), nei comandi shell
+@cindex @code{"} (doppio apice), nei comandi shell
+I doppi apici proteggono la maggior parte di quel che @`e racchiuso tra i
+doppi apici di apertura e quelli di chiusura.
+La shell effettua almeno la sostituzione di variabili e di comandi
+sul testo racchiuso tra doppi apici.
+Shell differenti possono fare ulteriori tipi di elaborazione
+sul testo racchiuso tra doppi apici.
+
+Poich@'e alcuni caratteri all'interno di un testo racchiuso tra doppi apici
+sono interpretati dalla shell, essi devono essere @dfn{protetti} all'interno
+del testo stesso. Sono da tener presenti i caratteri
+@samp{$}, @samp{`}, @samp{\}, e @samp{"}, tutti i quali devono essere
+preceduti da una barra inversa quando ricorrono all'interno di un testo
+racchiuso tra doppi apici, per poter essere passati letteralmente al
+programma. (La barra inversa viene tolta prima del passaggio al programma.)
+Quindi, l'esempio visto
+@ifnotinfo
+precedentemente
+@end ifnotinfo
+in @ref{Leggere dal terminale}:
+
+@example
+awk 'BEGIN @{ print "Non v\47allarmate!" @}'
+@end example
+
+@noindent
+si potrebbe scrivere invece cos@`{@dotless{i}}:
+
+@example
+$ @kbd{awk "BEGIN @{ print \"Non v'allarmate!\" @}"}
+@print{} Non v'allarmate!
+@end example
+
+@cindex apice singolo (@code{'}), con doppio apice
+@cindex @code{'} (apice singolo), con doppio apice
+Va notato che l'apice singolo non @`e speciale all'interno di un testo
+racchiuso tra doppi apici.
+
+@item
+Le stringhe nulle sono rimosse se presenti come parte di un argomento
+non-nullo sulla riga di comando, mentre oggetti esplicitamente nulli
+sono mantenuti come tali.
+Per esempio, per richiedere che il separatore di campo @code{FS} sia
+impostato alla stringa nulla, digitare:
+
+@example
+awk -F "" '@var{programma}' @var{file} # corretto
+@end example
+
+@noindent
+@cindex stringa nulla come argomento a @command{gawk}, protezione della
+Non @`e invece da usare:
+
+@example
+awk -F"" '@var{programma}' @var{file} # errato!
+@end example
+
+@noindent
+Nel secondo caso, @command{awk} tenta di usare il nome del programma come
+valore di @code{FS}, e il primo @value{FN} come testo del programma!
+Ci@`o come minimo genera un errore di sintassi, e un comportamento confuso nel
+caso peggiore.
+@end itemize
+
+@cindex protezione, nella riga di comando di @command{gawk}, trucchi per
+Mischiare apici singoli e doppi @`e difficile. Occorre utilizzare
+trucchi della shell per gli apici, come questi:
+
+@example
+$ @kbd{awk 'BEGIN @{ print "Questo @`e un apice singolo. <'"'"'>" @}'}
+@print{} Questo @`e un apice singolo. <'>
+@end example
+
+@noindent
+Questo programma stampa tre stringhe tra apici concatenate tra loro.
+La prima e la terza sono rinchiuse tra apici singoli, la seconda tra apici
+doppi.
+
+Quanto sopra pu@`o essere ``semplificato'' cos@`{@dotless{i}}:
+
+@example
+$ @kbd{awk 'BEGIN @{ print "Questo @`e un apice singolo <'\''>" @}'}
+@print{} Questo @`e un apice singolo <'>
+@end example
+
+@noindent
+A voi la scelta del pi@`u leggibile dei due.
+
+Un'altra opzione @`e quella di usare doppi apici, proteggendo i doppi apici
+inclusi, a livello @command{awk}:
+
+@example
+$ @kbd{awk "BEGIN @{ print \"Questo @`e un apice singolo <'>\" @}"}
+@print{} Questo @`e un apice singolo <'>
+@end example
+
+@noindent
+Quest'opzione @`e fastidiosa anche perch@'e il doppio apice, la barra inversa e
+il simbolo del dollaro sono molto comuni nei programmi @command{awk} pi@`u
+avanzati.
+
+Una terza opzione @`e quella di usare le sequenze ottali equivalenti
+(@pxref{Sequenze di protezione})
+per i caratteri
+apice singolo e doppio, cos@`{@dotless{i}}:
+
+@example
+$ @kbd{awk 'BEGIN @{ print "Questo @`e un apice singolo <\47>" @}'}
+@print{} Questo @`e un apice singolo <'>
+$ @kbd{awk 'BEGIN @{ print "Questo @`e un doppio apice <\42>" @}'}
+@print{} Questo @`e un doppio apice <">
+@end example
+
+@noindent
+Questo funziona bene, ma sai dovrebbe commentare chiaramente quel che
+il testo protetto significa.
+
+Una quarta possibilit@`a @`e di usare assegnamenti di variabili sulla riga di
+comando, cos@`{@dotless{i}}:
+
+@example
+@kbd{$ awk -v sq="'" 'BEGIN @{ print "Questo @`e un apice singolo <" sq ">" @}'}
+@print{} Questo @`e un apice singolo <'>
+@end example
+
+(Qui, le due stringhe costanti e il valore di @code{sq} sono concatenati in
+un'unica stringa che @`e stampata da @code{print}.)
+
+Se servono veramente sia gli apici singoli che quelli doppi nel proprio
+programma @command{awk}, @`e probabilmente meglio tenerlo in un file separato,
+dove la shell non interferisce, e si potr@`a scrivere quello che si vuole.
+
+@node Doppi apici in DOS
+@subsubsection Doppi apici in file .BAT Windows
+
+@ignore
+Date: Wed, 21 May 2008 09:58:43 +0200 (CEST)
+From: jeroen.brink@inter.NL.net
+Subject: (g)awk "contribution"
+To: arnold@skeeve.com
+Message-id: <42220.193.172.132.34.1211356723.squirrel@webmail.internl.net>
+
+Hello Arnold,
+
+maybe you can help me out. Found your email on the GNU/awk online manual
+pages.
+
+I've searched hard to figure out how, on Windows, to print double quotes.
+Couldn't find it in the Quotes area, nor on google or elsewhere. Finally i
+figured out how to do this myself.
+
+How to print all lines in a file surrounded by double quotes (on Windows):
+
+gawk "{ print \"\042\" $0 \"\042\" }" <file>
+
+Maybe this is a helpfull tip for other (Windows) gawk users. However, i
+don't have a clue as to where to "publish" this tip! Do you?
+
+Kind regards,
+
+Jeroen Brink
+@end ignore
+
+Sebbene questo @value{DOCUMENT} in generale si preoccupi solo di sistemi POSIX
+e della shell POSIX, il problema che stiamo per vedere emerge abbastanza
+spesso presso parecchi utenti, e per questo ne parliamo.
+
+@cindex Brink, Jeroen
+Le ``shell'' nei sistemi Microsoft Windows usaso il carattere doppio apice
+per protezione, e rendono difficile o impossibile inserire un carattere
+doppio apice in uno @dfn{script} scritto su una riga di comando.
+l'esempio che segue, per il quale ringraziamo Jeroen Brink, mostra come
+stampare tutte le righe di un file, racchiudendole tra doppi apici:
+
+@example
+gawk "@{ print \"\042\" $0 \"\042\" @}" @var{file}
+@end example
+
+
+@node File dati di esempio
+@section @value{DDF} per gli esempi
+
+@cindex input file, esempi
+@cindex file di @code{mail-list}
+Molti degli esempi in questo @value{DOCUMENT} hanno come input due @value{DF}
+di esempio. Il primo, @file{mail-list}, contiene una lista di nomi di
+persone, insieme ai loro indirizzi email e a informazioni riguardanti le
+persone stesse.
+Il secondo @value{DF}, di nome @file{inventory-shipped}, contiene
+informazioni riguardo a consegne mensili. In entrambi i file,
+ogni riga @`e considerata come un @dfn{record}.
+
+Nel @file{mail-list}, ogni record contiene il nome di una persona,
+il suo numero di telefono, il suo indirizzo email, e un codice che indica
+la sua relazione con l'autore della lista.
+Le colonne sono allineate usando degli spazi.
+Una @samp{A} nell'ultima colonna indica che quella persona @`e un conoscente
+[Acquaintance]. Una @samp{F} nell'ultima colonna significa che quella
+persona @`e un amico [Friend]. Una @samp{R} vuol dire che quella persona @`e
+un parente [Relative]:
+
+@example
+@c system if test ! -d eg ; then mkdir eg ; fi
+@c system if test ! -d eg/lib ; then mkdir eg/lib ; fi
+@c system if test ! -d eg/data ; then mkdir eg/data ; fi
+@c system if test ! -d eg/prog ; then mkdir eg/prog ; fi
+@c system if test ! -d eg/misc ; then mkdir eg/misc ; fi
+@c file eg/data/mail-list
+Amelia 555-5553 amelia.zodiacusque@@gmail.com F
+Anthony 555-3412 anthony.asserturo@@hotmail.com A
+Becky 555-7685 becky.algebrarum@@gmail.com A
+Bill 555-1675 bill.drowning@@hotmail.com A
+Broderick 555-0542 broderick.aliquotiens@@yahoo.com R
+Camilla 555-2912 camilla.infusarum@@skynet.be R
+Fabius 555-1234 fabius.undevicesimus@@ucb.edu F
+Julie 555-6699 julie.perscrutabor@@skeeve.com F
+Martin 555-6480 martin.codicibus@@hotmail.com A
+Samuel 555-3430 samuel.lanceolis@@shu.edu A
+Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R
+@c endfile
+@end example
+
+@cindex file @code{inventory-shipped}
+Il @value{DF} @file{inventory-shipped} contiene
+informazioni sulle consegne effettuate durante l'anno.
+Ogni record contiene il mese, il numero di contenitori verdi spediti,
+il numero di scatole rosse spedite, il numero di borse arancione spedite,
+e il numero di pacchetti blu spediti, in quest'ordine.
+Ci sono 16 record, relativi ai dodici mesi dello scorso anno e ai primi
+quattro mesi dell'anno in corso.
+Una riga vuota separa i data relativi a ciascun anno:
+
+@example
+@c file eg/data/inventory-shipped
+Jan 13 25 15 115
+Feb 15 32 24 226
+Mar 15 24 34 228
+Apr 31 52 63 420
+May 16 34 29 208
+Jun 31 42 75 492
+Jul 24 34 67 436
+Aug 15 34 47 316
+Sep 13 55 37 277
+Oct 29 54 68 525
+Nov 20 87 82 577
+Dec 17 35 61 401
+
+Jan 21 36 64 620
+Feb 26 58 80 652
+Mar 24 75 70 495
+Apr 21 70 74 514
+@c endfile
+@end example
+
+Questi file di esempio sono inclusi nella distribuzione @command{gawk},
+nella directory @file{awklib/eg/data}.
+
+@node Molto semplice
+@section Alcuni esempi molto semplici
+
+I seguenti comandi eseguono un semplice programma @command{awk} che cerca
+nel file in input @file{mail-list} la stringa di caratteri @samp{li} (una
+sequenza di caratteri @`e solitamente chiamato una @dfn{stringa};
+il termine @dfn{stringa} @`e basato su un uso linguistico, del tipo
+``una stringa di perle'' o ``una stringa di luci decorative''):
+
+@example
+awk '/li/ @{ print $0 @}' mail-list
+@end example
+
+@noindent
+Quando si incontra una riga che contiene @samp{li}, la si stampa, perch@'e
+@w{@samp{print $0}} significa "stampa la riga corrente". (Lo scrivere solo
+@samp{print} ha lo stesso significato, quindi avremmo anche potuto
+limitarci a fare cos@`{@dotless{i}}).
+
+Si sar@`a notato che delle barre (@samp{/}) delimitano la stringa @samp{li}
+nel programma @command{awk}. Le barre indicano che @samp{li} @`e il
+modello da ricercare. Questo tipo di notazione @`e definita come
+@dfn{espressione regolare}, e sar@`a trattata pi@`u avanti in maggior dettaglio
+@iftex
+(@pxrefil{Espressioni regolari}).
+@end iftex
+@ifnottex
+(@pxref{Espressioni regolari}).
+@end ifnottex
+Il modello pu@`o corrispondere anche solo a una parte di una parola.
+Ci sono
+apici singoli che racchiudono il programma @command{awk} in modo che la
+shell non interpreti alcuna parte di esso come un carattere speciale della
+shell.
+
+Questo @`e quello che il programma stampa:
+
+@example
+$ @kbd{awk '/li/ @{ print $0 @}' mail-list}
+@print{} Amelia 555-5553 amelia.zodiacusque@@gmail.com F
+@print{} Broderick 555-0542 broderick.aliquotiens@@yahoo.com R
+@print{} Julie 555-6699 julie.perscrutabor@@skeeve.com F
+@print{} Samuel 555-3430 samuel.lanceolis@@shu.edu A
+@end example
+
+@cindex azioni, default
+@cindex criteri di ricerca, default
+In una regola @command{awk}, il criterio di selezione o l'azione possono
+essere omessi, ma non entrambi. Se il criterio @`e omesso, l'azione viene
+applicata a @emph{ogni} riga dell'input.
+Se l'azione viene omessa, per default si stampano tutte le righe che
+sono individuate dal criterio di selezione.
+
+@cindex azioni, omesse
+Quindi, si potrebbe omettere l'azione (l'istruzione @code{print} e le
+graffe) nell'esempio precedente e il risultato sarebbe lo stesso:
+@command{awk} stampa tutte le righe che corrispondono al criterio di
+ricerca @samp{li}. Per confronto, omettendo l'istruzione @code{print} ma
+lasciando le graffe si richiede un'azione nulla, che non fa nulla (cio@`e non
+stampa alcuna riga).
+
+@cindex programmi @command{awk}, esempi molto corti
+Molti programmi @command{awk} pratici sono lunghi solo una o due righe.
+Qui sotto troviamo una collezione di programmi utili e corti, per iniziare.
+Alcuni di questi programmi contengono elementi del linguaggio che non sono
+ancora stati spiegati. (La descrizione del programma fornisce una buona
+idea di quel che si vuole ottenere, ma occorre leggere il resto del
+@value{DOCUMENT} per divenire esperti in @command{awk}!)
+Molti degli esempi usano un @value{DF} di nome @file{data}. Questo serve solo
+a indicare la posizione del nome; se questi programmi devono venir usati per
+se stessi, sostituire i propri @value{FNS} al posto di @file{data}.
+Per futura memoria, si noti che spesso c'@`e pi@`u di un modo per fare qualcosa
+in @command{awk}. In un altro momento, si potrebbe tornare a guardare questi
+esempi per vedere se si riescono a trovare modi differenti per fare le stesse
+cose mostrate qui appresso:
+
+@itemize @value{BULLET}
+@item
+Stampare ogni riga lunga pi@`u di 80 caratteri:
+
+@example
+awk 'length($0) > 80' data
+@end example
+
+L'unica regola presente ha un'espressione di relazione come modello
+e non ha azione---quindi applica l'azione di default, stampando il record.
+
+@item
+Stampare la lunghezza della riga in input pi@`u lunga:
+
+@example
+awk '@{ if (length($0) > max) max = length($0) @}
+ END @{ print max @}' data
+@end example
+
+Il codice associato a @code{END} viene eseguito dopo che tutto
+l'input @`e stato letto; @`e l'altra faccia della medaglia di @code{BEGIN}.
+
+@cindex programma @command{expand}
+@cindex @command{expand}, programma
+@item
+Stampare la lunghezza della riga pi@`u lunga in @file{data}:
+
+@example
+expand data | awk '@{ if (x < length($0)) x = length($0) @}
+ END @{ print "la lunghezza massima di una riga @`e" x @}'
+@end example
+
+Questo esempio @`e leggermente diverso da quello precedente:
+l'input @`e l'output del comando @command{expand}, che cambia i TAB
+in spazi, in modo che le larghezze confrontate siano quelle che sarebbero
+qualora le si stampasse, e non il numero dei caratteri di input su ogni
+riga. [il carattere TAB occupa un byte nel file, ma pu@`o generare fino a
+otto spazi bianchi in fase di stampa.]
+
+@item
+Stampare ogni riga che abbia almeno un campo:
+
+@example
+awk 'NF > 0' data
+@end example
+
+Questa @`e una maniera facile per eliminare le righe vuote dal file (o
+piuttosto, per creare un nuovo file, simile al vecchio, ma nel quale le
+linee vuote sono state tolte).
+
+@item
+Stampare sette numeri casuali compresi tra 0 e 100, inclusi:
+
+@example
+awk 'BEGIN @{ for (i = 1; i <= 7; i++)
+ print int(101 * rand()) @}'
+@end example
+
+@item
+Stampare il numero totale di byte usato da un @var{elenco-file}:
+
+@example
+ls -l @var{elenco-file} | awk '@{ x += $5 @}
+ END @{ print "byte totali: " x @}'
+@end example
+
+@item
+Stampare il numero totale di kilobyte usati da @var{elenco-file}:
+
+@c Don't use \ continuation, not discussed yet
+@c Remember that awk does floating point division,
+@c no need for (x+1023) / 1024
+@example
+ls -l @var{elenco-file} | awk '@{ x += $5 @}
+ END @{ print "K-byte totali:", x / 1024 @}'
+@end example
+
+@item
+Stampare una lista in ordine alfabetico di tutti gli utenti del sistema
+[Unix]:
+
+@example
+awk -F: '@{ print $1 @}' /etc/passwd | sort
+@end example
+
+@item
+Contare le righe in un file:
+
+@example
+awk 'END @{ print NR @}' data
+@end example
+
+@item
+Stampare le righe pari nel @value{DF}:
+
+@example
+awk 'NR % 2 == 0' data
+@end example
+
+Se aveste usato invece l'espressione @samp{NR % 2 == 1},
+il programma avrebbe stampato le righe dispari.
+@end itemize
+
+@node Due regole
+@section Un esempio che usa due regole
+@cindex programmi @command{awk}
+
+Il programma @command{awk} legge il file in input una riga alla volta.
+Per ogni riga @command{awk} controlla la corrispondenza con ogni regola.
+Se viene trovata pi@`u di una corrispondenza, vengono eseguite altrettante
+azioni, nell'ordine in cui appaiono nel programma @command{awk}.
+Se non viene trovata nessuna corrispondenza, non viene eseguita alcuna azione.
+
+Dopo aver elaborato tutte le regole che hanno corrispondenza con la riga (e
+pu@'o darsi che nessuna corrisponda), @command{awk} legge la riga successiva. Comunque
+@pxref{Istruzione next},
+@ifdocbook
+e @ref{Istruzione Nextfile}.)
+@end ifdocbook
+@ifnotdocbook
+e anche @pxref{Istruzione nextfile}.)
+@end ifnotdocbook
+Si prosegue cos@`{@dotless{i}} finch@'e il programma raggiunge la fine del file.
+Per esempio, il seguente programma @command{awk} contiene due regole:
+
+@example
+/12/ @{ print $0 @}
+/21/ @{ print $0 @}
+@end example
+
+@noindent
+La prima regola ha la stringa @samp{12} da cercare e
+@samp{print $0} come
+azione. La seconda regola ha la
+stringa @samp{21} da cercare e ha ancora @samp{print $0} come azione.
+L'azione di ciascuna regola @`e racchiusa in una coppia di parentesi graffe.
+
+Questo programma stampa ogni riga che contiene la stringa
+@samp{12} @emph{oppure} la stringa @samp{21}. Se una riga contiene entrambe
+le stringhe, @`e stampata due volte, una volta per ogni regola.
+
+Questo @`e ci@`o che capita se eseguiamo questo programma sui nostri @value{DF},
+@file{mail-list} e @file{inventory-shipped}:
+
+@example
+$ @kbd{awk '/12/ @{ print $0 @}}
+> @kbd{/21/ @{ print $0 @}' mail-list inventory-shipped}
+@print{} Anthony 555-3412 anthony.asserturo@@hotmail.com A
+@print{} Camilla 555-2912 camilla.infusarum@@skynet.be R
+@print{} Fabius 555-1234 fabius.undevicesimus@@ucb.edu F
+@print{} Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R
+@print{} Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R
+@print{} Jan 21 36 64 620
+@print{} Apr 21 70 74 514
+@end example
+
+@noindent
+Si noti che la riga che inizia con @samp{Jean-Paul}
+nel file @file{mail-list}
+@`e stata stampata due volte, una volta per ogni regola.
+
+@node Maggiore sofisticazione
+@section Un esempio pi@`u complesso
+
+Dopo aver imparato a eseguire alcuni semplici compiti, vediamo cosa possono
+fare i tipici programmi @command{awk}.
+Questo esempio mostra come @command{awk} pu@`o essere usato per riassumere,
+selezionare e riordinare l'output di un altro comando. Sono usate
+funzionalit@`a di cui non si @`e ancora parlato, quindi non ci si deve preoccupare
+se alcuni dettagli risulteranno oscuri:
+
+@example
+ls -l | awk '$6 == "Nov" @{ somma += $5 @}
+ END @{ print somma @}'
+@end example
+
+@cindex comando @command{ls}
+Questo comando stampa il numero totale di byte in tutti i file contenuti
+nella directory corrente, la cui data di modifica @`e novembre (di qualsiasi
+anno). La parte @w{@samp{ls -l}} dell'esempio @`e un comando di sistema che
+fornisce un elenco dei file in una directory, con anche la dimensione di
+ogni file e la data di ultima modifica. Il suo output @`e del tipo:
+
+@example
+-rw-r--r-- 1 arnold user 1933 Nov 7 13:05 Makefile
+-rw-r--r-- 1 arnold user 10809 Nov 7 13:03 awk.h
+-rw-r--r-- 1 arnold user 983 Apr 13 12:14 awk.tab.h
+-rw-r--r-- 1 arnold user 31869 Jun 15 12:20 awkgram.y
+-rw-r--r-- 1 arnold user 22414 Nov 7 13:03 awk1.c
+-rw-r--r-- 1 arnold user 37455 Nov 7 13:03 awk2.c
+-rw-r--r-- 1 arnold user 27511 Dec 9 13:07 awk3.c
+-rw-r--r-- 1 arnold user 7989 Nov 7 13:03 awk4.c
+@end example
+
+@noindent
+@cindex continuazione di riga, nella C shell
+Il primo campo contiene le autorizzazioni di lettura/scrittura [r/w], il
+secondo il numero dei collegamenti al file [cio@`e il numero di nomi con cui
+il file @`e conosciuto], e il terzo campo identifica il proprietario del file.
+Il quarto campo identifica il gruppo a cui appartiene il file.
+Il quinto campo contiene la dimensione del file, in byte.
+Il sesto, settimo e ottavo campo contengono il mese, il giorno e l'ora,
+rispettivamente, in cui il file @`e stato modificato. Infine, il nono campo
+contiene il @value{FN}.
+
+@c @cindex automatic initialization
+@cindex inizializzazione automatica
+L'espressione @samp{$6 == "Nov"} nel nostro programma @command{awk} controlla
+se il sesto campo dell'output di @w{@samp{ls -l}} corrisponda alla stringa
+@samp{Nov}. Ogni volta che una riga ha la stringa
+@samp{Nov} come suo sesto campo, @command{awk} esegue l'azione
+@samp{somma += $5}. Questo aggiunge il quinto campo (la dimensione del file)
+alla variabile @code{somma}. Come risultato, quando @command{awk} ha finito
+di leggere tutte le righe in input, @code{somma} contiene la somma totale
+delle dimensioni dei file che corrispondono al criterio di ricerca.
+(Ci@`o funziona contando sul fatto che le variabili @command{awk} sono
+automaticamente inizializzate a zero.)
+
+Dopo che l'ultima riga dell'output di @command{ls} @`e stata elaborata, la
+regola @code{END} viene eseguita e viene stampato il valore di @code{somma}.
+In questo esempio, il valore di @code{somma} @`e 80600.
+
+Queste tecniche pi@`u avanzate di @command{awk} sono trattate in
+@value{SECTIONS}
+successive (@pxref{Panoramica sulle azioni}). Prima di poter passare a una
+programmazione pi@`u avanzata con @command{awk}, @`e necessario sapere come
+@command{awk} interpreta i file in input e visualizza quelli in output.
+Modificando campi e usando l'istruzione @code{print} @`e possibile produrre
+dei rapporti molto utili ed esteticamente gradevoli.
+
+@node Istruzioni/Righe
+@section Istruzioni e righe in @command{awk}
+@cindex interruzioni di riga
+@cindex andare a capo
+
+Molto spesso, ogni riga di un programma @command{awk} @`e un'istruzione a s@'e
+stante o una regola isolata, come:
+
+@example
+awk '/12/ @{ print $0 @}
+ /21/ @{ print $0 @}' mail-list inventory-shipped
+@end example
+
+@cindex @command{gawk}, andare a capo
+Comunque, @command{gawk} ignora i ritorni a capo dopo ognuno di questi
+simboli e istruzioni:
+
+@example
+, @{ ? : || && do else
+@end example
+
+@noindent
+Un ritorno a capo in ogni altro punto del programma @`e considerato come la
+fine di un'istruzione.@footnote{Il @samp{?} e i @samp{:} elencati sopra sono
+usati nell'espressione condizionale in tre parti descritta in
+@ref{Espressioni condizionali}.
+Il cambio di riga dopo @samp{?} e i @samp{:} @`e un'estensione minore in
+@command{gawk}; specificando @option{--posix} come opzione
+(@pxref{Opzioni}), quest'estensione non @`e valida.}
+
+@cindex @code{\} (barra inversa), continuazione di riga e
+@cindex barra inversa (@code{\}), continuazione di riga e
+Volendo dividere una sola istruzione su due righe in un punto in cui
+andando a capo sarebbe considerata conclusa, @`e possibile @dfn{continuare}
+nella riga successiva terminando la prima riga con un carattere di
+barra inversa (@samp{\}). La barra inversa dev'essere l'ultimo carattere
+sulla riga, per essere riconosciuto come un carattere di continuazione.
+Una barra inversa @`e consentita in ogni parte dell'istruzione, anche in mezzo
+a una stringa o a un'espressione regolare. Per esempio:
+
+@example
+awk '/Questa espressione regolare @`e troppo lunga, quindi\
+ la continuiamo sulla riga seguente/ @{ print $1 @}'
+@end example
+
+@noindent
+@cindex portabilit@`a, continuazione di riga con barra inversa e
+Non abbiamo quasi mai usato la continuazione tramite barra inversa nei nostri
+programmi di esempio. @command{gawk} non pone limiti alla lunghezza di
+una riga, quindi la continuazione tramite barra inversa non @`e mai strettamente
+necessaria; serve soltanto a migliorare la leggibilit@`a del programma.
+Per la stessa ragione, ma anche per amore di chiarezza, abbiamo tenuto
+concise molte istruzioni nei programmi presentati in questo @value{DOCUMENT}.
+La continuazione tramite barra inversa @`e molto utile quando il proprio
+programma @command{awk} si trova in un file sorgente separato, invece di
+essere immesso nella riga di comando. Si noti anche che molte implementazioni
+di @command{awk} presentano delle differenze su dove @`e possibile usare
+la continuazione tramite barra inversa. Per esempio, potrebbero non
+consentire di spezzare una costante di tipo stringa usando la continuazione
+tramite barra inversa. Quindi, per ottenere la massima portabilit@`a dei
+propri programmi @command{awk}, @`e meglio non spezzare le righe nel
+mezzo di un'espressione regolare o di una stringa.
+@c 10/2000: gawk, mawk, and current bell labs awk allow it,
+@c solaris 2.7 nawk does not. Solaris /usr/xpg4/bin/awk does though! sigh.
+
+@cindex comando @command{csh}
+@cindex barra inversa (@code{\}), continuazione di riga e, in @command{csh}
+@cindex @code{\} (barra inversa), continuazione di riga e, in @command{csh}
+@quotation ATTENZIONE
+@emph{la continuazione tramite barra inversa non funziona come sopra descritto
+nella C shell.} Funziona per programmi @command{awk} contenuti in file e
+per programmi sulla riga di comando, @emph{ammesso} che si stia usando una
+shell conforme a POSIX, come la Unix Bourne shell o Bash. Ma la C shell si
+comporta in maniera diversa! In quel caso, occorre usare due barre inverse
+consecutive, in fondo alla riga. Si noti anche che quando si usa la C shell
+@emph{ogni} andata a capo nel vostro programma @command{awk} deve essere
+indicata con una barra inversa. Per esempio:
+
+@example
+% @kbd{awk 'BEGIN @{ \}
+? @kbd{ print \\}
+? @kbd{ "ciao, mondo" \}
+? @kbd{@}'}
+@print{} ciao, mondo
+@end example
+
+@noindent
+Qui, il @samp{%} e il @samp{?} sono i prompt primario e secondario della
+C shell, analogamente a quelli usati nella shell standard @samp{$} e @samp{>}.
+
+Si confronti l'esempio precedente, come viene scritto in una shell conforme
+a POSIX:
+
+@example
+$ @kbd{awk 'BEGIN @{}
+> @kbd{print \}
+> @kbd{"ciao, mondo"}
+> @kbd{@}'}
+@print{} ciao, mondo
+@end example
+@end quotation
+
+@command{awk} @`e un linguaggio orientato alla riga. L'azione relativa a ogni
+regola deve iniziare sulla stessa riga del criterio di selezione. Per avere
+criterio di selezione e azione su righe separate, si
+@emph{deve} usare la continuazione tramite barra inversa; non si pu@`o fare
+diversamente.
+
+@cindex barra inversa (@code{\}), continuazione di riga, commenti e
+@cindex @code{\} (barra inversa), continuazione di riga, commenti e
+@cindex commenti, continuazione di riga con barra inversa e i
+Un'altra cosa da tener presente @`e che la continuazione tramite barra inversa e
+i commenti non possono essere frammisti. Non appena @command{awk} incontra
+un @samp{#} che inizia un commento, ignora @emph{tutto} il resto della riga.
+Per esempio:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print "Non allarmarti" # una amichevole \}
+> @kbd{ regola BEGIN}
+> @kbd{@}'}
+@error{} gawk: riga com.:2: regola BEGIN
+@error{} gawk: riga com.:2: ^ syntax error
+@end example
+
+@noindent
+In questo caso, parrebbe che la barra inversa continui il commento sulla riga
+successiva. Invece, la combinazione barra inversa-ritorno a capo non viene
+per nulla notata, in quanto ``nascosta'' all'interno del commento. Quindi,
+il @code{BEGIN} @`e marcato come errore di sintassi.
+
+@cindex istruzioni multiple
+@cindex @code{;} (punto e virgola), separare istruzioni nelle azioni
+@cindex punto e virgola (@code{;}), separare istruzioni nelle azioni
+Quando le istruzioni @command{awk} all'interno di una regola sono brevi, si
+potrebbe metterne pi@`u d'una su una riga sola. Ci@`o @`e possibile separando le
+istruzioni con un punto e virgola (@samp{;}).
+Questo vale anche per le regole stesse.
+Quindi, il programma visto all'inizio di
+@ifnotinfo
+questa
+@end ifnotinfo
+@ifinfo
+questo
+@end ifinfo
+@value{SECTION}
+poteva essere scritto anche cos@`{@dotless{i}}:
+
+@example
+/12/ @{ print $0 @} ; /21/ @{ print $0 @}
+@end example
+
+@quotation NOTA BENE
+La possibilit@`a che pi@`u regole coesistano sulla stessa riga, se sono separate
+da un punto e virgola, non esisteva nel linguaggio @command{awk} originale;
+@`e stata aggiunta per congruenza con quanto @`e consentito per le istruzioni
+all'interno di un'azione.
+@end quotation
+
+@node Altre funzionalit@`a
+@section Altre funzionalit@`a di @command{awk}
+
+@cindex variabili
+Il linguaggio @command{awk} mette a disposizione un numero di variabili
+@dfn{built-in}, o @dfn{predefinite}, che il programma dell'utente pu@`o usare
+per ottenere informazioni da @command{awk}. Ci sono pure altre variabili
+che il programma pu@`o impostare, per definire come @command{awk} deve
+gestire i dati.
+
+Inoltre, @command{awk} mette a disposizione parecchie funzioni predefinite
+[@dfn{built-in}] per effettuare calcoli di tipo comune e operazioni che
+agiscono sulle stringhe di caratteri.
+@command{gawk} mette a disposizione funzioni predefinite per gestire le
+marcature temporali, per effettuare manipolazioni a livello di bit, per
+tradurre stringhe al momento dell'esecuzione del programma
+(internazionalizzazione), per determinare qual @`e il tipo di una variabile,
+e per ordinare dei vettori.
+
+Nel seguito della presentazione del linguaggio @command{awk}, saranno
+introdotte molte delle variabili e parecchie funzioni. Esse sono
+descritte sistematicamente in @ref{Variabili predefinite} e in
+@ref{Funzioni}.
+
+@node Quando
+@section Quando usare @command{gawk}
+
+@cindex @command{awk}, uso di
+Ora che abbiamo visto qualcosa di quel che @command{awk} @`e in grado di fare,
+ci si potr@`a chiedere come @command{awk} potrebbe tornare utile. Usando
+programmi di utilit@`a, criteri di ricerca sofisticati, separatori
+di campo, istruzioni aritmetiche, e altri criteri di selezione, @`e possibile
+produrre degli output molto pi@`u complessi. Il linguaggio @command{awk} @`e
+molto utile per fornire dei tabulati partendo da grandi quantit@`a di dati
+grezzi, per esempio riassumendo informazioni dall'output di altri
+programmi di utilit@`a come @command{ls}.
+(@xref{Maggiore sofisticazione}.)
+
+I programmi scritti con @command{awk} sono normalmente molto pi@`u
+corti dei loro equivalenti in altri linguaggi. Ci@`o rende i programmi
+@command{awk} facili da comporre e da utilizzare. Spesso i programmi
+@command{awk} possono essere scritti al volo a terminale, usati una volta sola
+e buttati via. Poich@'e i programmi @command{awk} sono interpretati, si pu@`o
+evitare la (normalmente laboriosa) parte di compilazione nel ciclo tipico
+dello sviluppo software, ossia edita-compila-prova-correggi.
+
+@cindex Brian Kernighan, @command{awk} di
+In @command{awk} sono stati scritti programmi complessi, compreso un assembler
+completo, pluri-piattaforma per
+@ifclear FOR_PRINT
+@iftex
+microprocessori a 8-bit (@pxrefil{Glossario}, per maggiori informazioni),
+@end iftex
+@ifnottex
+microprocessori a 8-bit (@pxref{Glossario}, per maggiori informazioni),
+@end ifnottex
+@end ifclear
+@ifset FOR_PRINT
+microprocessori a 8-bit,
+@end ifset
+e un assembler di microcodice per un computer dedicato esclusivamente
+al linguaggio Prolog.
+Le possibilit@`a dell'originale @command{awk} erano messe a dura prova
+da programmi di questa complessit@`a, ma le versioni moderne sono pi@`u robuste.
+
+@cindex programmi @command{awk}, complessi
+Se capita di scrivere programmi @command{awk} pi@`u lunghi di, diciamo,
+qualche centinaio di righe, si potrebbe considerare la possibilit@`a di usare
+un linguaggio di programmazione differente da @command{awk}.
+La shell consente di ricercare stringhe ed espressioni regolari; inoltre
+consente di usare in maniera efficace i comandi di utilit@`a del sistema.
+Python offre un piacevole equilibrio tra la facilit@`a di una programmazione
+ad alto livello, e la possibilit@`a di interagire a livello di sistema
+operativo.@footnote{Altri linguaggi di @dfn{script} popolari comprendono Ruby
+e Perl.}
+
+@node Sommario dell'introduzione
+@section Sommario
+
+@c FIXME: Review this chapter for summary of builtin functions called.
+@itemize @value{BULLET}
+@item
+I programmi in @command{awk} consistono di coppie di
+@var{criterio di ricerca}--@var{azione}.
+
+@item
+Un'@var{azione} senza una @var{condizione di ricerca} viene sempre eseguita.
+L'@var{azione} di default per una condizione mancante @`e @samp{@{ print $0 @}}.
+
+@item
+Usare
+@samp{awk '@var{programma}' @var{file}}
+oppure
+@samp{awk -f @var{file-programma} @var{file}}
+per eseguire @command{awk}.
+
+@item
+Si pu@`o usare la notazione speciale @samp{#!} nella prima riga per creare
+programmi @command{awk} che siano eseguibili direttamente.
+
+@item
+I commenti nei programmi @command{awk} iniziano con @samp{#} e continuano
+fino alla fine della stessa riga.
+
+@item
+Prestare attenzione ai problemi con gli apici nei programmi @command{awk}
+che facciano parte di uno @dfn{script} della shell (o di un file .BAT di
+MS-Windows).
+
+@item
+Si pu@`o usare la continuazione tramite barra inversa per continuare righe di
+codice sorgente. Le righe sono continuate automaticamente dopo i simboli
+virgola, parentesi aperta, punto interrogativo, punto e virgola,
+@samp{||}, @samp{&&}, @code{do} ed @code{else}.
+@end itemize
+@node Invocare Gawk
+@chapter Eseguire @command{awk} e @command{gawk}
+
+Questo @value{CHAPTER} tratta di come eseguire @command{awk}, delle opzioni da
+riga di comando, sia quelle dello standard POSIX che quelle specifiche di
+@command{gawk}, e di cosa fanno @command{awk} e @command{gawk} con gli
+argomenti che non sono opzioni.
+Prosegue poi spiegando come @command{gawk} cerca i file sorgenti,
+leggendo lo standard input assieme ad altri file, le variabili d'ambiente di
+@command{gawk}, lo stato di ritorno di @command{gawk}, l'uso dei file inclusi,
+e opzioni e/o funzionalit@`a obsolete e non documentate.
+
+Molte delle opzioni e funzionalit@`a qui descritte sono trattate con
+maggior dettaglio nei capitoli successivi del @value{DOCUMENT}; gli argomenti
+presenti in questo @value{CHAPTER} che al momento non interessano si possono
+tranquillamente saltare.
+
+@menu
+* Riga di comando:: Come eseguire @command{awk}.
+* Opzioni:: Opzioni sulla riga di comando e loro
+ significato.
+* Altri argomenti:: Nomi dei file in input e assegnamento di
+ valori a variabili.
+* Specificare lo standard input:: Come specificare lo standard input insieme ad
+ altri file.
+* Variabili d'ambiente:: Le variabili d'ambiente usate da
+ @command{gawk}.
+* Codice di ritorno:: Il codice di ritorno all'uscita da
+ @command{gawk}.
+* Includere file:: Come includere altri file nel proprio
+ programma.
+* Caricare librerie condivise:: Caricare librerie condivise nel
+ proprio programma.
+* Parti obsolete:: Opzioni e/o funzionalit@`a obsolete.
+* Non documentato:: Opzioni e funzionalit@`a non documentate.
+* Sommario invocazione:: Sommario invocazione.
+@end menu
+
+@node Riga di comando
+@section Come eseguire @command{awk}
+@cindex riga di comando, eseguire @command{awk} da
+@cindex @command{awk}, eseguire
+@cindex argomenti, riga di comando, eseguire @command{awk}
+@cindex opzioni sulla riga di comando, eseguire @command{awk}
+
+Ci sono due modi di eseguire @command{awk}: con un programma esplicito o con
+uno o pi@`u file di programma. Qui @`e mostrata la sintassi di entrambi; le voci
+racchiuse tra [@dots{}] sono opzionali:
+
+@display
+@command{awk} [@var{opzioni}] @option{-f} @var{file_di _programma} [@option{--}] @var{file} @dots{}
+@command{awk} [@var{opzioni}] [@option{--}] @code{'@var{programma}'} @var{file} @dots{}
+@end display
+
+@cindex GNU, opzioni estese
+@cindex estese, opzioni
+@cindex opzioni estese
+In aggiunta alle tradizionali opzioni di una sola lettera in stile POSIX,
+@command{gawk} consente anche le opzioni estese GNU.
+
+@cindex angolo buio, invocare @command{awk}
+@cindex @dfn{lint}, controlli con programma vuoto
+@`E possibile invocare @command{awk} con un programma vuoto:
+
+@example
+awk '' file_dati_1 file_dati_2
+@end example
+
+@cindex @option{--lint}, opzione
+@noindent
+Fare cos@`{@dotless{i}} ha comunque poco senso; @command{awk} termina
+silenziosamente quando viene fornito un programma vuoto.
+@value{DARKCORNER}
+Se @`e stato specificato @option{--lint} sulla riga di comando,
+@command{gawk} emette un avviso che avverte
+che il programma @`e vuoto.
+
+@node Opzioni
+@section Opzioni sulla riga di comando
+@cindex opzioni sulla riga di comando
+@cindex riga di comando, opzioni
+@cindex GNU, opzioni estese
+@cindex opzioni estese
+
+Le opzioni sono precedute da un trattino e consistono in un unico carattere.
+Le opzioni estese in stile GNU sono precedute da un doppio trattino e
+consistono in una parola
+chiave. La parola chiave pu@`o essere abbreviata, a condizione che
+l'abbreviazione identifichi univocamente l'opzione. Se l'opzione prevede un
+argomento, la parola chiave @`e immediatamente seguita da un segno di uguale
+(@samp{=}) e dal valore dell'argomento, oppure la parola chiave e il valore
+dell'argomento sono separati da spazi.
+Se un'opzione con un valore viene immessa pi@`u di una volta,
+l'ultimo valore @`e quello che conta.
+
+@cindex POSIX @command{awk}, opzioni estese GNU e
+Ogni opzione estesa di @command{gawk} ha una corrispondente opzione
+breve in stile POSIX.
+Le opzioni estese e brevi sono
+intercambiabili in tutti i contesti.
+L'elenco seguente descrive le opzioni richieste dallo standard POSIX:
+
+@table @code
+@item -F @var{fs}
+@itemx --field-separator @var{fs}
+@cindex @option{-F}, opzione
+@cindex @option{--field-separator}, opzione
+@cindex @code{FS}, variabile, l'opzione @code{--field-separator} e
+Imposta la variabile @code{FS} a @var{fs}
+(@pxref{Separatori di campo}).
+
+@item -f @var{file-sorgente}
+@itemx --file @var{file-sorgente}
+@cindex @option{-f}, opzione
+@cindex @option{--file}, opzione
+@cindex @command{awk}, programmi, collocazione dei
+Legge il sorgente del programma @command{awk} da @var{file-sorgente}
+anzich@'e prenderlo dal primo argomento che non @`e un'opzione.
+Quest'opzione pu@`o essere data pi@`u volte; il programma @command{awk}
+@`e formato dalla concatenazione del contenuto di ogni
+@var{file-sorgente} specificato.
+
+@item -v @var{var}=@var{val}
+@itemx --assign @var{var}=@var{val}
+@cindex @option{-v}, opzione
+@cindex @option{--assign}, opzione
+@cindex variabili, impostazione
+Imposta la variabile @var{var} al valore @var{val} @emph{prima} che inizi
+l'esecuzione del programma. Tali valori di variabile sono disponibili
+all'interno della regola @code{BEGIN}
+(@pxref{Altri argomenti}).
+
+L'opzione @option{-v} pu@`o impostare una sola variabile per volta, ma pu@`o
+essere usata pi@`u di una volta, impostando ogni volta una variabile
+differente, in questo modo:
+@samp{awk @w{-v pippo=1} @w{-v pluto=2} @dots{}}.
+
+@cindex predefinite, variabili, opzione @code{-v}@comma{} impostare con
+@cindex variabili predefinite, impostare con opzione @code{-v}
+@quotation ATTENZIONE
+Usare @option{-v} per impostare valori di variabili predefinite
+pu@`o condurre a risultati sorprendenti. @command{awk} reimposter@`a i
+valori di quelle variabili secondo le sue necessit@`a, anche ignorando
+eventuali valori iniziali che possono essere stati assegnati.
+@end quotation
+
+@item -W @var{gawk-opt}
+@cindex @option{-W}, opzione
+Fornisce un'opzione specifica dell'implementazione. Questa @`e la convenzione
+POSIX per fornire opzioni specifiche dell'implementazione.
+Queste opzioni
+hanno anche una corrispondente opzione estesa scritta in stile GNU.
+Si noti che le opzioni estese possono essere abbreviate, sempre che
+le abbreviazioni siano univoche.
+L'elenco completo delle opzioni specifiche di @command{gawk} @`e riportato di
+seguito.
+
+@item --
+@cindex riga di comando, opzioni, fine delle
+@cindex opzioni sulla riga di comando, fine delle
+Segnale della fine delle opzioni da riga di comando. I seguenti argomenti
+non sono trattati come opzioni anche se iniziano con @samp{-}. Questa
+interpretazione di @option{--} segue le convenzioni POSIX per l'analisi degli
+argomenti.
+
+@cindex @code{-} (meno), nomi di file che iniziano con
+@cindex meno (@code{-}), nomi di file che iniziano con
+@`E utile se si hanno @value{FNS} che iniziano con @samp{-},
+o negli @dfn{script} di shell, se si hanno @value{FNS} che devono essere
+specificati dall'utente che potrebbero iniziare con @samp{-}.
+@`E utile anche per passare opzioni al programma @command{awk};
+si veda @ref{Funzione getopt}.
+@end table
+
+L'elenco che segue descrive le opzioni specifiche di @command{gawk}:
+
+@c Have to use @asis here to get docbook to come out right.
+@table @asis
+@item @option{-b}
+@itemx @option{--characters-as-bytes}
+@cindex @option{-b}, opzione
+@cindex @option{--characters-as-bytes}, opzione
+Fa s@`{@dotless{i}} che @command{gawk} tratti tutti i dati in input come caratteri di un solo
+byte. In aggiunta, tutto l'output scritto con @code{print} o @code{printf}
+viene trattato come composto da caratteri contenuti in un solo byte.
+
+Normalmente, @command{gawk} segue lo standard POSIX e cerca di elaborare i suoi
+dati di input in accordo con la localizzazione corrente
+(@pxref{Localizzazioni}).
+Questo spesso pu@`o comportare la conversione di caratteri multibyte in
+caratteri estesi (internamente), e pu@`o
+creare problemi o confusione se i dati di input non contengono caratteri
+multibyte validi. Quest'opzione @`e una maniera facile di dire a @command{gawk}:
+``Gi@`u le mani dai miei dati!''.
+
+@item @option{-c}
+@itemx @option{--traditional}
+@cindex @option{-c}, opzione
+@cindex @option{--traditional}, opzione
+@cindex modalit@`a compatibile di (@command{gawk}), specificare
+Specifica la @dfn{modalit@`a di compatibilit@`a}, nella quale le estensioni GNU al
+linguaggio @command{awk} sono disabilitate; in questo modo @command{gawk} si
+comporta proprio come la versione di BWK @command{awk}.
+
+@xref{POSIX/GNU},
+che riassume le estensioni.
+@ifclear FOR_PRINT
+Si veda anche
+@ref{Modalit@`a di compatibilit@`a}.
+@end ifclear
+
+@item @option{-C}
+@itemx @option{--copyright}
+@cindex @option{-C}, opzione
+@cindex @option{--copyright}, opzione
+@cindex GPL (General Public License), stampare
+Stampa la versione ridotta della General Public License ed esce.
+
+@item @option{-d}[@var{file}]
+@itemx @option{--dump-variables}[@code{=}@var{file}]
+@cindex @option{-d}, opzione
+@cindex @option{--dump-variables}, opzione
+@cindex fornire una lista di tutte le variabili del programma
+@cindex @file{awkvars.out}, file
+@cindex file @file{awkvars.out}
+@cindex variabili globali, stampare una lista delle
+Stampa una lista ordinata di variabili globali, i loro tipi, e i valori finali
+in @var{file}. Se non viene fornito alcun @var{file}, stampa questa lista
+in un file chiamato @file{awkvars.out} nella directory corrente.
+Non sono consentiti spazi tra @option{-d} e @var{file}, se
+@var{file} viene specificato.
+
+@cindex risoluzione di problemi, refusi@comma{} variabili globali
+@cindex problemi, risoluzione di, refusi@comma{} variabili globali
+Avere una lista di tutte le variabili globali @`e un buon modo per cercare
+refusi nei propri programmi.
+Si pu@`o usare quest'opzione anche se si ha un grosso programma con tantissime
+funzioni, e si vuol essere sicuri che le funzioni non usino
+inavvertitamente variabili globali che sarebbero dovute essere locali
+(questo @`e un errore particolarmente facile da fare con nomi di variabile
+semplici come @code{i}, @code{j}, etc.).
+
+@item @option{-D}[@var{file}]
+@itemx @option{--debug}[@code{=}@var{file}]
+@cindex @option{-D}, opzione
+@cindex @option{--debug}, opzione
+@cindex @command{awk}, debug, abilitare
+Abilita l'esecuzione del debug di programmi @command{awk}
+(@pxref{Debugging}).
+Per default, il debugger legge i comandi interattivamente dalla tastiera
+(standard input).
+L'argomento opzionale @var{file} consente di specificare un file con una lista
+di comandi per il debugger da eseguire in maniera non interattiva.
+Non sono consentiti spazi tra @option{-D} e @var{file}, se
+@var{file} viene indicato.
+
+@item @option{-e} @var{testo-del-programma}
+@itemx @option{--source} @var{testo-del-programma}
+@cindex @option{-e}, opzione
+@cindex @option{--source}, opzione
+@cindex codice sorgente, combinare
+Fornisce del codice sorgente nel @var{testo-del-programma}.
+Quest'opzione consente di combinare il codice sorgente contenuto in file
+col codice sorgente immesso sulla riga di comando.
+Questo @`e particolarmente utile quando si hanno funzioni di libreria che si
+vogliono usare dai programmi da riga di comando
+(@pxref{AWKPATH (Variabile)}).
+
+@item @option{-E} @var{file}
+@itemx @option{--exec} @var{file}
+@cindex @option{-E}, opzione
+@cindex @option{--exec}, opzione
+@cindex @command{awk}, programmi, collocazione dei
+@cindex CGI, @command{awk} @dfn{script} per
+Simile a @option{-f}, legge il testo del programma @command{awk} da
+@var{file}. Ci sono due differenze rispetto a @option{-f}:
+
+@itemize @value{BULLET}
+@item
+Quest'opzione fa terminare l'elaborazione delle opzioni; qualsiasi
+altra cosa sulla riga di comando viene inoltrata direttamente al programma
+@command{awk}.
+
+@item
+Le variabili da riga di comando della forma
+@samp{@var{var}=@var{value}} non sono ammesse.
+@end itemize
+
+Quest'opzione @`e particolarmente necessaria per le applicazioni World Wide Web
+CGI che passano argomenti attraverso le URL; l'uso di quest'opzione impedisce
+a un utente malintenzionato (o ad altri) di passare opzioni, assegnamenti o
+codice sorgente @command{awk} (con @option{-e}) all'applicazione
+CGI.@footnote{per maggiori dettagli,
+si veda la Sezione 4.4 di @uref{http://www.ietf.org/rfc/rfc3875,
+RFC 3875}. Si veda anche
+@uref{http://lists.gnu.org/archive/html/bug-gawk/2014-11/msg00022.html,
+note esplicative spedite alla mailing list @command{gawk} bug}.}
+Quest'opzione dovrebbe essere usata
+con @dfn{script} @samp{#!}
+(@pxref{@dfn{Script} eseguibili}), in questo modo:
+
+@example
+#! /usr/local/bin/gawk -E
+
+@var{il programma awk @`e qui @dots{}}
+@end example
+
+@item @option{-g}
+@itemx @option{--gen-pot}
+@cindex @option{-g}, opzione
+@cindex @option{--gen-pot}, opzione
+@cindex portabilit@`a, generare file oggetto
+@cindex file oggetto portabili, generare
+Analizza il programma sorgente e
+genera un file GNU @command{gettext} @dfn{portable object template} sullo
+standard output per tutte le costanti di tipo stringa che sono state marcate
+come da tradurre.
+@xref{Internazionalizzazione},
+per informazioni su quest'opzione.
+
+@item @option{-h}
+@itemx @option{--help}
+@cindex @option{-h}, opzione
+@cindex @option{--help}, opzione
+@cindex GNU, opzioni estese, stampare una lista di
+@cindex opzioni, stampare una lista di
+@cindex stampa, lista di opzioni
+Stampa un messaggio sull'``uso'' riassumendo le opzioni brevi ed estese
+accettate da @command{gawk} ed esce.
+
+@item @option{-i} @var{file-sorgente}
+@itemx @option{--include} @var{file-sorgente}
+@cindex @option{-i}, opzione
+@cindex @option{--include}, opzione
+@cindex @command{awk}, programmi, collocazione dei
+Legge una libreria di sorgenti @command{awk} da @var{file-sorgente}.
+Quest'opzione @`e del tutto equivalente a usare la direttiva @code{@@include}
+all'interno del proprio programma. @`E molto simile all'opzione
+@option{-f}, ma ci sono due differenze importanti. Primo, quando viene usata
+l'opzione @option{-i}, il sorgente del programma non viene caricato se @`e
+stato caricato in precedenza, mentre con @option{-f}, @command{gawk} carica
+sempre il file. Secondo, poich@'e quest'opzione @`e pensata per essere usata
+con librerie di codice, @command{gawk} non riconosce tali file come
+costituenti l'input del programma principale. Cos@`{@dotless{i}}, dopo l'elaborazione di
+un argomento @option{-i}, @command{gawk} si aspetta di trovare il codice
+sorgente principale attraverso l'opzione @option{-f} o sulla riga di comando.
+
+@item @option{-l} @var{ext}
+@itemx @option{--load} @var{ext}
+@cindex @option{-l}, opzione
+@cindex @option{--load}, opzione
+@cindex caricare estensioni
+Carica un'estensione dinamica denominata @var{ext}. Le estensioni sono
+memorizzate come librerie condivise di sistema.
+Quest'opzione ricerca la libreria usando la variabile d'ambiente
+@env{AWKLIBPATH}. Il suffisso corretto per la piattaforma in uso verr@`a
+fornito per default, perci@`o non @`e necessario specificarlo nel nome
+dell'estensione. La routine di inizializzazione dell'estensione dovrebbe
+essere denominata @code{dl_load()}. Un'alternativa @`e quella di usare la
+direttiva @code{@@load} all'interno del programma per caricare una libreria
+condivisa. Questa funzionalit@`a avanzata @`e descritta in dettaglio in
+@ref{Estensioni dinamiche}.
+
+@item @option{-L}[@var{valore}]
+@itemx @option{--lint}[@code{=}@var{valore}]
+@cindex @option{-l}, opzione
+@cindex @option{--lint}, opzione
+@cindex @dfn{lint}, controlli, emissione di avvertimenti
+@cindex avvertimenti, emissione di
+Emette messaggi d'avvertimento relativi a costrutti dubbi o non portabili ad
+altre implementazioni di @command{awk}.
+Non sono consentiti spazi tra @option{-L} e @var{valore}, se
+viene indicato il @var{valore}.
+Alcuni avvertimenti vengono emessi quando @command{gawk} legge preliminarmente
+il programma. Altri vengono emessi quando il programma viene eseguito.
+Con l'argomento opzionale @samp{fatal}, gli avvertimenti @dfn{lint} sono considerati
+come errori gravi. Potrebbe essere una misura drastica, per@`o il suo uso
+incoragger@`a certamente lo sviluppo di programmi @command{awk} pi@`u corretti.
+Con l'argomento opzionale @samp{invalid}, vengono emessi solo gli avvertimenti
+relativi a quello che @`e effettivamente non valido (funzionalit@`a non ancora
+completamente implementata).
+
+Alcuni avvertimenti vengono stampati solo una volta, anche se i costrutti dubbi
+per i quali vengono emessi avvisi ricorrono diverse volte nel programma
+@command{awk}. Perci@`o, nell'eliminazione dei problemi rilevati da
+@option{--lint}, bisogna porre attenzione a cercare tutte le occorrenze di ogni
+costrutto inappropriato. Siccome i programmi @command{awk} generalmente sono
+brevi, questa non @`e un'operazione gravosa.
+
+@item @option{-M}
+@itemx @option{--bignum}
+@cindex @option{-M}, opzione
+@cindex @option{--bignum}, opzione
+Chiede il calcolo con precisione arbitraria sui numeri. Quest'opzione non ha
+alcun effetto se @command{gawk} non @`e compilato per l'uso delle librerie GNU
+MPFR e MP
+(@pxref{Calcolo con precisione arbitraria}).
+
+@item @option{-n}
+@itemx @option{--non-decimal-data}
+@cindex @option{-n}, opzione
+@cindex @option{--non-decimal-data}, opzione
+@cindex esadecimali@comma{} valori, abilitare l'interpretazione di
+@cindex ottali@comma{} valori, abilitare l'interpretazione di
+@cindex risoluzione di problemi, opzione @code{--non-decimal-data}
+Abilita l'interpretazione automatica di valori ottali ed esadecimali
+nei dati di input
+(@pxref{Dati non decimali}).
+
+@quotation ATTENZIONE
+Quest'opzione pu@`o generare gravi malfunzionamenti nei vecchi programmi.
+Usare con cautela. Si noti anche che
+quest'opzione potrebbe non essere pi@`u disponibile in una futura versione di
+@command{gawk}.
+@end quotation
+
+@item @option{-N}
+@itemx @option{--use-lc-numeric}
+@cindex @option{-N}, opzione
+@cindex @option{--use-lc-numeric}, opzione
+Forza l'uso del carattere di separazione decimale della localizzazione
+quando analizza i dati in input
+(@pxref{Localizzazioni}).
+
+@item @option{-o}[@var{file}]
+@itemx @option{--pretty-print}[@code{=}@var{file}]
+@cindex @option{-o}, opzione
+@cindex @option{--pretty-print}, opzione
+Consente la stampa di una versione formattata elegantemente dei programmi
+@command{awk}. Implica l'opzione @option{--no-optimize}.
+Per default il programma di output viene creato in un file
+chiamato @file{awkprof.out} (@pxref{Profilare}).
+L'argomento opzionale @var{file} consente di specificare un
+@value{FN} differente per l'output.
+Non sono consentiti spazi tra @option{-o} e @var{file}, se
+@var{file} viene indicato.
+
+@quotation NOTA
+Nel passato, quest'opzione eseguiva anche il programma.
+Ora non @`e pi@`u cos@`{@dotless{i}}.
+@end quotation
+
+@item @option{-O}
+@itemx @option{--optimize}
+@cindex @option{--optimize}, opzione
+@cindex @option{-O}, opzione
+Abilita le ottimizzazioni di default nella rappresentazione interna del
+programma. Attualmente, questo comprende delle semplificazioni nell'uso
+di costanti e l'eliminazione delle code di chiamata nelle funzioni
+ricorsive [sostituzione della chiamata di funzione con dei salti
+diretti alla funzione].
+
+Queste ottimizzazioni sono abilitate per default.
+Quest'opzione rimane disponibile per compatibilit@`a all'indietro.
+Tuttavia pu@`o essere usata per annullare l'effetto di una precedente
+opzione @option{-s} (si veda pi@`u sotto in questa lista).
+
+@item @option{-p}[@var{file}]
+@itemx @option{--profile}[@code{=}@var{file}]
+@cindex @option{-p}, opzione
+@cindex @option{--profile}, opzione
+@cindex @command{awk}, profilatura, abilitare la
+Abilita la creazione del profilo di esecuzione di programmi @command{awk}
+(@pxref{Profilare}).
+Implicitamente viene forzata l'opzione @option{--no-optimize}.
+Per default, i profili vengono creati in un file chiamato @file{awkprof.out}.
+L'argomento opzionale @var{file} consente di specificare un altro
+@value{FN} per il file del profilo.
+Non sono consentiti spazi tra @option{-p} e @var{file}, se
+viene indicato un @var{file}.
+
+Il profilo contiene il numero di esecuzioni di ogni istruzione sul margine
+sinistro e il conteggio delle chiamate di funzione per ogni funzione.
+
+@item @option{-P}
+@itemx @option{--posix}
+@cindex @option{-P}, opzione
+@cindex @option{--posix}, opzione
+@cindex POSIX, modalit@`a
+@cindex @command{gawk}, estensioni@comma{} disabilitare
+Opera in modalit@`a POSIX rigorosa. Disabilita tutte le estensioni di
+@command{gawk} (proprio come @option{--traditional}) e
+disabilita tutte le estensioni non consentite da POSIX.
+
+@xref{Estensioni comuni}, per un sommario delle estensioni
+di @command{gawk} che sono disabilitate da quest'opzione.
+Inoltre,
+vengono applicate le seguenti
+restrizioni:
+
+@itemize @value{BULLET}
+
+@cindex ritorno a capo
+@cindex spazi vuoti, ritorno a capo invece che
+@item
+I ritorni a capo non sono consentiti dopo @samp{?} o @samp{:}
+(@pxref{Espressioni condizionali}).
+
+
+@cindex @code{FS}, variabile, come carattere TAB
+@item
+Specificando @samp{-Ft} sulla riga di comando non si imposta il valore
+della variabile @code{FS} a un singolo carattere TAB
+(@pxref{Separatori di campo}).
+
+@cindex localizzazione, separatore decimale della
+@cindex separatore decimale, carattere, specifico della localizzazione
+@item
+Il carattere di separatore decimale della localizzazione @`e usato per analizzare
+i dati di input
+(@pxref{Localizzazioni}).
+@end itemize
+
+@c @cindex automatic warnings
+@c @cindex warnings, automatic
+@cindex @option{--traditional}, opzione, e opzione @code{--posix}
+@cindex @option{--posix}, opzione, e opzione @code{--traditional}
+Se si forniscono entrambe le opzioni @option{--traditional} e @option{--posix}
+sulla riga di comando, @option{--posix} ha la precedenza. Se vengono fornite
+entrambe le opzioni @command{gawk} emette un avviso.
+
+@item @option{-r}
+@itemx @option{--re-interval}
+@cindex @option{-r}, opzione
+@cindex @option{--re-interval}, opzione
+@cindex espressioni regolari, espressioni di intervallo e
+Consente le espressioni di intervallo
+(@pxref{Operatori di espressioni regolari})
+nelle espressioni regolari.
+Questo @`e ora il comportamento di default di @command{gawk}.
+Tuttavia, quest'opzione rimane (sia per retrocompatibilit@`a
+che per l'uso in combinazione con @option{--traditional}).
+
+@item @option{-s}
+@itemx @option{--no-optimize}
+@cindex @option{--no-optimize}, opzione
+@cindex opzione @option{--no-optimize}
+@cindex @option{-s}, opzione,
+@cindex opzione @option{-s}
+Disabilita le opzioni di ottimizzazione di default di @command{gawk}
+effettuate sulla rappresentazione interna del programma.
+
+@item @option{-S}
+@itemx @option{--sandbox}
+@cindex @option{-S}, opzione
+@cindex @option{--sandbox}, opzione
+@cindex sandbox, modalit@`a
+@cindex prova, modalit@`a di
+Disabilita la funzione @code{system()},
+la ridirezione dell'input con @code{getline},
+la ridirezione dell'output con @code{print} e @code{printf},
+e le estensioni dinamiche.
+@`E particolarmente utile quando si vogliono eseguire @dfn{script} @command{awk}
+da sorgenti dubbie e si vuol essere ricuri che gli @dfn{script} non abbiano
+accesso al sistema (oltre al @value{DF} di input specificato).
+
+@item @option{-t}
+@itemx @option{--lint-old}
+@cindex @option{-L}, opzione
+@cindex @option{--lint-old}, opzione
+Avvisa su costrutti che non sono disponibili nella versione originale di
+@command{awk} dalla versione 7 di Unix
+(@pxref{V7/SVR3.1}).
+
+@item @option{-V}
+@itemx @option{--version}
+@cindex @option{-V}, opzione
+@cindex @option{--version}, opzione
+@cindex @command{gawk}, versioni di, informazioni su@comma{} stampa
+Stampa informazioni sulla versione di questa specifica copia di @command{gawk}.
+Consente di determinare se la copia di @command{gawk} in uso @`e aggiornata
+rispetto a quello che @`e attualmente in distribuzione da parte della Free
+Software Foundation.
+@`E utile anche per la segnalazione di bug
+(@pxref{Bug}).
+@end table
+
+Ogni altra opzione, se @`e stato specificato il testo di un programma
+@`e contrassegnata come non valida con un messaggio di avvertimento,
+altrimenti @`e ignorata.
+
+@cindex @option{-F}, opzione, opzione @option{-Ft} imposta @code{FS} a TAB
+In modalit@`a di compatibilit@`a, come caso particolare, se il valore di @var{fs}
+fornito all'opzione @option{-F} @`e @samp{t}, @code{FS} @`e impostata al carattere
+TAB (@code{"\t"}). Questo @`e vero solo per @option{--traditional} e non
+per @option{--posix}
+(@pxref{Separatori di campo}).
+
+@cindex @option{-f}, opzione, usi multipli
+L'opzione @option{-f} pu@`o essere usata pi@`u di una volta nella riga di comando.
+In questo caso, @command{awk} legge il sorgente del suo programma da tutti i
+file indicati, come se fossere concatenati assieme a formare un unico grande
+file.
+Questo @`e utile per creare librerie di funzioni di @command{awk}. Queste
+funzioni possono venir scritte una volta e in seguito recuperate da una
+posizione standard, invece di doverle includere in ogni singolo programma.
+L'opzione @option{-i} @`e simile in questo senso.
+(Come indicato in
+@ref{Sintassi delle definizioni},
+i nomi di funzione devono essere univoci).
+
+Con @command{awk} standard, le funzioni di libreria si possono ancora usare,
+anche se il programma @`e immesso dalla tastiera,
+specificando @samp{-f /dev/tty}. Dopo aver scritto il programma,
+premere @kbd{Ctrl-d} (il carattere di fine file) per terminarlo.
+(Si potrebbe anche usare @samp{-f -} per leggere il sorgente del programma
+dallo standard input, ma poi non si potr@`a usare lo standard input come sorgente
+di dati).
+
+Siccome @`e scomodo usare il meccanismo di @command{awk} standard per combinare
+file sorgenti e programmi @command{awk} da riga di comando, @command{gawk}
+fornisce l'opzione @option{-e}. Questo non richiede di evitare l'uso dello
+standard input per immettere codice sorgente; consente di combinare
+facilmente codice sorgente da riga di comando e da libreria
+(@pxref{AWKPATH (Variabile)}).
+Come per @option{-f}, le opzioni @option{-e} e @option{-i}
+si possono usare pi@`u volte nella riga di comando.
+
+@cindex @option{-e}, opzione
+Se non sono specificate opzioni @option{-f} o @option{-e}, @command{gawk}
+usa il primo argomento che non @`e un'opzione come testo del
+codice sorgente del programma.
+
+@cindex @env{POSIXLY_CORRECT}, variabile d'ambiente
+@cindex @dfn{lint}, controlli, variabile d'ambiente @env{POSIXLY_CORRECT}
+@cindex POSIX, modalit@`a
+Se la variabile d'ambiente @env{POSIXLY_CORRECT} esiste,
+@command{gawk} si comporta in modalit@`a POSIX rigorosa, esattamente come se
+fosse stata fornita l'opzione @option{--posix}.
+Molti programi GNU cercano questa variabile d'ambiente per eliminare
+estensioni che confliggono con POSIX, ma @command{gawk} si comporta in modo
+diverso: sopprime tutte le estensioni, anche quelle che non confliggono con
+POSIX, e funziona rigorosamente in modalit@`a POSIX.
+Se viene fornita l'opzione @option{--lint} sulla riga di comando e
+@command{gawk} passa alla modalit@`a POSIX a causa di @env{POSIXLY_CORRECT},
+viene emesso un messaggio di avvertimento indicando che @`e attiva la
+modalit@`a POSIX. Normalmente questa variabile si imposta nel file di avvio
+della shell a livello utente.
+Per una shell compatibile con Bourne (come Bash), queste righe andranno
+aggiunte nel file @file{.profile} della directory "home" dell'utente:
+
+@example
+POSIXLY_CORRECT=true
+export POSIXLY_CORRECT
+@end example
+
+@cindex @command{csh}, comando, variabile d'ambiente @env{POSIXLY_CORRECT}
+Per una shell compatibile con C,@footnote{Non raccomandato.}
+questa riga andr@`a aggiunta nel file @file{.login} nella directory "home"
+dell'utente:
+
+@example
+setenv POSIXLY_CORRECT true
+@end example
+
+@cindex portabilit@`a, variabile d'ambiente @env{POSIXLY_CORRECT}
+Avere @env{POSIXLY_CORRECT} impostata non @`e raccomandato per l'uso quotidiano,
+ma @`e utile per provare la portabilit@`a dei programmi su altri
+ambienti.
+
+@node Altri argomenti
+@section Altri argomenti della riga di comando
+@cindex riga di comando, argomenti
+@cindex argomenti, riga di comando
+
+Qualsiasi altro argomento sulla riga di comando @`e trattato normalmente come
+file in input da elaborare nell'ordine con cui @`e specificato. Comunque, un
+argomento che ha la forma @code{@var{var}=@var{valore}}, assegna
+il valore @var{valore} alla variabile @var{var}---non specifica affatto
+un file. (Si veda @ref{Opzioni di assegnamento}.) Nel seguente esempio,
+@var{count=1} @`e un assegnamento di variabile, non un @value{FN}:
+
+@example
+awk -f programma.awk file1 count=1 file2
+@end example
+
+@cindex @command{gawk}, variabile @code{ARGIND} in
+@cindex @code{ARGIND}, variabile, argomenti da riga di comando
+@cindex @code{ARGV}, vettore, indicizzare all'interno di
+@cindex @code{ARGC}/@code{ARGV}, variabili, argomenti da riga di comando
+Tutti gli argomenti da riga di comando sono resi disponibili al programma
+@command{awk} nel vettore @code{ARGV} (@pxref{Variabili predefinite}). Opzioni da
+riga di comando e il testo del programma (se presente) sono esclusi da
+@code{ARGV}. Tutti gli altri argomenti, compresi gli assegnamenti di
+variabile, sono inclusi. Come ogni elemento di @code{ARGV} viene elaborato,
+@command{gawk} imposta @code{ARGIND} all'indice in @code{ARGV}
+dell'elemento corrente.
+
+@c FIXME: One day, move the ARGC and ARGV node closer to here.
+La modifica di @code{ARGC} e @code{ARGV} nel proprio programma @command{awk}
+consente di controllare come @command{awk} elabora i file in input; questo @`e
+descritto pi@`u dettagliatamente in @ref{ARGC e ARGV}.
+
+@cindex file in input, assegnamenti di variabile e
+@cindex assegnamenti di variabile e file in input
+La distinzione tra argomenti che sono @value{FN} e argomenti di assegnamento
+di variabili vien fatta quando @command{awk} deve aprire il successivo file di
+input.
+A quel punto dell'esecuzione, controlla la variabile @value{FN} per vedere se
+@`e piuttosto un assegnamento di variabile; se cos@`{@dotless{i}} @`e, @command{awk} imposta la
+variabile invece di leggere un file.
+
+Dunque, le variabili ricevono effettivamente i valori loro assegnati dopo che
+tutti i file precedentemente specificati sono stati letti. In particolare, i
+valori delle variabili assegnati in questo modo @emph{non} sono disponibili
+all'interno di una regola @code{BEGIN}
+(@pxref{BEGIN/END}),
+poich@'e tali regole vengono eseguite prima che @command{awk} cominci a
+esaminare la lista degli argomenti.
+
+@cindex angolo buio, sequenze di protezione
+I valori delle variabili dati sulla riga di comando sono elaborati per
+rimuovere sequenze di protezione (@pxref{Sequenze di protezione}).
+@value{DARKCORNER}
+
+In alcune implementazioni di @command{awk} molto vecchie, quando un
+assegnamento di variabile capitava prima di un qualsiasi @value{FN},
+l'assegnamento avveniva @emph{prima} che fosse stata eseguita la regola
+@code{BEGIN}. Il comportamento di @command{awk} era in questo modo
+ambiguo; alcuni assegnamenti da riga di comando erano disponibili
+all'interno della regola @code{BEGIN}, mentre altri no. Sfortunatamente,
+alcune applicazioni finivano per essere dipendenti da questa
+``funzionalit@`a''. Quando @command{awk} fu modificato per essere pi@`u
+coerente, fu aggiunta l'opzione @option{-v} a beneficio delle
+applicazioni che dipendevano dal vecchio comportamento.
+
+La funzionalit@`a dell'assegnamento di variabile @`e molto utile per assegnare
+valori a variabili come @code{RS}, @code{OFS}, e @code{ORS}, che controllano i
+formati di input e di output, prima di effettuare la scansione dei @value{DF}.
+@`E utile anche per effettuare passaggi multipli su un o stesso
+@value{DF}. Per esempio:
+
+@cindex file, passaggi multipli su
+@example
+awk 'pass == 1 @{ @var{pass 1 stuff} @}
+ pass == 2 @{ @var{pass 2 stuff} @}' pass=1 mydata pass=2 mydata
+@end example
+
+Una volta disponibile la funzionalit@`a per assegnare una variabile, l'opzione
+@option{-F} per impostare il valore di @code{FS} non @`e pi@`u strettamente
+necessaria. Rimane per compatibilit@`a all'indietro.
+
+@node Specificare lo standard input
+@section Come specificare lo standard input insieme ad altri file
+
+Capita spesso di voler leggere lo standard input assieme ad altri file.
+Per esempio, leggere un file, leggere lo standard input derivante da una
+@dfn{pipe}, e poi leggere un altro file.
+
+Il modo di indicare lo standard input, con tutte le versioni di @command{awk},
+@`e quello di usare un segno meno o trattino da solo, @samp{-}. Per esempio:
+
+@example
+@var{qualche_comando} | awk -f ilmioprogramma.awk file1 - file2
+@end example
+
+@noindent
+In questo caso, @command{awk} legge prima @file{file1}, poi legge
+l'output di @var{qualche_comando}, e infile legge
+@file{file2}.
+
+Si pu@`o anche usare @code{"-"} per indicare lo standard input quando si leggono
+i file con @code{getline} (@pxref{Getline file}).
+
+In aggiunta, @command{gawk} consente di specificare il
+@value{FN} speciale @file{/dev/stdin}, sia sulla riga di comando che
+quando si usa @code{getline}.
+Anche qualche altra versione di @command{awk} include questa funzionalit@`a,
+ma non @`e standard.
+(Alcuni sistemi operativi prevedono un file @file{/dev/stdin}
+nel filesystem; comunque, @command{gawk} elabora sempre
+questo @value{FN} per conto suo [ossia non importa se il sistema
+operativo rende disponibile il file o no].)
+
+@node Variabili d'ambiente
+@section Le variabili d'ambiente usate da @command{gawk}
+@cindex variabili d'ambiente usate da @command{gawk}
+
+Diverse variabili d'ambiente influiscono sul comportamento
+di @command{gawk}.
+
+@menu
+* AWKPATH (Variabile):: Ricerca di programmi @command{awk}
+ in una lista di directory.
+* AWKLIBPATH (Variabile):: Ricerca di librerie condivise
+ @command{awk} su varie directory.
+* Altre variabili d'ambiente:: Le variabili d'ambiente.
+@end menu
+
+@node AWKPATH (Variabile)
+@subsection Ricerca di programmi @command{awk} in una lista di directory.
+@cindex @env{AWKPATH}, variabile d'ambiente
+@cindex directory, ricerca di file sorgente
+@cindex percorso di ricerca per file sorgente
+@cindex ricerca, percorso di, per file sorgente
+@cindex differenze tra @command{awk} e @command{gawk}, variabile d'ambiente @env{AWKPATH}
+@ifinfo
+Il precedente @value{SECTION} ha descritto come i file di programma di
+@command{awk} possono essere specificati sulla riga di comando con
+l'opzione @option{-f}.
+@end ifinfo
+Nella maggior parte delle implementazioni di @command{awk} si deve indicare il
+percorso completo di ogni file di programma, a meno che il file non
+sia nella directory corrente. Con @command{gawk}, invece, se la
+variabile @value{FN} impostata con le opzioni @option{-f} o @option{-i} non
+contiene un separatore di directory @samp{/}, @command{gawk} cerca un file con
+quel nome in un elenco di directory (chiamato @dfn{percorso di ricerca}),
+scorrendole una per una.
+
+Il percorso di ricerca @`e una stringa di nomi di directory separati da due
+punti@footnote{Punti e virgola in MS-Windows.}. @command{gawk} prende
+il percorso di ricerca dalla variabile d'ambiente @env{AWKPATH}. Se questa
+variabile non esiste, o se ha un come valore la stringa nulla,
+@command{gawk} usa un percorso di default (descritto tra poco).
+
+La funzionalit@`a del percorso di ricerca @`e particolarmente utile per costruire
+librerie di funzioni di @command{awk}. I file di libreria possono essere messi
+in una directory standard inclusa nel percorso di ricerca
+e richiamati sulla riga di comando con un
+@value{FN} breve. Altrimenti, si dovrebbe scrivere l'intero @value{FN} per
+ciascun file.
+
+Usando l'opzione @option{-i}, o l'opzione @option{-f}, i programmi di
+@command{awk} scritti sulla riga di comando possono usare le funzionalit@`a
+contenute nei file di libreria di @command{awk}
+@iftex
+(@pxrefil{Funzioni di libreria}).
+@end iftex
+@ifnottex
+(@pxref{Funzioni di libreria}).
+@end ifnottex
+La ricerca del percorso non viene eseguita se @command{gawk} @`e in modalit@`a di
+compatibilit@`a, sia con l'opzione @option{--traditional} che con l'opzione
+@option{--posix}.
+@xref{Opzioni}.
+
+Se il file del codice sorgente non viene trovato con una prima ricerca,
+il percorso viene cercato di nuovo dopo aver aggiunto il suffisso
+@samp{.awk} al @value{FN}.
+
+Il meccanismo di ricerca del percorso di @command{gawk} @`e simile a quello
+della shell.
+(Si veda @uref{http://www.gnu.org/software/bash/manual/,
+@cite{The Bourne-Again SHell manual}}.)
+Un elemento nullo nel percorso indica la directory corrente.
+(Un elemento nullo @`e indicato iniziando o terminando il percorso con un segno
+di @samp{:} oppure mettendo due @samp{:} consecutivi [@samp{::}].)
+
+@quotation NOTA
+Per includere la directory corrente nel percorso di ricerca, si pu@`o
+aggiungere @file{.} come un elemento del percorso di ricerca, oppure
+inserire un elemento nullo.
+
+Diverse passate versioni di @command{gawk} avrebbero effettuato anche una
+ricerca esplicita nella directory corrente, prima o dopo aver esaminato il
+percorso di ricerca. A partire dalla @value{PVERSION} 4.1.2, questo non
+vale pi@`u; se si desidera una ricerca nella directory corrente, @`e
+necessario aggiungere @file{.} esplicitamente, oppure aggiungendo un
+elemento nullo al percorso di ricerca.
+@end quotation
+
+Il valore di default di @env{AWKPATH} @`e
+@samp{.:/usr/local/share/awk}.@footnote{La versione di @command{gawk}
+che state usando potrebbe usare una directory diversa; ci@`o dipende da come
+@command{gawk} @`e stato compilato e installato. La directory effettiva @`e il
+valore di @code{$(datadir)} generato quando @`e stato configurato
+@command{gawk}. Non @`e comunque il caso di preoccuparsi per questo.}
+Poich@'e @file{.} @`e incluso all'inizio, @command{gawk} cerca dapprima nella
+directory corrente, e poi in @file{/usr/local/share/awk}.
+In pratica, questo vuol dire che solo raramente ci sar@`a bisogno di cambiare
+il valore di @env{AWKPATH}.
+
+@xref{File da usare a inizio sessione}, per informazioni su funzioni che possono
+essere di aiuto per gestire la variabile @env{AWKPATH}.
+
+@command{gawk} memorizza il valore del percorso di ricerca in uso in
+@code{ENVIRON["AWKPATH"]}. Questo consente di aver accesso al valore del
+percorso di ricerca in uso all'interno di un programma @command{awk}.
+
+Sebbene la variabile @code{ENVIRON["AWKPATH"]} possa
+essere cambiata anche all'interno di
+un programma @command{awk}, questo non modifica il comportamento del
+programma in esecuzione. Questo comportamento ha una sua logica: la variabile
+d'ambiente @env{AWKPATH} @`e usata per trovare i file sorgenti del programma; una
+volta che il programma @`e in esecuzione, tutti i file sono stati trovati,
+e @command{gawk} non ha pi@`u bisogno di usare @env{AWKPATH}.
+
+@node AWKLIBPATH (Variabile)
+@subsection Ricerca di librerie condivise @command{awk} su varie directory.
+@cindex @env{AWKLIBPATH}, variabile d'ambiente
+@cindex directory, ricerca di estensioni caricabili
+@cindex percorso di ricerca per estensioni
+@cindex differenze tra @command{awk} e @command{gawk}, variabile d'ambiente @code{AWKLIBPATH}
+
+La variabile d'ambiente @env{AWKLIBPATH} @`e simile alla variabile @env{AWKPATH},
+ma @`e usata per ricercare estensioni caricabili (memorizzate come
+librerie condivise di sistema) specificate con l'opzione @option{-l},
+anzich@'e file sorgenti. Se l'estensione non viene trovata, il percorso viene
+cercato nuovamente dopo aver aggiunto il suffisso per la libreria condivisa
+appropriato per la piattaforma. Per esempio, sui sistemi GNU/Linux viene usato
+il suffisso @samp{.so}. Il percorso di ricerca specificato @`e usato anche
+attraverso la direttiva @code{@@load}
+(@pxref{Caricare librerie condivise}).
+
+Se la variabile d'ambiente @env{AWKLIBPATH} non esiste, o se ha come valore
+la stringa nulla, @command{gawk} usa un percorso di ricerca di default;
+questo normalmente vale @samp{/usr/local/lib/gawk}, anche se il suo valore
+pu@`o essere diverso, a seconda di come @`e stato installato @command{gawk}.
+
+@xref{File da usare a inizio sessione}, per informazioni su funzioni che possono
+essere di aiuto per gestire la variabile @env{AWKPATH}.
+
+@command{gawk} memorizza il valore del percorso di ricerca in uso in
+@code{ENVIRON["AWKLIBPATH"]}. Questo consente di aver accesso al valore del
+percorso di ricerca in uso all'interno di un programma @command{awk}.
+
+@node Altre variabili d'ambiente
+@subsection Le variabili d'ambiente.
+
+Molte altre variabili d'ambiente influenzano il comportamento di
+@command{gawk}, ma esse sono pi@`u specializzate. Quelle dell'elenco seguente
+sono quelle pi@`u utili agli utenti normali:
+
+@table @env
+@item GAWK_MSEC_SLEEP
+Specifica l'intervallo tra due tentativi di riconnessione,
+in millisecondi. Sui sistemi che non prevedono
+la chiamata di sistema @code{usleep()},
+il valore @`e arrotondato a un numero intero di secondi .
+
+@item GAWK_READ_TIMEOUT
+Specifica per quanto tempo, in millisecondi, @command{gawk}
+aspetta l'input prima di emettere un messaggio di errore.
+
+@item GAWK_SOCK_RETRIES
+Controlla il numero di volte che @command{gawk} cerca di
+ristabilire una connessione bidirezionale TCP/IP (@dfn{socket}) prima di
+rinunciare a farlo.
+@xref{Reti TCP/IP}.
+Si noti che quando @`e attiva l'opzione di continuazione dopo errori di I/O
+(@pxref{Continuazione dopo errori}),
+@command{gawk} tenta di aprire un @dfn{socket} TCP/IP soltanto una volta.
+
+@item POSIXLY_CORRECT
+Provoca il passaggio di @command{gawk} alla modalit@`a di compatibilit@`a POSIX,
+disabilitando tutte le estensioni tradizionali e GNU.
+@xref{Opzioni}.
+@end table
+
+Le variabili d'ambiente nell'elenco che segue sono utili
+soprattutto agli sviluppatori di @command{gawk} per il collaudo e la messa
+a punto del programma. Sono soggette a cambiamenti. Le variabili sono:
+
+@table @env
+@item AWKBUFSIZE
+Questa variabile riguarda solo @command{gawk} installato su sistemi
+conformi a POSIX.
+Col valore di @samp{exact}, @command{gawk} usa la dimensione di ogni file di
+input come dimensione del buffer di memoria da allocare per I/O. Altrimenti,
+il valore dovrebbe essere un numero, e @command{gawk} usa questo numero come
+dimensione del buffer da allocare. (Quando questa variabile non @`e impostata,
+@command{gawk} usa la pi@`u piccola tra le dimensioni del file e la dimensione
+del blocco di ``default'', che normalmente @`e la dimensione del blocco I/O
+del filesystem).
+
+@item AWK_HASH
+Se questa variabile @`e impostata con un valore di @samp{gst}, @command{gawk}
+usa la funzione hash di GNU Smalltalk per gestire i vettori.
+Questa funzione pu@`o essere leggermente pi@`u veloce della funzione standard.
+@item AWKREADFUNC
+Se questa variabile esiste, @command{gawk} legge i file sorgenti una riga per
+volta, anzich@'e a blocchi. Questa variabile @`e presente
+per problemi di debug su filesystem di sistemi operativi non POSIX,
+dove l'I/O @`e elaborato a record, non a blocchi.
+
+@item GAWK_MSG_SRC
+Se questa variabile esiste, @command{gawk} include il @value{FN} e il
+numero di riga all'interno del codice sorgente @command{gawk}
+dal quale sono stati generati i messaggi di avvertimento o
+i messaggi di errore grave. Il suo intento @`e quello di aiutare a isolare
+l'origine di un messaggio, poich@'e ci possono essere pi@`u righe di codice che
+producono lo stesso messaggio di avvertimento o di errore.
+
+@item GAWK_LOCALE_DIR
+Specifica la posizione dei file oggetto compilati contenenti la traduzione dei
+messaggi emessi da @command{gawk} stesso. Questa variabile @`e passata alla
+funzione @code{bindtextdomain()} nella fase di partenza di @command{gawk}.
+
+@item GAWK_NO_DFA
+Se questa variabile esiste, @command{gawk} non usa il riconoscitore di
+espressioni regolari ASFD [automa a stati finiti deterministico] per i tipi di
+test di corrispondenza. Questo pu@`o causare un rallentamento di @command{gawk}.
+Il suo intento @`e quello di aiutare a isolare le differenze tra i due
+riconoscitori di espressioni regolari che @command{gawk} usa internamente (non
+dovrebbero esserci differenze, ma a volte la teoria non coincide con la
+pratica).
+
+@item GAWK_STACKSIZE
+Specifica di quanto @command{gawk} dovrebbe accrescere il suo stack di
+valutazione interno, all'occorrenza.
+
+@item INT_CHAIN_MAX
+Specifica il numero massimo previsto di elementi che @command{gawk} mantiene
+su una catena hash per gestire i vettori indicizzati da numeri interi.
+
+@item STR_CHAIN_MAX
+Specifica il numero massimo previsto di elementi che @command{gawk} mantiene
+su una catena hash per gestire i vettori indicizzati da stringhe.
+
+@item TIDYMEM
+Se questa variabile esiste, @command{gawk} usa le chiamate di libreria
+@code{mtrace()} della @dfn{GNU C library} per aiutare a scoprire
+possibili sprechi di memoria.
+@end table
+
+@node Codice di ritorno
+@section Il codice di ritorno all'uscita da @command{gawk}
+
+@cindex codice di ritorno, di @command{gawk}
+@cindex stato d'uscita, di @command{gawk}
+Se l'istruzione @code{exit} viene usata con un valore
+(@pxref{Istruzione exit}), @command{gawk} termina l'esecuzione con il valore
+numerico specificato.
+
+Altrimenti, se non ci sono stati problemi durante l'esecuzione,
+@command{gawk} esce col valore della costante C
+@code{EXIT_SUCCESS}, che normalmente @`e zero.
+
+Se si verifica un errore, @command{gawk} esce col valore della
+costante C @code{EXIT_FAILURE}, che normalmente @`e uguale a uno.
+
+Se @command{gawk} esce a causa di un errore grave, il codice di ritorno
+@`e due. Sui sistemi non POSIX questo valore pu@`o essere mappato
+a @code{EXIT_FAILURE}.
+
+@node Includere file
+@section Come includere altri file nel proprio programma
+
+@c Panos Papadopoulos <panos1962@gmail.com> contributed the original
+@c text for this section.
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive una funzionalit@`a disponibile solo in
+@command{gawk}.
+
+@cindex @code{@@include}, direttiva
+@cindex direttiva @code{@@include}
+@cindex includere file, direttiva @code{@@include}
+La direttiva @code{@@include} pu@`o essere usata per leggere file sorgenti
+di @command{awk} esterni. Questo d@`a la possibilit@`a di suddividere file
+sorgenti di @command{awk} di grandi dimensioni in porzioni pi@`u piccole e pi@`u
+maneggevoli, e anche di riutilizzare codice @command{awk} di uso comune
+da diversi @dfn{script} @command{awk}. In altre parole, si possono
+raggruppare funzioni di @command{awk} usate per eseguire determinati compiti
+all'interno di file esterni. Questi file possono essere usati proprio come
+librerie di funzioni, usando la direttiva @code{@@include} assieme alla
+variabile d'ambiente @env{AWKPATH}. Si noti che i file sorgenti possono
+venire inclusi anche usando l'opzione @option{-i}.
+
+Vediamolo con un esempio.
+Iniziamo con due @dfn{script} @command{awk} (banali), che chiameremo
+@file{test1} e @file{test2}. Questo @`e lo @dfn{script} @file{test1}:
+
+@example
+BEGIN @{
+ print "Questo @`e lo script test1."
+@}
+@end example
+
+@noindent
+e questo @`e @file{test2}:
+
+@example
+@@include "test1"
+BEGIN @{
+ print "Questo @`e lo script test2."
+@}
+@end example
+
+L'esecuzione di @command{gawk} con @file{test2}
+produce il seguente risultato:
+
+@example
+$ @kbd{gawk -f test2}
+@print{} Questo @`e lo script test1.
+@print{} Questo @`e lo script test2.
+@end example
+
+@command{gawk} esegue lo @dfn{script} @file{test2}, il quale include
+@file{test1}, usando la direttiva @code{@@include}.
+Cos@`{@dotless{i}}, per includere file sorgenti di @command{awk} esterni, basta usare
+@code{@@include} seguito dal nome del file da includere,
+racchiuso tra doppi apici.
+
+@quotation NOTA
+Si tenga presente che questo @`e un costrutto del linguaggio e che @value{FN}
+non pu@`o essere una variabile di tipo stringa, ma solo una costante di tipo
+letterale racchiusa tra doppi apici.
+@end quotation
+
+I file da includere possono essere nidificati; p.es., dato un terzo
+@dfn{script}, che chiameremo @file{test3}:
+
+@example
+@@include "test2"
+BEGIN @{
+ print "Questo @`e lo script test3."
+@}
+@end example
+
+@noindent
+L'esecuzione di @command{gawk} con lo @dfn{script} @file{test3} produce i
+seguenti risultati:
+
+@example
+$ @kbd{gawk -f test3}
+@print{} Questo @`e lo script test1.
+@print{} Questo @`e lo script test2.
+@print{} Questo @`e lo script test3.
+@end example
+
+Il @value{FN}, naturalmente, pu@`o essere un nome di percorso.
+Per esempio:
+
+@example
+@@include "../funzioni_di_i_o"
+@end example
+
+@noindent
+e:
+
+@example
+@@include "/usr/awklib/network"
+@end example
+
+@noindent
+sono entrambi percorsi validi. La variabile d'ambiente @env{AWKPATH} pu@`o
+rivestire grande importanza quando si usa @code{@@include}. Le stesse
+regole per l'uso della variabile d'ambiente @env{AWKPATH} nelle ricerche
+da riga di comando
+(@pxref{AWKPATH (Variabile)}) si applicano anche a
+@code{@@include}.
+
+Questo @`e di grande aiuto nella costruzione di librerie di funzioni di
+@command{gawk}. Se si ha uno @dfn{script} di grandi dimensioni contenente
+utili funzioni @command{awk} di uso comune, lo si pu@`o suddividere in file
+di libreria e mettere questi file in una directory dedicata. In seguito si
+possono includere queste ``librerie'' usando il percorso completo dei
+file, o impostando opportunamente la variabile d'ambiente @env{AWKPATH} e
+quindi usando @code{@@include} con la sola parte del percorso completo che
+designa il file. Naturalmente,
+si possono tenere i file di libreria in pi@`u di una directory;
+pi@`u @`e complesso l'ambiente di lavoro, pi@`u
+directory possono essere necessarie per organizzare i file da includere.
+
+Vista la possibilit@`a di specificare opzioni @option{-f} multiple, il
+meccanismo @code{@@include} non @`e strettamente necessario.
+Comunque, la direttiva @code{@@include} pu@`o essere d'aiuto nel costruire
+programmi @command{gawk} autosufficienti, riducendo cos@`{@dotless{i}} la necessit@`a
+di scrivere righe di comando complesse e tediose.
+In particolare, @code{@@include} @`e molto utile per scrivere @dfn{script} CGI
+eseguibili da pagine web.
+
+Come @`e stato detto in @ref{AWKPATH (Variabile)}, i file sorgenti vengono
+sempre cercati nella directory corrente, prima di eseguire la ricerca in
+@env{AWKPATH}; questo si applica anche ai file indicati con
+@code{@@include}.
+
+@node Caricare librerie condivise
+@section Caricare librerie condivise nel proprio programma
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive una funzionalit@`a disponibile solo in
+@command{gawk}.
+
+@cindex @code{@@load}, direttiva
+@cindex direttiva @code{@@load}
+@cindex caricare estensioni, direttiva @code{@@load}
+@cindex estensioni, caricamento, direttiva @code{@@load}
+La direttiva @code{@@load} pu@`o essere usata per leggere estensioni di
+@command{awk} esterne (memorizzate come librerie condivise di sistema).
+Questo consente di collegare del codice compilato che pu@`o offrire prestazioni
+migliori o dare l'accesso a funzionalit@`a estese non incluse nel linguaggio
+@command{awk}. La variabile @env{AWKLIBPATH} viene usata per ricercare
+l'estensione. Usare @code{@@load} @'e del tutto equivalente a usare l'opzione da
+riga di comando @option{-l}.
+
+Se l'estensione non viene trovata in @env{AWKLIBPATH}, viene effettuata
+un'altra ricerca dopo aver aggiunto al @value{FN} il suffisso della
+libreria condivisa comunemente in uso per la piattaforma corrente. Per
+esempio, sui sistemi GNU/Linux viene usato il suffisso @samp{.so}:
+
+@example
+$ @kbd{gawk '@@load "ordchr"; BEGIN @{print chr(65)@}'}
+@print{} A
+@end example
+
+@noindent
+Questo @`e equivalente all'esempio seguente:
+
+@example
+$ @kbd{gawk -lordchr 'BEGIN @{print chr(65)@}'}
+@print{} A
+@end example
+
+@noindent
+Per l'uso da riga di comando @`e pi@`u conveniente l'opzione @option{-l},
+ma @code{@@load} @`e utile da inserire all'interno di un file sorgente di
+@command{awk} che richieda l'accesso a un'estensione.
+
+@ref{Estensioni dinamiche}, descrive come scrivere estensioni (in C or C++)
+che possono essere caricate sia con @code{@@load} che con l'opzione
+@option{-l}. @`E anche descritta l'estensione @code{ordchr}.
+
+@node Parti obsolete
+@section Opzioni e/o funzionalit@`a obsolete
+
+@c update this section for each release!
+
+@cindex opzioni deprecate
+@cindex funzionalit@`a deprecate
+@cindex obsolete, funzionalit@`a
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive funzionalit@`a o opzioni da riga di comando
+provenienti da precedenti versioni di @command{gawk} che non sono pi@`u
+disponibili nella versione corrente, o che sono ancora utilizzabili ma sono
+deprecate (ci@`o significa che @emph{non} saranno presenti nella prossima
+versione).
+
+I file speciali relativi ai processi @file{/dev/pid}, @file{/dev/ppid},
+@file{/dev/pgrpid} e @file{/dev/user} erano deprecati, ma ancora disponibili,
+in @command{gawk} 3.1. A partire dalla @value{PVERSION} 4.0, non sono
+pi@`u interpretati da @command{gawk} in modo speciale (al loro posto usare
+invece @code{PROCINFO}; si veda @ref{Variabili auto-assegnate}).
+
+@ignore
+This @value{SECTION}
+is thus essentially a place holder,
+in case some option becomes obsolete in a future version of @command{gawk}.
+@end ignore
+
+@node Non documentato
+@section Opzioni e funzionalit@`a non documentate
+@cindex non documentate, funzionalit@`a
+@cindex funzionalit@`a non documentate
+@cindex Skywalker, Luke
+@cindex Kenobi, Obi-Wan
+@cindex Jedi, Cavalieri
+@cindex Cavalieri Jedi
+@quotation
+@i{Usa il codice sorgente, Luke!}
+@author Obi-Wan
+@end quotation
+
+@cindex conchiglie, mare
+@ifnotinfo
+Questa @value{SECTION} @`e stata lasciata intenzionalmente vuota.
+@end ifnotinfo
+@ifinfo
+Questo @value{SECTION} @`e stato lasciato intenzionalmente vuoto.
+@end ifinfo
+
+@ignore
+@c If these came out in the Info file or TeX document, then they wouldn't
+@c be undocumented, would they?
+
+@command{gawk} ha un'opzione non documentata:
+
+@table @code
+@item -W nostalgia
+@itemx --nostalgia
+Stampa il messaggio @samp{awk: bailing out near line 1} e termina
+con un errore grave.
+Quest'opzione @`e stata ispirata dal comportamento comune delle primissime
+versioni di @command{awk} Unix e da una maglietta [con la scritta].
+Il messaggio @emph{NON} viene tradotto in ambienti non inglesi.
+@c so there! nyah, nyah.
+@end table
+
+Le prime versioni di @command{awk} non richiedevano alcun separatore (a capo
+
+o @samp{;}) tra le regole nei programmi @command{awk}. Quindi,
+era normale vedere programmi di una riga come:
+
+@example
+awk '@{ sum += $1 @} END @{ print sum @}'
+@end example
+
+@command{gawk} in realt@`a consente questo stile, ma la cosa non @`e
+documentata per non incoraggiare la pratica. Il modo corretto per scrivere
+quel programma @`e uno dei
+seguenti:
+
+@example
+awk '@{ sum += $1 @} ; END @{ print sum @}'
+@end example
+
+@noindent
+oppure:
+
+@example
+awk '@{ sum += $1 @}
+ END @{ print sum @}' data
+@end example
+
+@noindent
+@xref{Istruzioni/Righe}, per una spiegazione pi@`u ampia.
+
+Si possono inserire righe bianche dopo @samp{;} nei cicli @code{for}.
+Questa sembre essere stata una funzionalit@`a a lungo non documentata in
+@command{awk} Unix.
+
+Analogamente, si possono usare istruzioni @code{print} o @code{printf}
+nelle parti @var{valore-iniziale} e @var{incremento} di un ciclo
+@code{for}. Questa @`e un'altra funzionalit@`a a lungo non documentata in
+@command{awk} Unix.
+
+@command{gawk} consente di usare come nomi di parametro dei
+nomi di funzioni predefinite che facciano parte delle estensioni
+@command{gawk}, all'interno di funzioni definite dall'utente.
+Questo avviene per ``salvaguardare per il futuro'' vecchi programmi che
+utilizzino nomi di funzioni aggiunte da @command{gawk} dopo che questi
+programmi erano stati scritti.
+Le funzioni predefinite standard di command{awk}, per esempio
+@code{sin()} o @code{substr()} @emph{non} ammettono questa possibilit@`a.
+
+Il vettore @code{PROCINFO["argv"]} contiene tutti gli argomenti della
+riga di comando (una volta espansi i metacaratteri ed elaborata la
+ridirezione, nelle piattaforme in cui ci@`o dev'essere fatto manualmente
+dal programma), con indici che vanno da 0 as @code{argc} @minus{} 1.
+Per esempio, @code{PROCINFO["argv"][0]} conterr@`a il nome con cui @`e
+stato invocato @command{gawk}. L'esempio seguente mostra come @`e
+possibile usare questa funzionalit@`a:
+
+@example
+awk '
+BEGIN @{
+ for (i = 0; i < length(PROCINFO["argv"]); i++)
+ print i, PROCINFO["argv"][i]
+@}'
+@end example
+
+@`E da tener presente che questo vettore @`e diverso dal vettore
+standard @code{ARGV} che non comprende quegli argomenti della riga di
+comando che sono gi@`a stati elaborati da
+@command{gawk} (@pxref{ARGC e ARGV}).
+
+@end ignore
+
+@node Sommario invocazione
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+Per eseguire @command{awk} usare, o
+@samp{awk '@var{programma}' @var{file}}
+o
+@samp{awk -f @var{file-del-programma} @var{file}}.
+
+@item
+Le tre opzioni standard per tutte le versioni di @command{awk} sono
+@option{-f}, @option{-F} e @option{-v}. @command{gawk} fornisce queste e
+molte altre, come pure le opzioni estese corrispondenti scritte in stile GNU.
+
+@item
+Gli argomenti da riga di comando che non sono opzioni sono trattati normalmente
+come @value{FNS}, a meno che non abbiano la forma @samp{@var{var}=@var{valore}};
+nel qual caso vengono riconosciuti come assegnamenti di variabile da eseguire
+in quel punto
+nell'elaborazione dell'input.
+
+@item
+Tutti gli argomenti da riga di comando che non sono opzioni, escluso il testo
+del programma, vengono messe nel vettore @code{ARGV}. Modifiche a @code{ARGC}
+e @code{ARGV} influiscono su come @command{awk} elabora l'input.
+
+@item
+Si pu@`o usare un segno meno a s@'e stante (@samp{-}) per designare lo standard
+input sulla riga di comando. @command{gawk} consente anche di usare il
+@value{FN} speciale @file{/dev/stdin}.
+
+
+@item
+@command{gawk} tiene conto di diverse variabili d'ambiente;
+@env{AWKPATH}, @env{AWKLIBPATH} e @env{POSIXLY_CORRECT} sono le
+pi@`u importanti.
+
+@item
+Lo stato d'uscita di @command{gawk} invia informazioni al programma che lo
+ha invocato. Usare l'istruzione @code{exit} dall'interno di un programma
+@command{awk} per impostare il codice di ritorno.
+
+@item
+@command{gawk} consente di includere nel proprio programma file sorgenti di
+@command{awk} con la direttiva @code{@@include} o con le opzioni da riga di
+comando @option{-i} e @option{-f}.
+
+@item
+@command{gawk} consente di caricare funzioni aggiuntive scritte in C
+o C++ con la direttiva @code{@@load} e/o con l'opzione @option{-l}
+(questa funzionalit@`a avanzata @`e descritta pi@`u avanti, in
+@ref{Estensioni dinamiche}).
+@end itemize
+@node Espressioni regolari
+@chapter Espressioni regolari
+@cindex @dfn{regexp}
+@cindex espressioni regolari
+
+Una @dfn{espressione regolare}, o @dfn{regexp}, @`e un modo per descrivere un
+insieme di stringhe.
+Poich@'e le espressioni regolari sono una parte fondamentale della
+programmazione in @command{awk}, il loro formato e il loro uso meritano un
+@value{CHAPTER} a s@'e stante.
+
+@cindex barra (@code{/}), per delimitare le espressioni regolari
+@cindex @code{/} (barra), per delimitare le espressioni regolari
+Un'espressione regolare racchiusa tra barre (@samp{/})
+@`e un modello di ricerca @command{awk} che individua tutti i record in input
+il cui testo corrisponde al modello stesso.
+L'espressione regolare pi@`u semplice @`e una sequenza di lettere o di numeri, o
+di entrambi. Una tale @dfn{regexp} individua ogni stringa che contenga quella
+particolare sequenza.
+Quindi, la @dfn{regexp} @samp{pippo} individua ogni stringa che contenga
+@samp{pippo}. In altre parole, al modello di ricerca @code{/pippo/} corrisponde
+ogni record in input che contiene i cinque caratteri consecutivi @samp{pippo}
+@emph{in qualsiasi parte} del record. Altri tipi di @dfn{regexp} permettono
+di specificare classi di stringhe molto pi@`u complesse.
+
+@ifnotinfo
+All'inizio, gli esempi in questo @value{CHAPTER} sono semplici.
+Man mano che entriamo nei dettagli su
+come funzionano le espressioni regolari utilizzeremo formulazioni pi@`u
+complesse.
+@end ifnotinfo
+
+@menu
+* Uso di @dfn{regexp}:: Come usare le espressioni regolari.
+* Sequenze di protezione:: Come scrivere caratteri non stampabili.
+* Operatori di espressioni regolari:: Operatori di espressioni regolari.
+* Espressioni tra parentesi quadre:: Cosa possono contenere @samp{[...]}.
+* Pi@`u lungo da sinistra:: Quanto @`e lungo il testo individuato.
+* Espressioni regolari calcolate:: Usare @dfn{regexp} dinamiche.
+* Operatori di @dfn{regexp} GNU:: Operatori propri del software GNU.
+* Maiuscolo-Minuscolo:: Fare confronti ignorando
+ maiuscolo/minuscolo.
+* Sommario espressioni regolari:: Sommario delle espressioni regolari.
+@end menu
+
+@node Uso di @dfn{regexp}
+@section Uso di espressioni regolari
+
+@cindex espressioni regolari, come criteri di ricerca
+Un'espressione regolare pu@`o essere usata come modello di ricerca
+racchiudendola tra barre. L'espressione regolare @`e quindi confrontata
+con tutto il testo di ogni record (normalmente, basta che corrisponda a
+una parte qualsiasi del testo per risultare soddisfatta). Per esempio,
+il seguente programma stampa il secondo campo di ogni record in cui compaia
+la stringa @samp{li}, in qualsiasi parte del record:
+
+@example
+$ @kbd{awk '/li/ @{ print $2 @}' mail-list}
+@print{} 555-5553
+@print{} 555-0542
+@print{} 555-6699
+@print{} 555-3430
+@end example
+
+@cindex espressioni regolari, operatori
+@cindex operatori, ricerca in stringhe
+@c @cindex operators, @code{~}
+@cindex ricerca in stringhe, operatori
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+@c @cindex operatori, @code{!~}
+@cindex @code{if}, istruzione, uso di espressioni regolari in
+@cindex @code{while}, istruzione, uso di espressioni regolari in
+@cindex @code{do}-@code{while}, istruzione, uso di espressioni regolari in
+@c @cindex istruzione @code{if}
+@c @cindex istruzione @code{while}
+@c @cindex istruzione @code{do}
+Espressioni regolari possono anche essere usate in espressioni di confronto.
+Queste espressioni consentono di specificare le stringhe da riconoscere;
+non devono necessariamente comprendere l'intero record corrente. I due
+operatori @samp{~} e @samp{!~} confrontano espressioni regolari. Le
+espressioni che usano questi operatori possono essere usate come modelli di
+ricerca, o nelle istruzioni @code{if}, @code{while}, @code{for}, e @code{do}.
+(@xref{Istruzioni}.)
+Per esempio:
+
+@example
+@var{exp} ~ /@var{regexp}/
+@end example
+
+@noindent
+@`e verificata se l'espressione @var{exp} (intesa come stringa)
+corrisponde a @var{regexp}. L'esempio che segue individua, o sceglie,
+tutti i record in input in cui la lettera maiuscola @samp{J} @`e presente da
+qualche parte nel primo campo:
+
+@example
+$ @kbd{awk '$1 ~ /J/' inventory-shipped}
+@print{} Jan 13 25 15 115
+@print{} Jun 31 42 75 492
+@print{} Jul 24 34 67 436
+@print{} Jan 21 36 64 620
+@end example
+
+Lo stesso risultato si pu@`o ottenere anche cos@`{@dotless{i}}:
+
+@example
+awk '@{ if ($1 ~ /J/) print @}' inventory-shipped
+@end example
+
+Il prossimo esempio chiede che l'espressione @var{exp}
+(intesa come stringa)
+@emph{NON} corrisponda a @var{regexp}:
+
+@example
+@var{exp} !~ /@var{regexp}/
+@end example
+
+L'esempio che segue individua o sceglie tutti i record in input il cui
+primo campo @emph{NON} contiene
+la lettera maiuscola @samp{J}:
+
+@example
+$ @kbd{awk '$1 !~ /J/' inventory-shipped}
+@print{} Feb 15 32 24 226
+@print{} Mar 15 24 34 228
+@print{} Apr 31 52 63 420
+@print{} May 16 34 29 208
+@dots{}
+@end example
+
+@cindex @dfn{regexp}, costanti
+@cindex costanti @dfn{regexp}
+@cindex espressioni regolari, costanti, si veda costanti @dfn{regexp}
+Quando una @dfn{regexp} @`e racchiusa tra barre, come @code{/pippo/}, la chiamiamo
+una @dfn{costante regexp}, proprio come @code{5.27} @`e una costante
+numerica e @code{"pippo"} @`e una costante [di tipo] stringa.
+
+@node Sequenze di protezione
+@section Sequenze di protezione
+
+@cindex sequenze di protezione, in stringhe
+@cindex barra inversa (@code{\}), in sequenze di protezione
+@cindex @code{\} (barra inversa), in sequenze di protezione
+Alcuni caratteri non possono essere inclusi letteralmente in costanti
+stringa (@code{"pippo"}) o in costanti @dfn{regexp} (@code{/pippo/}).
+Vanno invece rappresentati usando @dfn{sequenze di protezione},
+ossia sequenze di caratteri preceduti da una barra inversa (@samp{\}).
+Una sequenza di protezione pu@`o essere usata per includere un carattere di
+"doppio apice" in una costante stringa. Poich@'e un semplice doppio apice
+termina la stringa, va usato @samp{\"} per richiedere che un doppio apice sia
+presente all'interno di una stringa. Per esempio:
+
+@example
+$ @kbd{awk 'BEGIN @{ print "Egli le disse \"ciao!\"." @}'}
+@print{} Egli le disse "ciao!".
+@end example
+
+Lo stesso carattere di barra inversa @`e un altro carattere che non pu@`o essere
+incluso normalmente; occorre scrivere @samp{\\} per inserire una barra
+inversa nella stringa o @dfn{regexp}. Quindi, la stringa costituita dai due
+caratteri @samp{"} e @samp{\} deve essere scritta come @code{"\"\\"}.
+
+Altre sequenze di protezione rappresentano caratteri non stampabili
+come TAB o il ritorno a capo. Anche se @`e possibile immettere la maggior parte dei
+caratteri non stampabili direttamente in una costante stringa o
+@dfn{regexp}, essi possono non essere di facile comprensione.
+
+La seguente lista elenca
+tutte le sequenze di protezione usate in @command{awk} e
+cosa rappresentano. Se non @`e detto altrimenti, tutte queste sequenze di
+protezione valgono sia per costanti stringa che per costanti @dfn{regexp}:
+
+@table @code
+@item \\
+Barra inversa letterale, @samp{\}.
+
+@c @cindex @command{awk} language, V.4 version
+@cindex @code{\} (barra inversa), @code{\a}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\a}, sequenza di protezione
+@item \a
+Il carattere ``campanello'', @kbd{Ctrl-g}, codice ASCII 7 (BEL).
+(Spesso genera qualche tipo di segnale sonoro udibile.)
+
+@cindex @code{\} (barra inversa), @code{\b}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\b}, sequenza di protezione
+@item \b
+Barra inversa, @kbd{Ctrl-h}, codice ASCII 8 (BS).
+
+@cindex @code{\} (barra inversa), @code{\f}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\f}, sequenza di protezione
+@item \f
+Nuova pagina, @kbd{Ctrl-l}, codice ASCII 12 (FF).
+
+@cindex @code{\} (barra inversa), @code{\n}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\n}, sequenza di protezione
+@item \n
+A capo, @kbd{Ctrl-j}, codice ASCII 10 (LF).
+
+@cindex @code{\} (barra inversa), @code{\r}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\r}, sequenza di protezione
+@item \r
+Ritorno del carrello, @kbd{Ctrl-m}, codice ASCII 13 (CR).
+
+@cindex @code{\} (barra inversa), @code{\t}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\t}, sequenza di protezione
+@item \t
+Tabulazione orizzontale, @kbd{Ctrl-i}, codice ASCII 9 (HT).
+
+@c @cindex @command{awk} language, V.4 version
+@cindex @code{\} (barra inversa), @code{\v}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\v}, sequenza di protezione
+@item \v
+Tabulazione verticale, @kbd{Ctrl-k}, codice ASCII 11 (VT).
+
+@cindex @code{\} (barra inversa), @code{\}@var{nnn}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\}@var{nnn}, sequenza di protezione
+@item \@var{nnn}
+Il valore ottale @var{nnn}, dove @var{nnn} pu@`o essere da 1 a 3 cifre ottali,
+tra @samp{0} e @samp{7}. Per esempio, il codice per il carattere ASCII ESC
+(escape) @`e @samp{\033}.
+
+@c @cindex @command{awk} language, V.4 version
+@c @cindex @command{awk} language, POSIX version
+@cindex @code{\} (barra inversa), @code{\x}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\x}, sequenza di protezione
+@cindex comuni, estensioni@comma{} @code{\x}, sequenza di protezione
+@cindex estensioni comuni, @code{\x}, sequenza di protezione
+@item \x@var{hh}@dots{}
+Il valore esadecimale @var{hh}, dove @var{hh} indica una sequenza di cifre
+esadecimali (@samp{0}--@samp{9}, e @samp{A}--@samp{F}
+o @samp{a}--@samp{f}). Dopo @samp{\x} @`e consentito un massimo di due cifre.
+Ogni ulteriore cifra esadecimale @`e considerata come una semplice
+lettera o numero. @value{COMMONEXT}
+(La sequenza di protezione @samp{\x} non @`e permessa in POSIX awk.)
+
+@quotation ATTENZIONE
+In ISO C, la sequenza di protezione continua fino a raggiungere il primo
+carattere che non sia una cifra esadecimale.
+In passato, @command{gawk} avrebbe continuato ad aggiungere
+cifre esadecimali al valore finch@'e non trovava una cifra non esadecimale
+oppure fino a raggiungere la fine della stringa.
+Comunque usare pi@`u di due cifre esadecimali produceva risultati indefiniti.
+Dalla @value{PVERSION} 4.2,
+vengono elaborate solo due cifre.
+@end quotation
+
+@cindex @code{\} (barra inversa), @code{\/}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\/}, sequenza di protezione
+@item \/
+Una barra (necessario solo per costanti @dfn{regexp}).
+Questa sequenza si usa per inserire una costante @dfn{regexp}
+che contiene una barra
+(come @code{/.*:\/home\/[[:alnum:]]+:.*/}; la notazione @samp{[[:alnum:]]}
+verr@`a spiegata pi@`u avanti,
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Espressioni tra parentesi quadre}).
+Poich@'e una @dfn{regexp} @`e racchiusa tra
+barre, si deve proteggere ogni barra che sia parte dell'espressione, per dire
+ad @command{awk} di andare avanti a scandire il resto della @dfn{regexp}.
+
+@cindex @code{\} (barra inversa), @code{\"}, sequenza di protezione
+@cindex barra inversa (@code{\}), @code{\"}, sequenza di protezione
+@item \"
+Un doppio apice (necessario solo per costanti stringa).
+Questa sequenza si usa per inserire in una costante stringa il carattere
+doppio apice
+(come @code{"Egli le disse \"ciao!\"."}).
+Poich@'e la stringa @`e racchiusa tra
+doppi apici, si deve proteggere ogni doppio apice che sia parte della stringa
+per dire ad @command{awk} di andare avanti a elaborare il resto della stringa.
+@end table
+
+In @command{gawk}, parecchie altre sequenze di due caratteri inizianti con
+con una barra inversa hanno un significato speciale nelle @dfn{regexp}.
+@ref{Operatori di @dfn{regexp} GNU}.
+
+In una @dfn{regexp}, una barra inversa che preceda un carattere non presente
+nella lista precedente, e non elencato in
+@ref{Operatori di @dfn{regexp} GNU},
+significa che il carattere seguente dovrebbe essere preso letteralmente,
+anche se normalmente sarebbe un operatore di @dfn{regexp}. Per esempio,
+@code{/a\+b/} individua i tre caratteri @samp{a+b}.
+
+@cindex barra inversa (@code{\}), in sequenze di protezione
+@cindex @code{\} (barra inversa), in sequenze di protezione
+@cindex portabilit@`a
+Per una completa portabilit@`a, non usare una barra inversa prima di qualsiasi
+carattere non incluso nella lista precedente, o che non sia un operatore.
+@c 11/2014: Moved so as to not stack sidebars
+@sidebar Barra inversa prima di un carattere normale
+@cindex portabilit@`a, barra inversa in sequenze di protezione
+@cindex POSIX @command{awk}, barre inverse in costanti stringa
+@cindex barra inversa (@code{\}), in sequenze di protezione, POSIX e
+@cindex @code{\} (barra inversa), in sequenze di protezione, POSIX e
+
+@cindex risoluzione di problemi, barra inversa prima di caratteri non speciali
+@cindex problemi, risoluzione di, barra inversa prima di caratteri non speciali
+Se si mette una barra inversa in una costante stringa prima di qualcosa che
+non sia uno dei caratteri elencati sopra, POSIX @command{awk} di proposito
+lascia indefinito il comportamento. Ci sono due possibilit@`a:
+
+@c @cindex automatic warnings
+@c @cindex warnings, automatic
+@cindex Brian Kernighan, @command{awk} di
+@table @asis
+@item Togliere la barra inversa
+Questo @`e quel che sia BWK @command{awk} che @command{gawk} fanno.
+Per esempio, @code{"a\qc"} equivale a @code{"aqc"}.
+(Poich@'e questo @`e un errore che pu@`o capitare o non capitare con la stessa
+probabilit@`a, @command{gawk} lo segnala).
+Volendo usare come separatore di campo @samp{FS = @w{"[ \t]+\|[ \t]+"}}
+ossia delle barre verticali precedute e seguite da almeno uno spazio,
+occorre mettere due barre inverse nella stringa:
+@samp{FS = @w{"[ \t]+\\|[ \t]+"}}.)
+@c I did this! This is why I added the warning.
+
+@cindex @command{gawk}, sequenze di protezione
+@cindex Unix @command{awk}, barre inverse in sequenze di protezione
+@cindex @command{mawk}, programma di utilit@`a
+@cindex programma di utilit@`a @command{mawk}
+@item Tenere la barra inversa cos@`{@dotless{i}} com'@`e.
+Alcune altre implementazioni di @command{awk} fanno questo.
+In quelle implementazioni, immettere @code{"a\qc"} equivale a immettere
+@code{"a\\qc"}.
+@end table
+@end sidebar
+Ricapitolando:
+
+@itemize @value{BULLET}
+@item
+Le sequenze di protezione nella lista di cui sopra sono sempre elaborate
+per prime, sia per le costanti stringa che per le costanti @dfn{regexp}. Questo
+viene fatto quasi subito, non appena @command{awk} legge il programma.
+
+@item
+@command{gawk} elabora sia costanti @dfn{regexp} che @dfn{regexp} dinamiche
+(@pxref{Espressioni regolari calcolate}),
+per gli operatori speciali elencati in
+@ref{Operatori di @dfn{regexp} GNU}.
+
+@item
+Una barra inversa prima di ogni altro carattere richiede di trattare quel
+carattere letteralmente.
+@end itemize
+
+@sidebar Sequenze di protezione per metacaratteri
+@cindex metacaratteri, sequenze di protezione per
+
+Supponiamo che si usi una protezione ottale o esadecimale
+per rappresentare un metacarattere di @dfn{regexp}
+(si veda @ref{Operatori di espressioni regolari}).
+@command{awk} considera il carattere come un carattere letterale o
+come un operatore di @dfn{regexp}?
+
+@cindex angolo buio, sequenze di protezione, per metacaratteri
+Storicamente, tali caratteri erano considerati letteralmente.
+@value{DARKCORNER}
+Invece, lo standard POSIX richiede che siano considerati
+come metacaratteri veri e propri, e questo @`e ci@`o che @command{gawk} fa.
+In modalit@`a compatibile (@pxref{Opzioni}),
+@command{gawk} tratta i caratteri scritti come sequenze ottali ed esadecimali
+letteramente, quando sono usati in costanti @dfn{regexp}. Quindi,
+@code{/a\52b/} @`e equivalente a @code{/a\*b/}.
+@end sidebar
+
+@node Operatori di espressioni regolari
+@section Operatori di espressioni regolari
+@cindex espressioni regolari, operatori
+@cindex metacaratteri in espressioni regolari
+
+@`E possibile inserire in espressioni regolari dei caratteri speciali,
+detti @dfn{operatori di espressioni regolari} o @dfn{metacaratteri}, per
+aumentarne il potere e la versatilit@`a.
+
+Le sequenze di protezione descritte
+@ifnotinfo
+prima
+@end ifnotinfo
+in @ref{Sequenze di protezione}
+sono valide all'interno di una @dfn{regexp}. Sono precedute da una @samp{\} e
+sono riconosciute e convertite nei caratteri reali corrispondenti nella
+primissima fase dell'elaborazione delle @dfn{regexp}.
+
+Ecco una lista dei metacaratteri. Tutti i caratteri che non sono sequenze
+di protezione e che non sono elencati qui rappresentano se stessi:
+
+@c Use @asis so the docbook comes out ok. Sigh.
+@table @asis
+@cindex barra inversa (@code{\}), operatore @dfn{regexp}
+@cindex barra inversa (@code{\}), operatore @dfn{regexp}
+@cindex @code{\} (barra inversa), operatore @dfn{regexp}
+@item @code{\}
+Si usa per togliere il significato speciale a un carattere quando si effettuano
+confronti. Per esempio, @samp{\$}
+individua il carattere @samp{$}.
+
+@cindex espressioni regolari, ancore nelle
+@cindex Texinfo, inizi di capitolo nei file
+@cindex @code{^} (circonflesso), operatore @dfn{regexp}
+@cindex circonflesso (@code{^}), operatore @dfn{regexp}
+@item @code{^}
+Si usa per indicare l'inizio di una stringa. Per esempio, @samp{^@@chapter}
+individua @samp{@@chapter} all'inizio di una stringa e si pu@`o usare per
+identificare inizi di capitoli in file sorgenti Texinfo.
+Il simbolo @samp{^} @`e conosciuto come @dfn{@`ancora}, perch@'e @`ancora la ricerca
+solo all'inizio della stringa.
+
+@`E importante notare che @samp{^} non individua un inizio di riga
+(il punto subito dopo un ritorno a capo @samp{\n}) che si trovi all'interno
+di una stringa. La condizione non @`e verificata nell'esempio seguente:
+
+@example
+if ("riga1\nRIGA 2" ~ /^R/) @dots{}
+@end example
+
+@cindex @code{$} (dollaro), operatore @dfn{regexp}
+@cindex dollaro (@code{$}), operatore @dfn{regexp}
+@item @code{$}
+Simile a @samp{^}, ma serve a indicare la fine di una stringa.
+Per esempio, @samp{p$}
+individua un record che termina con la lettera @samp{p}. Il @samp{$} @`e
+un'@`ancora e non individua una fine di riga (il punto immediatamente prima
+di un carattere di ritorno a capo @samp{\n})
+contenuta in una stringa.
+La condizione nell'esempio seguente non @`e verificata:
+
+@example
+if ("riga1\nRIGA 2" ~ /1$/) @dots{}
+@end example
+
+@cindex @code{.} (punto), operatore @dfn{regexp}
+@cindex punto (@code{.}), operatore @dfn{regexp}
+@item @code{.} (punto)
+Individua un qualsiasi carattere,
+@emph{incluso} il carattere di ritorno a capo. Per esempio, @samp{.P}
+individua ogni carattere in una stringa che sia seguito da una @samp{P}.
+Usando la concatenazione, si pu@`o formare un'espressione regolare come
+@samp{U.A}, che individua qualsiasi sequenza di tre caratteri che inizia con
+@samp{U} e finisce con @samp{A}.
+
+@cindex POSIX @command{awk}, uso del punto (@code{.})
+In modalit@`a POSIX stretta (@pxref{Opzioni}),
+@samp{.} non individua il carattere @sc{nul},
+ossia il carattere con tutti i bit uguali a zero.
+In altri contesti, @sc{nul} @`e solo un carattere qualsiasi. Altre versioni
+di @command{awk} possono non essere in grado di individuare il carattere
+@sc{nul}.
+
+@cindex @code{[]} (parentesi quadre), operatore @dfn{regexp}
+@cindex parentesi quadre (@code{[]}), operatore @dfn{regexp}
+@cindex espressioni tra parentesi
+@cindex insiemi di caratteri, si veda anche espressioni tra parentesi quadre
+@cindex liste di caratteri, si veda espressioni tra parentesi quadre
+@cindex classi di caratteri, si veda espressioni tra parentesi quadre
+@item @code{[}@dots{}@code{]}
+Questa @`e chiamata una @dfn{espressione tra parentesi quadre}.@footnote{In
+altri testi, un'espressione tra parentesi quadre potrebbe essere
+definita come @dfn{insieme di caratteri}, @dfn{classe di caratteri} o
+ @dfn{lista di caratteri}.}
+Individua @emph{uno} qualsiasi dei caratteri racchiusi tra
+parentesi quadre. Per esempio, @samp{[MVX]} individua uno qualsiasi
+dei caratteri @samp{M}, @samp{V}, o @samp{X} in una stringa. Una spiegazione
+esauriente di quel che si pu@`o mettere all'interno di un'espressione tra
+parentesi quadre @`e data in
+@ref{Espressioni tra parentesi quadre}.
+
+@cindex espressioni tra parentesi quadre, complementate
+@item @code{[^}@dots{}@code{]}
+Questa @`e una @dfn{espressione tra parentesi quadre complementata}. Il primo
+carattere dopo la @samp{[} @emph{deve} essere un @samp{^}. Individua
+qualsiasi carattere
+@emph{tranne} quelli tra parentesi quadre. Per esempio, @samp{[^awk]}
+individua qualsiasi carattere che non sia una @samp{a}, @samp{w}, o @samp{k}.
+
+@cindex @code{|} (barra verticale)
+@cindex barra verticale (@code{|})
+@item @code{|}
+Questo @`e un @dfn{operatore alternativa} ed @`e usato per specificare delle
+alternative. La @samp{|} ha la precedenza pi@`u bassa tra tutti gli operatori
+di espressioni regolari. Per esempio, @samp{^P|[aeiouy]} individua tutte le
+stringhe corrispondenti a @samp{^P} oppure a @samp{[aeiouy]}. Ci@`o significa
+che individua qualsiasi stringa che inizi con @samp{P} o contenga (in
+qualsiasi posizione al suo interno) una vocale inglese minuscola.
+
+L'alternativa si applica alle @dfn{regexp} pi@`u ampie individuabili in ogni
+lato.
+
+@cindex @code{()} (parentesi), operatore @dfn{regexp}
+@cindex parentesi (@code{()}), operatore @dfn{regexp}
+@item @code{(}@dots{}@code{)}
+Le parentesi sono usate per raggruppare, sia nelle espressioni regolari sia
+in quelle aritmetiche. Si possono usare per concatenare espressioni regolari
+che contengono l'operatore alternativa, @samp{|}. Per esempio,
+@samp{@@(samp|code)\@{[^@}]+\@}} individua sia @samp{@@code@{pippo@}} sia
+@samp{@@samp@{pluto@}}.
+(Queste sono sequenze in linguaggio Texinfo per controllare la formattazione.
+Il significato di @samp{+} @`e
+spiegato pi@`u avanti in questa lista.)
+
+@cindex @code{*} (asterisco), operatore @code{*}, come operatore @dfn{regexp}
+@cindex asterisco (@code{*}), operatore @code{*}, come operatore @dfn{regexp}
+@item @code{*}
+Questo simbolo richiede che la precedente espressione regolare sia
+ripetuta tante volte quanto serve per trovare una corrispondenza. Per
+esempio, @samp{ph*} applica il simbolo
+@samp{*} al carattere @samp{h} che lo precede immediatamente e ricerca
+corrispondenze costituite da una @samp{p} seguita da un numero qualsiasi di
+@samp{h}. Viene individuata anche solo la @samp{p}, se non ci sono
+@samp{h}.
+
+Ci sono due sfumature da capire sul funzionamento di @samp{*}.
+Primo, @samp{*} tiene conto solo del singolo componente dell'espressione
+regolare che lo precede (p.es., in @samp{ph*} vale solo per @samp{h}).
+Per fare s@`{@dotless{i}} che @samp{*} si applichi a una sottoespressione pi@`u estesa,
+occorre metterla tra parentesi:
+@samp{(ph)*} individua @samp{ph}, @samp{phph}, @samp{phphph} e cos@`{@dotless{i}} via.
+
+Secondo, @samp{*} trova quante pi@`u ripetizioni siano possibili. Se il testo
+da ricercare @`e @samp{phhhhhhhhhhhhhhooey}, @samp{ph*} individua tutte le
+@samp{h}.
+
+@cindex @code{+} (pi@`u), operatore @dfn{regexp}
+@cindex pi@`u (@code{+}), operatore @dfn{regexp}
+@item @code{+}
+Questo simbolo @`e simile a @samp{*}, tranne per il fatto che l'espressione
+precedente deve essere trovata almeno una volta. Questo significa che
+@samp{wh+y} individuerebbe @samp{why} e @samp{whhy}, ma non @samp{wy}, mentre
+@samp{wh*y} li troverebbe tutti e tre.
+
+@cindex @code{?} (punto interrogativo), operatore @dfn{regexp}
+@cindex punto interrogativo (@code{?}), operatore @dfn{regexp}
+@item @code{?}
+Questo simbolo @`e simile a @samp{*}, tranne per il fatto che l'espressione che
+precede pu@`o essere trovata una volta sola oppure non trovata
+affatto. Per esempio, @samp{fe?d}
+individua @samp{fed} e @samp{fd}, ma nient'altro.
+
+@cindex espressioni di intervallo, (@dfn{regexp})
+@item @code{@{}@var{n}@code{@}}
+@itemx @code{@{}@var{n}@code{,@}}
+@itemx @code{@{}@var{n}@code{,}@var{m}@code{@}}
+Uno o due numeri tra parentesi graffe rappresentano una
+@dfn{espressione di intervallo}.
+Se c'@`e un numero tra graffe, la @dfn{regexp} precedente @`e ripetuta
+@var{n} volte.
+Se ci sono due numeri separati da una virgola, la @dfn{regexp} precedente @`e
+ripetuta da @var{n} a @var{m} volte.
+Se c'@`e un numero seguito da una virgola, allora la @dfn{regexp} precedente
+@`e ripetuta almeno @var{n} volte:
+
+@table @code
+@item wh@{3@}y
+Riconosce @samp{whhhy}, ma non @samp{why} o @samp{whhhhy}.
+
+@item wh@{3,5@}y
+Riconosce soltanto @samp{whhhy}, @samp{whhhhy}, o @samp{whhhhhy}.
+
+@item wh@{2,@}y
+Riconosce @samp{whhy}, @samp{whhhy} e cos@`{@dotless{i}} via.
+@end table
+
+@cindex POSIX @command{awk}, espressioni di intervallo in
+Le espressioni di intervallo non erano tradizionalmente disponibili in
+@command{awk}. Sono state aggiunte come parte dello standard POSIX per
+rendere @command{awk} ed @command{egrep} coerenti tra di loro.
+
+@cindex @command{gawk}, espressioni di intervallo e
+In passato, poich@'e vecchi programmi possono usare @samp{@{} e @samp{@}} in
+costanti @dfn{regexp},
+@command{gawk} @emph{non} riconosceva espressioni di intervallo
+nelle @dfn{regexp}.
+
+Comunque, a partire dalla @value{PVERSION} 4.0,
+@command{gawk} riconosce espressioni di intervallo per default.
+Ci@`o accade perch@'e la compatibilit@`a con POSIX @`e ritenuta pi@`u
+importante da molti utenti @command{gawk} rispetto alla compatibilit@`a con
+dei vecchi programmi.
+
+Per programmi che usano @samp{@{} e @samp{@}} in costanti @dfn{regexp},
+@`e buona pratica proteggerli sempre con una barra inversa. Allora le
+costanti @dfn{regexp} sono valide e si comportano come desiderato, usando
+qualsiasi versione di @command{awk}.@footnote{@`E meglio usare due barre inverse
+se si sta usando una costante stringa con un operatore @dfn{regexp} o una
+funzione.}
+
+Infine, quando @samp{@{} e @samp{@}} appaiono in costanti @dfn{regexp}
+in un modo non interpretabile come espressione di intervallo
+(come in @code{/q@{a@}/}), allora sono prese letteralmente.
+@end table
+
+@cindex precedenza, operatore @dfn{regexp}
+@cindex espressioni regolari, operatori, precedenza di
+Nelle espressioni regolari, gli operatori @samp{*}, @samp{+}, e @samp{?},
+come pure le parentesi graffe @samp{@{} e @samp{@}},
+hanno
+la precedenza pi@`u alta, seguiti dalla concatenazione, e infine da @samp{|}.
+Come nell'algebra, le parentesi possono cambiare il raggruppamento degli
+operatori.
+@cindex POSIX @command{awk}, espressioni regolari e
+@cindex @command{gawk}, espressioni regolari, precedenza
+In POSIX @command{awk} e in @command{gawk}, gli operatori @samp{*},
+@samp{+}, e @samp{?} rappresentano se stessi quando non c'@`e nulla
+nella @dfn{regexp} che li precede. Per esempio, @code{/+/} individua un
+semplice segno pi@`u. Comunque, molte altre versioni di @command{awk}
+trattano una simile notazione come un errore di sintassi.
+
+Se @command{gawk} @`e in modalit@`a compatibile (@pxref{Opzioni}), le espressioni
+di intervallo non si possono usare nelle espressioni regolari.
+
+@node Espressioni tra parentesi quadre
+@section Usare espressioni tra parentesi quadre
+@cindex espressioni tra parentesi quadre
+@cindex espressioni tra parentesi quadre, espressioni di intervallo
+@cindex espressioni di intervallo, (@dfn{regexp})
+@cindex elenchi di caratteri in un'espressione regolare
+@cindex caratteri, elenchi di, in un'espressione regolare
+
+Come detto sopra, un'espressione tra parentesi quadre individua qualsiasi
+carattere incluso tra le parentesi quadre aperta e chiusa.
+
+All'interno di un'espressione tra parentesi quadre, una
+@dfn{espressione di intervallo} @`e formata da due caratteri separati da un
+trattino. Individua ogni singolo carattere compreso tra i due caratteri,
+ordinati secondo l'insieme di caratteri in uso nel sistema. Per esempio,
+@samp{[0-9]} @`e equivalente a @samp{[0123456789]}.
+(Si veda @ref{Intervalli e localizzazione} per una spiegazione di come
+lo standard POSIX e @command{gawk} sono cambiati nel corso degli anni.
+La cosa ha un interesse principalmente storico.)
+
+Con la crescente popolarit@`a dello
+@uref{http://www.unicode.org, standard di caratteri Unicode},
+c'@`e un'ulteriore dettaglio da tenere in conto. Le sequenze di
+protezione ottali ed esadecimali utilizzabili per inserire
+valori all'interno di espressioni tra parentesi quadre
+sono considerate contenere solo caratteri
+che occupano un unico byte (caratteri il cui valore stia
+nell'intervallo 0--256). Per individuare un intervallo di
+caratteri in cui i punti di inizio e fine dell'intervello
+abbiano valori maggiori di 256, occorre immettere direttamente
+le codifiche multi-byte dei caratteri in questione.
+
+@cindex @code{\} (barra inversa), in espressioni tra parentesi quadre
+@cindex barra inversa (@code{\}), in espressioni tra parentesi quadre
+@cindex @code{^} (circonflesso), in espressioni tra parentesi quadre
+@cindex circonflesso (@code{^}), in espressioni tra parentesi quadre
+@cindex @code{-} (meno), in espressioni tra parentesi quadre
+@cindex meno (@code{-}), in espressioni tra parentesi quadre
+Per includere uno dei caratteri @samp{\}, @samp{]}, @samp{-}, o @samp{^} in
+un'espressione tra parentesi quadre, occorre inserire un @samp{\} prima del
+carattere stesso. Per esempio:
+
+@example
+[d\]]
+@end example
+
+@noindent
+individua sia @samp{d} che @samp{]}.
+Inoltre, se si mette una @samp{]} subito dopo la
+@samp{[} aperta, la parentesi quadra chiusa @`e considerata come uno dei
+caratteri da individuare.
+
+@cindex POSIX @command{awk}, espressioni tra parentesi quadre e
+@cindex espressioni regolari estese (ERE)
+@cindex ERE (espressioni regolari estese)
+@cindex @command{egrep}, programma di utilit@`a
+@cindex programma di utilit@`a @command{egrep}
+L'utilizzo di @samp{\} nelle espressioni tra parentesi quadre
+@`e compatibile con altre implementazioni di @command{awk} ed @`e anche richiesto
+da POSIX.
+Le espressioni regolari in @command{awk} sono un insieme pi@`u esteso delle
+specificazioni POSIX per le espressioni regolari estese (ERE).
+Le ERE POSIX sono basate sulle espressioni regolari accettate dal
+tradizionale programma di utilit@`a @command{egrep}.
+
+@cindex espressioni tra parentesi quadre, classi di caratteri
+@cindex POSIX @command{awk}, espressioni tra parentesi quadre e, classi di caratteri
+Le @dfn{classi di caratteri} sono una funzionalit@`a introdotta nello standard
+POSIX. Una classe di caratteri @`e una particolare notazione per descrivere
+liste di caratteri cha hanno un attributo specifico, ma i caratteri
+veri e propri possono variare da paese a paese e/o
+da insieme di caratteri a insieme di caratteri. Per esempio, la nozione di
+cosa sia un carattere alfabetico @`e diversa tra gli Stati Uniti e la Francia.
+
+Una classe di caratteri @`e valida solo in una @dfn{regexp} @emph{contenuta}
+tra le parentesi quadre di un'espressione tra parentesi quadre. Le classi di
+caratteri consistono di @samp{[:},
+una parola chiave che segnala la classe, e @samp{:]}. La
+@ref{tabella-caratteri-classe} elenca le classi di caratteri definite dallo
+standard POSIX.
+
+@float Tabella,tabella-caratteri-classe
+@caption{classi di caratteri POSIX}
+@multitable @columnfractions .15 .85
+@headitem Classe @tab Significato
+@item @code{[:alnum:]} @tab Caratteri alfanumerici.
+@item @code{[:alpha:]} @tab Caratteri alfabetici.
+@item @code{[:blank:]} @tab Caratteri spazio e TAB.
+@item @code{[:cntrl:]} @tab Caratteri di controllo.
+@item @code{[:digit:]} @tab Caratteri numerici.
+@item @code{[:graph:]} @tab Caratteri che sono stampabili e visibili.
+(Uno @dfn{spazio} @`e stampabile ma non visibile, mentre una @samp{a} @`e l'uno e
+l'altro.)
+@item @code{[:lower:]} @tab Caratteri alfabetici minuscoli.
+@item @code{[:print:]} @tab Caratteri stampabili (caratteri che non sono
+caratteri di controllo).
+@item @code{[:punct:]} @tab Caratteri di punteggiatura (caratteri che non
+sono lettere, cifre, caratteri di controllo, o caratteri di spazio).
+@item @code{[:space:]} @tab Caratteri di spazio (come @dfn{spazio}, TAB, e
+@dfn{formfeed}, per citarne alcuni).
+@item @code{[:upper:]} @tab Caratteri alfabetici maiuscoli.
+@item @code{[:xdigit:]} @tab Caratteri che sono cifre esadecimali.
+@end multitable
+@end float
+
+Per esempio, prima dello standard POSIX, si doveva scrivere
+@code{/[A-Za-z0-9]/} per individuare i
+caratteri alfanumerici. Se l'insieme
+di caratteri in uso comprendeva altri caratteri alfabetici, l'espressione
+non li avrebbe individuati.
+Con le classi di caratteri POSIX si pu@`o scrivere
+@code{/[[:alnum:]]/} per designare i caratteri alfabetici e numerici
+dell'insieme di caratteri in uso.
+
+@c Thanks to
+@c Date: Tue, 01 Jul 2014 07:39:51 +0200
+@c From: Hermann Peifer <peifer@gmx.eu>
+Alcuni programmi di utilit@`a che cercano espressioni regolari prevedono
+una classe di caratteri, non standard,
+@samp{[:ascii:]}; @command{awk} non la prevede. Tuttavia, @`e possibile ottenere
+lo stesso risultato utilizzando @samp{[\x00-\x7F]}. Quest'espressione
+individua tutti i valori numerici tra zero e 127, che @`e l'intervallo definito
+dell'insieme di caratteri ASCII. Usando una lista di caratteri che esclude
+(@samp{[^\x00-\x7F]}) si individuano tutti i caratteri mono-byte che non
+sono nell'intervallo ASCII.
+
+@cindex espressioni tra parentesi quadre, elementi di collazione
+@cindex espressioni tra parentesi quadre, non-ASCII
+@cindex elementi di collazione
+In espressioni tra parentesi quadre possono apparire due ulteriori sequenze
+speciali. Riguardano insiemi di caratteri non-ASCII, che possono avere
+simboli singoli (chiamati @dfn{elementi di collazione}) che sono rappresentati
+con pi@`u di un carattere. Possono designare anche parecchi caratteri che sono
+equivalenti tra loro ai fini della @dfn{collazione}, o dell'ordinamento.
+(Per esempio, in francese, la semplice ``e'' e la sua versione con accento grave ``@`e''
+sono equivalenti). Queste sequenze sono:
+
+@table @asis
+@cindex espressioni tra parentesi quadre, elementi di collazione
+@cindex elementi di collazione
+@item elementi di collazione
+Elementi di collazione multi-byte racchiusi fra
+@samp{[.} e @samp{.]}. Per esempio, se @samp{ch} @`e un elemento di collazione,
+@samp{[[.ch.]]} @`e una @dfn{regexp} che individua questo elemento di
+collazione, mentre @samp{[ch]} @`e una @dfn{regexp} che individua le lettere
+@samp{c} o @samp{h}.
+
+@cindex espressioni tra parentesi quadre, classi di equivalenza
+@item classi di equivalenza
+Sono nomi, specifici a una particolare localizzazione, per una lista di
+caratteri equivalenti tra loro. Il nome @`e racchiuso fra
+@samp{[=} e @samp{=]}.
+Per esempio, il nome @samp{e} potrebbe essere usato per designare
+``e'', ``@^e'', ``@`e'', e ``@'e''. In questo caso, @samp{[[=e=]]} @`e una @dfn{regexp}
+che corrisponde a @samp{e}, @samp{@^e}, @samp{@`e} e @samp{@'e}.
+@end table
+
+Queste funzionalit@`a sono molto utili in localizzazioni non inglesi.
+
+@cindex internazionalizzazione, localizzazione, classi di caratteri
+@cindex @command{gawk}, classi di caratteri e
+@cindex POSIX @command{awk}, espressioni tra parentesi quadre e, classi di caratteri
+@quotation ATTENZIONE
+Le funzioni di libreria che @command{gawk} usa per individuare le espressioni
+regolari per ora riconoscono solo le classi di caratteri POSIX;
+non riconoscono simboli di collazione o classi di equivalenza.
+@end quotation
+@c maybe one day ...
+
+In un'espressione tra parentesi quadre, una parentesi aperta (@samp{[})
+che non costituisca l'inizio della specificazione di una classe di
+caratteri, di simboli di collazione o di una classe di equivalenza
+@`e interpretata letteralmente. Questo vale anche per @samp{.} e @samp{*}.
+
+@node Pi@`u lungo da sinistra
+@section Quanto @`e lungo il testo individuato?
+
+@cindex espressioni regolari, corrispondenza pi@`u a sinistra
+@c @cindex matching, leftmost longest
+Si consideri il caso seguente:
+
+@example
+echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}'
+@end example
+
+Questo esempio usa la funzione @code{sub()} per modificare il record in input.
+(@code{sub()} sostituisce la prima ricorrenza in ogni testo individuato dal
+primo argomento con la stringa fornita come secondo argomento;
+@pxref{Funzioni per stringhe}.) Qui, la @dfn{regexp} @code{/a+/} richiede
+``uno o pi@`u caratteri @samp{a},'' e il testo da sostituire @`e @samp{<A>}.
+
+L'input contiene quattro caratteri @samp{a}.
+Le espressioni regolari @command{awk} (e POSIX) individuano sempre
+la sequenza @emph{pi@`u lunga}, partendo da sinistra, di caratteri in input che
+corrispondono. Quindi, tutti e quattro i caratteri @samp{a} sono
+rimpiazzati con @samp{<A>} in questo esempio:
+
+@example
+$ @kbd{echo aaaabcd | awk '@{ sub(/a+/, "<A>"); print @}'}
+@print{} <A>bcd
+@end example
+
+Per semplici test corrisponde/non corrisponde, la cosa ha poca importanza.
+Ma se si sta controllando un testo o si fanno sostituzioni usando le funzioni
+@code{match()}, @code{sub()}, @code{gsub()} e @code{gensub()},
+@`e invece molto importante.
+@ifinfo
+@xref{Funzioni per stringhe},
+Per maggiori informazioni su queste funzioni.
+@end ifinfo
+Tenere in conto questo principio @`e importante anche quando si suddividono
+record e campi usando delle @dfn{regexp} (@pxref{Record},
+e anche @pxref{Separatori di campo}).
+
+@node Espressioni regolari calcolate
+@section Usare @dfn{regexp} dinamiche
+
+@cindex espressioni regolari calcolate
+@cindex espressioni regolari dinamiche
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+@c @cindex operators, @code{~}
+@c @cindex operators, @code{!~}
+L'espressione a destra di un operatore @samp{~} o @samp{!~} non deve
+necessariamente essere una costante @dfn{regexp} (cio@`e, una stringa di
+caratteri tra barre). Pu@`o essere una qualsiasi
+espressione. L'espressione @`e valutata e convertita in una stringa
+se necessario; il contenuto della stringa @`e poi usato come una @dfn{regexp}.
+Una @dfn{regexp} calcolata in questo modo @`e detta una @dfn{regexp dinamica}
+o una @dfn{regexp calcolata}:
+
+@example
+BEGIN @{ @dfn{regexp}_numerica = "[[:digit:]]+" @}
+$0 ~ @dfn{regexp}_numerica @{ print @}
+@end example
+
+@noindent
+Questo @dfn{script} imposta @code{regexp_numerica} come una @dfn{regexp} che
+descrive una o pi@`u cifre, e poi controlla se un record in input corrisponde a
+questa regexp.
+
+@quotation NOTA
+Usando gli operatori @samp{~} e @samp{!~}, si tenga presente che c'@`e
+una differenza tra una costante @dfn{regexp} racchiusa tra barre e una
+costante stringa racchiusa tra doppi apici.
+Se si intende utilizzare una costante stringa, occorre comprendere che
+la stringa @`e, in sostanza, scandita @emph{due volte}: la prima volta quando
+@command{awk} legge il programma, e la seconda volta quando va a
+confrontare la stringa a sinistra dell'operatore con il modello che sta
+alla sua destra. Questo vale per ogni espressione (come la
+@code{regexp_numerica}, vista nel precedente esempio), non solo per le
+costanti stringa.
+@end quotation
+
+@cindex costanti @dfn{regexp}, barre vs.@: doppi apici
+@cindex @code{\} (barra inversa), in costanti @dfn{regexp}
+@cindex barra inversa (@code{\}), in costanti @dfn{regexp}
+@cindex @code{"} (doppio apice), in costanti @dfn{regexp}
+@cindex doppio apice (@code{"}), in costanti @dfn{regexp}
+Che differenza fa la doppia scansione di una stringa?
+La risposta ha a che vedere con le sequenze di protezione e particolarmente
+con le barre inverse. Per inserire una barra inversa in un'espressione
+regolare all'interno di una stringa, occorre inserire @emph{due} barre
+inverse.
+
+Per esempio, @code{/\*/} @`e una costante @dfn{regexp} per designare un @samp{*}
+letterale.
+@`E richiesta una sola barra inversa. Per fare lo stesso con una stringa,
+occorre immettere @code{"\\*"}. La prima barra inversa protegge la
+seconda in modo che la stringa in realt@`a contenga i
+due caratteri @samp{\} e @samp{*}.
+
+@cindex risoluzione di problemi, costanti @dfn{regexp} vs.@: costanti stringa
+@cindex problemi, risoluzione di, costanti @dfn{regexp} vs.@: costanti stringa
+@cindex costanti @dfn{regexp}, vs.@: costanti stringa
+@cindex costanti stringa, vs.@: costanti @dfn{regexp}
+Dato che si possono usare sia costanti @dfn{regexp} che costanti stringa per
+descrivere espressioni regolari, qual @`e da preferire? La risposta @`e
+``costanti @dfn{regexp}'', per molti motivi:
+
+@itemize @value{BULLET}
+@item
+Le costanti stringa sono pi@`u complicate da scrivere e pi@`u difficili
+da leggere. Usare costanti @dfn{regexp} rende i programmi
+meno inclini all'errore. Non comprendere la differenza tra i due tipi di
+costanti @`e una fonte frequente di errori.
+
+@item
+@`E pi@`u efficiente usare costanti @dfn{regexp}. @command{awk} pu@`o accorgersi
+che @`e stata fornita una @dfn{regexp} e memorizzarla internamente in una forma
+che rende la ricerca di corrispondenze pi@`u efficiente. Se si usa una costante
+stringa, @command{awk} deve prima convertire la stringa nel suo formato
+interno e quindi eseguire la ricerca di corrispondenze.
+
+@item
+Usare costanti @dfn{regexp} @`e la forma migliore; lascia comprendere
+chiaramente che si vuole una corrispondenza con una @dfn{regexp}.
+@end itemize
+
+@sidebar Usare @code{\n} in espressioni tra parentesi quadre in @dfn{regexp} dinamiche
+@cindex espressioni regolari dinamiche, contenenti dei ritorni a capo
+@cindex ritorno a capo, in @dfn{regexp} dinamiche
+
+Alcune delle prime versioni di @command{awk} non consentono di usare il
+carattere di ritorno
+a capo all'interno di un'espressione tra parentesi quadre in @dfn{regexp}
+dinamiche:
+
+@example
+$ @kbd{awk '$0 ~ "[ \t\n]"'}
+@error{} awk: newline in character class [
+@error{} ]...
+@error{} source line number 1
+@error{} context is
+@error{} $0 ~ "[ >>> \t\n]" <<<
+@end example
+
+@cindex ritorno a capo, in costanti @dfn{regexp}
+Ma un ritorno a capo in una costante @dfn{regexp} non d@`a alcun problema:
+
+@example
+$ @kbd{awk '$0 ~ /[ \t\n]/'}
+@kbd{ecco una riga di esempio}
+@print{} ecco una riga di esempio
+@kbd{Ctrl-d}
+@end example
+
+@command{gawk} non ha questo problema, e non dovrebbe accadere spesso
+in pratica, ma val la pena di notarlo a futura memoria.
+@end sidebar
+
+@node Operatori di @dfn{regexp} GNU
+@section Operatori @dfn{regexp} propri di @command{gawk}
+
+@c This section adapted (long ago) from the regex-0.12 manual
+
+@cindex espressioni regolari, operatori, @command{gawk}
+@cindex @command{gawk}, espressioni regolari, operatori
+@cindex operatori, specifici per GNU
+@cindex espressioni regolari, operatori, per parole
+@cindex parola, definizione in @dfn{regexp}
+Il software GNU che ha a che fare con espressioni regolari comprende alcuni
+operatori @dfn{regexp} aggiuntivi. Questi
+operatori sono descritti in
+@ifnotinfo
+questa
+@end ifnotinfo
+@ifinfo
+questo
+@end ifinfo
+@value{SECTION} e sono specificamente
+per @command{gawk}; non sono disponibili in altre implementazioni di
+@command{awk}.
+La maggior parte degli operatori aggiuntivi riguarda l'identificazione di
+parole. Ai nostri fini, una @dfn{parola} @`e una sequenza di uno o pi@`u lettere,
+cifre, o trattini bassi (@samp{_}):
+
+@table @code
+@c @cindex operatori, @code{\s} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\s}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\s}, operatore (@command{gawk})
+@item \s
+Corrisponde a ogni carattere bianco.
+Lo si pu@`o pensare come un'abbreviazione di
+@w{@samp{[[:space:]]}}.
+
+@c @cindex operatori, @code{\S} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\S}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\S}, operatore (@command{gawk})
+@item \S
+Corrisponde a ogni carattere che non @`e uno spazio bianco.
+Lo si pu@`o pensare come un'abbreviazione di
+@w{@samp{[^[:space:]]}}.
+
+@c @cindex operatori, @code{\w} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\w}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\w}, operatore (@command{gawk})
+@item \w
+Corrisponde a ogni carattere che componga una parola; ovvero, corrisponde a
+ogni lettera, cifra, o trattino basso.
+Lo si pu@`o pensare come un'abbreviazione di
+@w{@samp{[[:alnum:]_]}}.
+
+@c @cindex operatori, @code{\W} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\W}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\W}, operatore (@command{gawk})
+@item \W
+Corrisponde a ogni carattere che non @`e parte di una parola.
+Lo si pu@`o pensare come un'abbreviazione di
+@w{@samp{[^[:alnum:]_]}}.
+
+@c @cindex operatori, @code{\<} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\<}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\<}, operatore (@command{gawk})
+@item \<
+Individua la stringa nulla all'inizio di una parola.
+Per esempio, @code{/\<via/} individua @samp{via} ma non
+@samp{funivia}.
+
+@c @cindex operatori, @code{\>} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\>}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\>}, operatore (@command{gawk})
+@item \>
+Individua la stringa nulla alla fine di una parola.
+Per esempio, @code{/via\>/} individua @samp{via} ma non @samp{viadotto}.
+
+@c @cindex operatori, @code{\y} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\y}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\y}, operatore (@command{gawk})
+@cindex limite-di-parola, individuare il
+@item \y
+Individua la stringa nulla o alla fine o all'inizio di una parola.
+(cio@`e, il limite di una parola - @dfn{boundar@strong{y}} in inglese).
+Per esempio, @samp{\yradar?\y}
+individua sia @samp{rada} che @samp{radar}, come parole separate.
+
+@c @cindex operatori, @code{\B} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\B}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\B}, operatore (@command{gawk})
+@item \B
+Individua la stringa nulla che ricorre all'interno di una parola.
+Per esempio,
+@code{/\Bora\B/} individua @samp{Colorado}, ma non individua @samp{che ora @`e}.
+@samp{\B} @`e essenzialmente l'opposto di @samp{\y}.
+@end table
+
+@cindex buffer, operatori per
+@cindex espressioni regolari, operatori, per buffer
+@cindex operatori, ricerca in stringhe, per buffer
+Ci sono due altri operatori che operano sui buffer. In Emacs un
+@dfn{buffer} @`e, naturalmente, un buffer di Emacs. In altri programmi GNU,
+fra cui @command{gawk}, le routine di libreria delle @dfn{regexp} considerano
+come buffer l'intera stringa su cui effettuare il confronto.
+Gli operatori sono:
+
+@table @code
+@item \`
+@c @cindex operatori, @code{\`} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\`}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\`}, operatore (@command{gawk})
+Individua la stringa nulla che occorre all'inizio di un buffer
+(di una stringa)
+
+@c @cindex operatori, @code{\'} (@command{gawk})
+@cindex barra inversa (@code{\}), @code{\'}, operatore (@command{gawk})
+@cindex @code{\} (barra inversa), @code{\'}, operatore (@command{gawk})
+@item \'
+Individua la stringa nulla che occorre alla fine di un buffer
+(di una stringa)
+@end table
+
+@cindex @code{^} (circonflesso), operatore @dfn{regexp}
+@cindex circonflesso (@code{^}), operatore @dfn{regexp}
+@cindex @code{?} (punto interrogativo), operatore @dfn{regexp}
+@cindex punto interrogativo (@code{?}), operatore @dfn{regexp}
+Poich@'e @samp{^} e @samp{$} si riferiscono sempre all'inizio e alla
+fine di stringhe, questi operatori non aggiungono nuove funzionalit@`a
+ad @command{awk}. Sono inclusi per compatibilit@`a con altro
+software GNU.
+
+@cindex @command{gawk}, operatore limite-di-parola
+@cindex limite-di-parola, operatore (@command{gawk})
+@cindex operatori, limite-di-parola (@command{gawk})
+In altro software GNU, l'operatore di limite-di-parola @`e @samp{\b}. Questo,
+comunque, @`e in conflitto con la definizione, nel linguaggio @command{awk},
+di @samp{\b} come
+backspace, quindi @command{gawk} usa una lettera differente.
+Un metodo alternativo sarebbe stato di richiedere due barre inverse negli
+operatori GNU, ma questo @`e stato ritenuto troppo arzigogolato. Il metodo
+corrente di usare @samp{\y} al posto del @samp{\b} di GNU sembra essere
+il male minore.
+
+@cindex espressioni regolari, @command{gawk}, opzioni sulla riga di comando
+@cindex @command{gawk}, opzioni sulla riga di comando, ed espressioni regolari
+Le varie opzioni sulla riga di comando
+(@pxref{Opzioni})
+controllano come @command{gawk} interpreta i caratteri nelle @dfn{regexp}:
+
+@table @asis
+@item Nessuna opzione
+Per default, @command{gawk} fornisce tutte le funzionalit@`a delle
+regexp POSIX e gli
+operatori @dfn{regexp} GNU
+@ifnotinfo
+predecentemente descritti.
+@end ifnotinfo
+@ifnottex
+@ifnotdocbook
+Sono descritti
+in @ref{Operatori di espressioni regolari}.
+@end ifnotdocbook
+@end ifnottex
+
+@item @code{--posix}
+Sono ammesse solo le @dfn{regexp} POSIX; gli operatori GNU non sono
+speciali (p.es., @samp{\w} individua una semplice lettera @samp{w}).
+Le espressioni di intervallo sono ammesse.
+
+@cindex Brian Kernighan, @command{awk} di
+@item @code{--traditional}
+Le @dfn{regexp} Unix tradizionali di @command{awk} sono ammesse. Gli
+operatori GNU non sono speciali, e le espressioni
+di intervallo non sono ammesse.
+Le classi di caratteri POSIX (@samp{[[:alnum:]]}, etc.) sono ammesse,
+poich@'e BWK @command{awk} le prevede.
+I caratteri descritti usando sequenze di protezione ottali ed esadecimali sono
+trattati letteralmente, anche se rappresentano metacaratteri di @dfn{regexp}.
+
+@item @code{--re-interval}
+Sono consentite espressioni di intervallo in @dfn{regexp},
+se @option{--traditional} @`e stata specificata.
+Altrimenti, le espressioni di intervallo sono disponibili per default.
+@end table
+
+@node Maiuscolo-Minuscolo
+@section Fare confronti ignorando maiuscolo/minuscolo
+
+@cindex espressioni regolari, maiuscolo/minuscolo
+@cindex @dfn{regexp}, maiuscolo/minuscolo
+@cindex maiuscolo/minuscolo e @dfn{regexp}
+Il tipo di carattere (maiuscolo/minuscolo) @`e normalmente rilevante nelle
+espressioni regolari, sia nella ricerca di
+caratteri normali (cio@`e, non metacaratteri), sia all'interno di espressioni
+fra parentesi. Quindi, una @samp{w} in un'espressione regolare individua
+solo una @samp{w} e non la corrispondente maiuscola @samp{W}.
+
+Il modo pi@`u semplice per richiedere una ricerca non sensibile al
+maiuscolo/minuscolo @`e di usare un'espressione tra parentesi quadre, per
+esempio @samp{[Ww]}. Comunque, questo pu@`o essere pesante se si usa spesso,
+e pu@`o rendere le espressioni regolari di difficile lettura.
+Ci sono due alternative che potrebbero essere preferibili.
+
+Un modo per fare un confronto non sensibile a maiuscolo/minuscolo in un
+particolare punto del programma
+@`e di convertire i dati in un solo tipo (o minuscole o maiuscole),
+usando le funzioni di stringa
+predefinite @code{tolower()} o @code{toupper()} (che non
+abbiamo ancora introdotto;
+@pxref{Funzioni per stringhe}).
+Per esempio:
+
+@example
+tolower($1) ~ /foo/ @{ @dots{} @}
+@end example
+
+@noindent
+converte il primo campo in minuscole, prima di fare un confronto.
+Questo funziona in ogni @command{awk} conforme allo standard POSIX.
+
+@cindex @command{gawk}, espressioni regolari, differenza maiuscolo/minuscolo
+@cindex distinzione maiuscolo/minuscolo, @command{gawk}
+@cindex differenze tra @command{awk} e @command{gawk}, espressioni regolari
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+@cindex @code{IGNORECASE}, variabile, con operatori @code{~} e @code{!~}
+@cindex @command{gawk}, variabile @code{IGNORECASE} in
+@c @cindex variables, @code{IGNORECASE}
+Un altro metodo, proprio di @command{gawk}, @`e di impostare la variabile
+@code{IGNORECASE} a un valore diverso da zero (@pxref{Variabili predefinite}).
+Quando @code{IGNORECASE} @`e diverso da zero, @emph{tutte} le operazioni con
+regexp e stringhe ignorano la distinzione maiuscolo/minuscolo.
+
+Il cambio del valore di @code{IGNORECASE} controlla dinamicamente la
+sensibilit@`a a maiuscolo/minuscolo del programma quando @`e in esecuzione.
+Il tipo di carattere (maiuscolo/minuscolo) @`e rilevante per default,
+poich@'e @code{IGNORECASE} (come la maggior parte delle variabili) @`e
+inizializzata a zero:
+
+@example
+x = "aB"
+if (x ~ /ab/) @dots{} # questo test non risulter@`a verificato
+
+IGNORECASE = 1
+if (x ~ /ab/) @dots{} # adesso sar@`a verificato
+@end example
+
+In generale, non @`e possibile usare @code{IGNORECASE} per rendere certe regole
+non sensibili a maiuscolo/minuscolo e altre regole invece s@`{@dotless{i}}, perch@'e non c'@`e
+una maniera diretta per impostare
+@code{IGNORECASE} solo per l'espressione di
+una particolare regola.@footnote{Programmatori esperti in C e C++ noteranno
+che questo @`e possible, usando qualcosa come
+@samp{IGNORECASE = 1 && /foObAr/ @{ @dots{} @}}
+e
+@samp{IGNORECASE = 0 || /foobar/ @{ @dots{} @}}.
+Comunque, questo @`e un po' tortuoso e non @`e raccomandato.}
+Per fare questo, si usino espressioni tra parentesi quadre oppure
+@code{tolower()}. Comunque, una cosa che si pu@`o fare con @code{IGNORECASE}
+soltanto @`e di utilizzare o di ignorare la sensibilit@`a a maiuscolo/minuscolo
+per tutte le regole contemporaneamente.
+
+@code{IGNORECASE} @`e impostabile dalla riga di comando o in una regola
+@code{BEGIN} (@pxref{Altri argomenti}; e
+@pxref{Usare BEGIN/END}).
+Impostare @code{IGNORECASE} dalla riga di comando @`e un modo per rendere
+un programma insensibile a maiuscolo/minuscolo senza doverlo modificare.
+
+@c @cindex ISO 8859-1
+@c @cindex ISO Latin-1
+In localizzazioni multibyte,
+le equivalenze tra caratteri maiuscoli
+e minuscoli sono controllate usando i valori in formato esteso
+dell'insieme di caratteri della localizzazione.
+Per il resto, i caratteri sono controllati usando l'insieme di caratteri
+ISO-8859-1 (ISO Latin-1).
+Questo insieme di caratteri @`e un'estensione del tradizionale insieme con 128
+caratteri ASCII, che include anche molti caratteri adatti
+per le lingue europee.@footnote{Se questo sembra oscuro,
+non c'@`e ragione di preoccuparsi; significa solo che @command{gawk} fa
+la cosa giusta.}
+
+Il valore di @code{IGNORECASE} non ha effetto se @command{gawk} @`e in
+modalit@`a compatibile (@pxref{Opzioni}).
+Il tipo di carattere (maiuscolo o minuscolo) @`e sempre rilevante in modalit@`a
+compatibile.
+
+@node Sommario espressioni regolari
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+Le espressioni regolari descrivono insiemi di stringhe da confrontare.
+In @command{awk}, le costanti @dfn{regexp} sono scritte racchiuse
+fra barre: @code{/}@dots{}@code{/}.
+
+@item
+Le costanti @dfn{regexp} possono essere usate da sole in modelli di ricerca e
+in espressioni condizionali, o come parte di espressioni di ricerca
+usando gli operatori @samp{~} e @samp{!~}.
+
+@item
+Le sequenze di protezione consentono di rappresentare caratteri non stampabili
+e consentono anche di rappresentare metacaratteri @dfn{regexp} come caratteri
+letterali per i quali cercare corrispondenze.
+
+@item
+Gli operatori @dfn{regexp} consentono raggruppamento, alternativa e
+ripetizione.
+
+@item
+Le espressioni tra parentesi quadre sono delle notazioni abbreviate per
+specificare insiemi di caratteri che possono avere corrispondenze in un
+punto particolare di una @dfn{regexp}.
+All'interno di espressioni tra parentesi quadre, le classi di caratteri POSIX
+consentono di specificare certi gruppi di caratteri in maniera indipendente
+dalla localizzazione.
+
+@item
+Le espressioni regolari individuano il testo pi@`u lungo possibile, a partire
+da sinistra nella stringa in esame. Questo ha importanza nei casi in cui
+serve conoscere la lunghezza della corrispondenza, come nella sostituzione di
+testo e quando il separatore di record sia una @dfn{regexp}.
+
+@item
+Espressioni di ricerca possono usare @dfn{regexp} dinamiche, ossia, i valori
+delle stringhe sono considerato come espressioni regolari.
+
+@item
+La variabile @command{gawk} @code{IGNORECASE} consente di controllare la
+differenza maiuscolo/minuscolo nel confronto mediante @dfn{regexp}. In altre
+versioni di @command{awk}, vanno usate invece le funzioni @code{tolower()} o
+@code{toupper()}.
+
+@end itemize
+
+@node Leggere file
+@chapter Leggere file in input
+
+@cindex leggere file in input
+@cindex file in input, leggere
+@cindex file in input
+@cindex @code{FILENAME}, variabile
+@cindex variabile @code{FILENAME}
+Nel tipico programma @command{awk},
+@command{awk} legge tutto l'input sia dallo standard input
+(per default @`e la tastiera, ma spesso @`e una @dfn{pipe} da un altro comando)
+o da file i cui nomi vengono specificati sulla riga di comando di
+@command{awk}. Se si specificano file in input, @command{awk} li legge
+nell'ordine, elaborando tutti i dati di uno prima di passare al successivo.
+Il nome del file in input corrente si trova nella variabile predefinita
+@code{FILENAME}
+(@pxref{Variabili predefinite}).
+
+@cindex record
+@cindex campi
+L'input @`e letto in unit@`a chiamate @dfn{record}, e viene elaborato, secondo le
+regole del programma, un record alla volta.
+Per default, ogni record @`e una riga. Ogni
+record @`e suddiviso automaticamente in "pezzi" chiamati @dfn{campi}.
+Questo rende pi@`u pratico far lavorare i programmi sulle parti di un record.
+
+@cindex @code{getline}, comando
+In rare occasioni, si potrebbe aver bisogno di usare il comando
+@code{getline}. Il comando @code{getline} @`e utile sia perch@'e pu@`o procurare
+un input esplicito da un numero indeterminato di file, sia perch@'e non vanno
+specificati sulla riga di comando di @command{awk} i nomi dei file usati con
+getline (@pxref{Getline}).
+
+@menu
+* Record:: Controllare come i dati sono suddivisi
+ in record.
+* Campi:: Un'introduzione ai campi.
+* Campi non costanti:: Numeri di campo variabili.
+* Cambiare i campi:: Cambiare il contenuto di un campo.
+* Separatori di campo:: I separatori di campo, e come
+ cambiarli.
+* Dimensione costante:: Leggere campi di larghezza costante.
+* Separazione in base al contenuto:: Definire campi dal loro contenuto.
+* Righe multiple:: Leggere record che sono su pi@`u righe.
+* Getline:: Leggere file sotto il controllo del
+ programma, usando la funzione
+ @code{getline}.
+* Timeout in lettura:: Leggere input entro un tempo limite.
+* Proseguire dopo errore in input:: Elaborare ulteriore input dopo certi
+ errori di I/O.
+* Directory su riga di comando:: Cosa succede mettendo una directory
+ sulla riga di comando.
+* Sommario di Input:: Sommario di Input.
+* Esercizi su Input:: Esercizi.
+@end menu
+
+@node Record
+@section Controllare come i dati sono suddivisi in record
+
+@cindex input, suddividere in record
+@cindex record, suddividere l'input in
+@cindex @code{NR}, variabile
+@cindex @code{FNR}, variabile
+@command{awk} suddivide l'input per il programma in record e campi.
+Tiene traccia del numero di record gi@`a letti dal
+file in input corrente. Questo valore @`e memorizzato in una variabile
+predefinita chiamata @code{FNR} che @`e reimpostata a zero ogni volta che si
+inizia un nuovo file. Un'altra variabile predefinita, @code{NR}, registra il
+numero totale di record in input gi@`a letti da tutti i @value{DF}.
+Il suo valore iniziale @`e zero ma non viene mai reimpostata a zero
+automaticamente.
+
+@menu
+* awk divisione record:: Come @command{awk} standard divide i record.
+* gawk divisione record:: Come @command{gawk} divide i record.
+@end menu
+
+@node awk divisione record
+@subsection Come @command{awk} standard divide i record.
+
+@cindex separatori di record
+@cindex record, separatori di
+I record sono separati da un carattere chiamato @dfn{separatore di record}.
+Per default, il separatore di record @`e il carattere di ritorno a capo.
+Questo @`e il motivo per cui i record sono, per default, righe singole.
+Per usare un diverso carattere come separatore di record
+basta assegnare quel carattere alla variabile predefinita @code{RS}.
+
+@cindex ritorno a capo, come separatore di record
+@cindex a capo, come separatore di record
+@cindex @code{RS}, variabile
+Come per ogni altra variabile,
+il valore di @code{RS} pu@`o essere cambiato nel programma @command{awk}
+con l'operatore di assegnamento, @samp{=}
+(@pxref{Operatori di assegnamento}).
+Il nuovo separatore di record dovrebbe essere racchiuso tra doppi apici,
+per indicare una costante di stringa. Spesso il momento giusto per far questo
+@`e all'inizio dell'esecuzione, prima che sia elaborato qualsiasi input,
+in modo che il primo record sia letto col separatore appropriato.
+Per far ci@`o, si usa il criterio speciale @code{BEGIN}
+(@pxref{BEGIN/END}).
+Per esempio:
+
+@example
+awk 'BEGIN @{ RS = "u" @}
+ @{ print $0 @}' mail-list
+@end example
+
+@noindent
+cambia il valore di @code{RS} in @samp{u}, prima di leggere qualsiasi input.
+Il nuovo valore @`e una stringa il cui primo carattere @`e la lettera ``u''; come
+risultato, i record sono separati dalla lettera ``u''. Poi viene letto il
+file in input, e la seconda regola nel programma @command{awk} (l'azione
+eseguita se non si specifica un criterio)
+stampa ogni record. Poich@'e ogni istruzione @code{print} aggiunge
+un ritorno a capo alla fine del suo output, questo programma
+@command{awk} copia l'input con ogni @samp{u} trasformato in un ritorno
+a capo. Qui vediamo il risultato dell'esecuzione del programma sul file
+@file{mail-list}:
+
+@example
+$ @kbd{awk 'BEGIN @{ RS = "u" @}}
+> @kbd{@{ print $0 @}' mail-list}
+@print{} Amelia 555-5553 amelia.zodiac
+@print{} sq
+@print{} e@@gmail.com F
+@print{} Anthony 555-3412 anthony.assert
+@print{} ro@@hotmail.com A
+@print{} Becky 555-7685 becky.algebrar
+@print{} m@@gmail.com A
+@print{} Bill 555-1675 bill.drowning@@hotmail.com A
+@print{} Broderick 555-0542 broderick.aliq
+@print{} otiens@@yahoo.com R
+@print{} Camilla 555-2912 camilla.inf
+@print{} sar
+@print{} m@@skynet.be R
+@print{} Fabi
+@print{} s 555-1234 fabi
+@print{} s.
+@print{} ndevicesim
+@print{} s@@
+@print{} cb.ed
+@print{} F
+@print{} J
+@print{} lie 555-6699 j
+@print{} lie.perscr
+@print{} tabor@@skeeve.com F
+@print{} Martin 555-6480 martin.codicib
+@print{} s@@hotmail.com A
+@print{} Sam
+@print{} el 555-3430 sam
+@print{} el.lanceolis@@sh
+@print{} .ed
+@print{} A
+@print{} Jean-Pa
+@print{} l 555-2127 jeanpa
+@print{} l.campanor
+@print{} m@@ny
+@print{} .ed
+@print{} R
+@print{}
+@end example
+
+@noindent
+Si noti che la voce relativa al nome @samp{Bill} non @`e divisa.
+Nel @value{DF} originale
+(@pxref{File dati di esempio}),
+la riga appare in questo modo:
+
+@example
+Bill 555-1675 bill.drowning@@hotmail.com A
+@end example
+
+@noindent
+Essa non contiene nessuna @samp{u}, per cui non c'@`e alcun motivo di dividere
+il record, diversamente dalle altre, che hanno una o pi@`u ricorrenze della
+@samp{u}. Infatti, questo record @`e trattato come parte del record precedente;
+il ritorno a capo che li separa nell'output @`e l'originale ritorno a capo nel
+@value{DF}, non quella aggiunta da @command{awk} quando ha stampato il record!
+
+@cindex separatori di record, cambiare i
+@cindex record, separatori di
+Un altro modo per cambiare il separatore di record @`e sulla riga di comando,
+usando la funzionalit@`a dell'assegnamento di variabile
+(@pxref{Altri argomenti}):
+
+@example
+awk '@{ print $0 @}' RS="u" mail-list
+@end example
+
+@noindent
+Questo imposta @code{RS} a @samp{u} prima di elaborare @file{mail-list}.
+
+Usando un carattere alfabetico come @samp{u} come separatore di record
+@`e molto probabile che si ottengano risultati strani.
+Usando un carattere insolito come @samp{/} @`e pi@`u probabile
+che si ottenga un comportamento corretto nella maggioranza dei casi, ma non
+c'@`e nessuna garanzia. La morale @`e: conosci i tuoi dati!
+
+Quando si usano caratteri normali come separatore di record,
+c'@`e un caso insolito che capita quando @command{gawk}
+@`e reso completamente conforme a POSIX (@pxref{Opzioni}).
+In quel caso, la seguente (estrema) @dfn{pipeline} stampa un sorprendente
+@samp{1}:
+
+@example
+$ echo | gawk --posix 'BEGIN @{ RS = "a" @} ; @{ print NF @}'
+@print{} 1
+@end example
+
+C'@`e un solo campo, consistente in un ritorno a capo. Il valore della
+variabile predefinita @code{NF} @`e il numero di campi nel record corrente.
+(Normalmente @command{gawk} tratta il ritorno a capo come uno spazio
+vuoto, stampando @samp{0} come risultato. Anche molte altre versioni di
+@command{awk} agiscono in questo modo.)
+
+@cindex angolo buio, file in input
+Il raggiungimento della fine di un file in input fa terminare il record di
+input corrente, anche se l'ultimo carattere nel file non @`e il carattere in
+@code{RS}. @value{DARKCORNER}
+
+@cindex stringhe vuote
+@cindex stringhe nulle
+@c @cindex strings, empty, see null strings
+La stringa nulla @code{""} (una stringa che non contiene alcun carattere)
+ha un significato particolare come
+valore di @code{RS}. Significa che i record sono separati
+soltanto da una o pi@`u righe vuote.
+@xref{Righe multiple} per maggiori dettagli.
+
+Se si cambia il valore di @code{RS} nel mezzo di un'esecuzione di
+@command{awk}, il nuovo valore @`e usato per delimitare i record successivi, ma
+non riguarda il record in corso di elaborazione e neppure quelli gi@`a
+elaborati.
+
+@cindex @command{gawk}, variabile @code{RT} in
+@cindex @code{RT}, variabile
+@cindex record, fine dei
+@cindex differenze tra @command{awk} e @command{gawk}, separatori di record
+@cindex espressioni regolari, come separatori di record
+@cindex record, separatori di, espressioni regolari come
+@cindex separatori di record, espressioni regolari come
+Dopo che @`e stata determinata la fine di un record, @command{gawk}
+imposta la variabile @code{RT} al testo nell'input che corrisponde a
+@code{RS}.
+
+@node gawk divisione record
+@subsection Divisione dei record con @command{gawk}
+
+@cindex estensioni comuni, @code{RS} come espressione regolare
+@cindex comuni, estensioni@comma{} @code{RS} come espressione regolare
+Quando si usa @command{gawk},
+il valore di @code{RS} non @`e limitato a una stringa costituita da un solo
+carattere, ma pu@`o essere qualsiasi espressione regolare
+@iftex
+(@pxrefil{Espressioni regolari}). @value{COMMONEXT}
+@end iftex
+@ifnottex
+(@pxref{Espressioni regolari}). @value{COMMONEXT}
+@end ifnottex
+In generale, ogni record termina alla stringa pi@`u vicina che corrisponde
+all'espressione regolare; il record successivo inizia alla fine della stringa
+che corrisponde. Questa regola generale @`e in realt@`a applicata anche nel caso
+normale, in cui @code{RS} contiene solo un ritorno a capo: un record
+termina all'inizio della prossima stringa che corrisponde (il prossimo
+ritorno a capo nell'input), e il record seguente inizia subito dopo la
+fine di questa stringa (al primo carattere della riga seguente).
+Il ritorno a capo, poich@'e corrisponde a @code{RS}, non appartiene a
+nessuno dei due record.
+
+Quando @code{RS} @`e un singolo carattere, @code{RT}
+contiene lo stesso singolo carattere. Peraltro, quando @code{RS} @`e
+un'espressione regolare, @code{RT} contiene l'effettivo testo in input
+corrispondente all'espressione regolare.
+
+Se il file in input termina senza che vi sia un testo che corrisponda a
+@code{RS}, @command{gawk} imposta @code{RT} alla stringa nulla.
+
+Il seguente esempio illustra entrambe queste caratteristiche.
+In quest'esempio @code{RS} @`e impostato a un'espressione regolare che
+cerca sia un ritorno a capo che una serie di una o pi@`u lettere
+maiuscole con uno spazio vuoto opzionale iniziale e/o finale:
+
+@example
+$ @kbd{echo record 1 AAAA record 2 BBBB record 3 |}
+> @kbd{gawk 'BEGIN @{ RS = "\n|( *[[:upper:]]+ *)" @}}
+> @kbd{@{ print "Record =", $0,"e RT = [" RT "]" @}'}
+@print{} Record = record 1 e RT = [ AAAA ]
+@print{} Record = record 2 e RT = [ BBBB ]
+@print{} Record = record 3 e RT = [
+@print{} ]
+@end example
+
+@noindent
+Le parentesi quadre racchiudono il contenuto di @code{RT}, rendendo visibile
+lo spazio vuoto iniziale e quello finale. L'ultimo valore di
+@code{RT} @`e un ritorno a capo.
+@xref{Programma sed semplice} per un esempio pi@`u utile
+su @code{RS} come espressione regolare e su @code{RT}.
+
+Se si imposta @code{RS} a un'espressione regolare che consente del testo
+finale opzionale, come @samp{RS = "abc(XYZ)?"} @`e possibile, per via di
+limitazioni dell'implementazione, che @command{gawk} possa trovare la parte
+iniziale dell'espressione regolare, ma non la parte finale, in modo
+particolare se il testo di input che potrebbe avere una corrispondenza con la
+parte finale @`e piuttosto lungo. @command{gawk} cerca di evitare questo
+problema, ma al momento non ci sono garanzie che questo funzioni sempre.
+
+@quotation NOTA
+Si ricordi che in @command{awk}, i metacaratteri di ancoraggio @samp{^} e
+@samp{$} trovano l'inizio e la fine di una @emph{stringa}, e non l'inizio e la
+fine di una @emph{riga}. Come risultato, qualcosa come
+@samp{RS = "^[[:upper:]]"} pu@`o solo corrispondere all'inizio di un file.
+Questo perch@'e @command{gawk} vede il file in input come un'unica lunga stringa
+in cui possono essere presenti dei caratteri di ritorno a capo.
+@`E meglio perci@`o evitare metacaratteri di ancoraggio nel valore di @code{RS}.
+@end quotation
+
+@cindex differenze tra @command{awk} e @command{gawk}, variabili @code{RS}/@code{RT}
+L'uso di @code{RS} come espressione regolare e la variabile @code{RT} sono
+estensioni @command{gawk}; non sono disponibili in
+modalit@`a compatibile
+(@pxref{Opzioni}).
+In modalit@`a compatibile, solo il primo carattere del valore di
+@code{RS} determina la fine del record.
+
+@sidebar @code{RS = "\0"} non @`e portabile
+@cindex portabilit@`a, file di dati come un unico record
+Ci sono casi in cui capita di dover trattare un intero @value{DF} come
+un record unico. L'unico modo di far questo @`e quello di dare a @code{RS}
+un valore che non ricorre nel file in input. Ci@`o @`e difficile da fare in modo
+generale, cos@`{@dotless{i}} che un programma possa
+funzionare con file in input arbitrari.
+
+Si potrebbe pensare che per i file di testo il carattere @sc{NUL}, che
+consiste di un carattere con tutti i bit uguali a zero, sia un buon valore da
+usare per @code{RS} in questo caso:
+
+@example
+BEGIN @{ RS = "\0" @} # l'intero file diventa un record?
+@end example
+
+@cindex differenze tra @command{awk} e @command{gawk}, stringhe, memorizzazione
+@command{gawk} di fatto lo accetta, e usa il carattere @sc{NUL}
+come separatore di record.
+Questo funziona per certi file speciali, come @file{/proc/environ} su sistemi
+GNU/Linux, dove il carattere @sc{NUL} @`e di fatto un separatore di record..
+Comunque, quest'uso @emph{non} @`e portabile sulla maggior parte delle
+implementazioni di @command{awk}.
+
+@cindex angolo buio, stringhe, memorizzazione
+Quasi tutte le altre implementazioni di @command{awk} @footnote{Almeno quelle
+che ci sono note.} memorizzano internamente le stringhe come stringhe
+in stile C. Le stringhe in stile C usano il carattere @sc{NUL} come
+terminatore di stringa. In effetti, questo significa che
+@samp{RS = "\0"} @`e lo stesso di @samp{RS = ""}.
+@value{DARKCORNER}
+
+Capita che recenti versioni di @command{mawk} possano usare i carattere
+@sc{NUL} come separatore di record. Comunque questo @`e un caso particolare:
+@command{mawk} non consente di includere caratteri @sc{NUL} nelle stringhe.
+(Ci@`o potrebbe cambiare in una versione futura di @command{mawk}.)
+
+@cindex record, trattare un file come un solo
+@cindex trattare un file, come un solo record
+@xref{Funzione readfile} per un modo interessante di leggere
+file interi. Se si usa @command{gawk}, si veda
+@ref{Esempio di estensione Readfile} per un'altra opzione.
+@end sidebar
+
+@node Campi
+@section Un'introduzione ai campi
+
+@cindex esaminare i campi
+@cindex campi
+@cindex accesso ai campi
+@cindex campi, esame dei
+Quando @command{awk} legge un record in input, il record @`e
+automaticamente @dfn{analizzato} o separato da @command{awk} in "pezzi"
+chiamati @dfn{campi}. Per default, i campi sono separati da
+@dfn{spazi vuoti}, come le parole in una riga stampata.
+Uno spazio vuoto in @command{awk} @`e qualsiasi stringa composta da uno o pi@`u
+spazi, segni di tabulazione o ritorni a capo;
+altri caratteri, come interruzione di pagina, tabulazione verticale, etc., che
+sono considerati spazi vuoti in altri linguaggi, @emph{non} sono considerati
+tali da @command{awk}.
+
+Lo scopo dei campi @`e quello di rendere pi@`u conveniente per l'utente far
+riferimento a questi frammenti dei record. Non @`e necessario usarli---si pu@`o
+operare sull'intero record, se si vuole---ma i campi sono ci@`o che rende
+cos@`{@dotless{i}} potenti dei semplici programmi @command{awk}.
+
+@cindex operatore di campo @code{$}
+@cindex @code{$} (dollaro), operatore di campo @code{$}
+@cindex dollaro (@code{$}), operatore di campo @code{$}
+@cindex operatore di campo, dollaro come
+Si usa il simbolo del dollaro (@samp{$})
+per far riferimento a un campo in un programma @command{awk},
+seguito dal numero del campo desiderato. Quindi, @code{$1}
+si riferisce al primo campo, @code{$2} al secondo, e cos@`{@dotless{i}} via.
+(Diversamente che nelle shell Unix, i numeri di campo non sono limitati a una
+sola cifra; @code{$127} @`e il centoventisettesimo campo nel record.)
+Per esempio, supponiamo che la seguente sia una riga in input:
+
+@example
+Questo pare essere un esempio proprio carino.
+@end example
+
+@noindent
+Qui il primo campo, o @code{$1}, @`e @samp{Questo}, il secondo campo, o
+@code{$2}, @`e @samp{pare}, e via dicendo. Si noti che l'ultimo campo,
+@code{$7}, @`e @samp{carino.}. Poich@'e non ci sono spazi tra la
+@samp{o} e il @samp{.}, il punto @`e considerato parte del settimo
+campo.
+
+@cindex @code{NF}, variabile
+@cindex campi, numero dei
+@code{NF} @`e una variabile predefinita il cui valore @`e il numero di campi nel
+record corrente. @command{awk} aggiorna automaticamente il valore di
+@code{NF} ogni volta che legge un record. Indipendentemente da quanti campi
+ci possano essere, l'ultimo campo in un record pu@`o essere rappresentato da
+@code{$NF}. Cos@`{@dotless{i}}, @code{$NF} @`e lo stesso di @code{$7}, che @`e @samp{carino.}.
+Se si cerca di far riferimento a un campo oltre l'ultimo
+(come @code{$8} quando il record ha solo sette campi), si ottiene
+la stringa nulla. (Se usato in un'operazione numerica si ottiene zero.)
+
+L'uso di @code{$0}, che sarebbe come un riferimento al campo ``numero zero'',
+@`e un caso particolare: rappresenta l'intero record in input. Si usa quando
+non si @`e interessati a un campo specifico. Vediamo qualche altro esempio:
+
+@example
+$ @kbd{awk '$1 ~ /li/ @{ print $0 @}' mail-list}
+@print{} Amelia 555-5553 amelia.zodiacusque@@gmail.com F
+@print{} Julie 555-6699 julie.perscrutabor@@skeeve.com F
+@end example
+
+@noindent
+Questo esempio stampa ogni record del file @file{mail-list} il cui primo campo
+contiene la stringa @samp{li}.
+
+Per converso, il seguente esempio cerca @samp{li} @emph{nell'intero record} e
+stampa il primo e l'ultimo campo di ogni record in input per cui @`e stata
+trovata una corrispondenza:
+
+@example
+$ @kbd{awk '/li/ @{ print $1, $NF @}' mail-list}
+@print{} Amelia F
+@print{} Broderick R
+@print{} Julie F
+@print{} Samuel A
+@end example
+
+@node Campi non costanti
+@section Numeri di campo variabili
+@cindex campi, numero dei
+@cindex numeri di campo
+
+Un numero di campo non @`e necessario che sia una costante. Nel linguaggio
+@command{awk} si pu@`o usare qualsiasi espressione dopo @samp{$} per far
+riferimento a un campo. Il valore dell'espressione specifica il numero di
+campo. Se il valore @`e una stringa, piuttosto che un numero, viene convertito
+in un numero. Consideriamo questo esempio:
+
+@example
+awk '@{ print $NR @}'
+@end example
+
+@noindent
+Ricordiamo che @code{NR} @`e il numero dei record letti fino a questo punto: uno
+nel primo record, due nel secondo, etc. Cos@`{@dotless{i}} quest'esempio stampa il primo
+campo del primo record, il secondo campo del secondo record, e cos@`{@dotless{i}} via.
+Per il ventesimo record, @`e stampato il campo numero 20; molto probabilmente il
+record ha meno di 20 campi, perci@`o stampa una riga vuota.
+Questo @`e un altro esempio sull'uso di espressioni come numeri di campo:
+
+@example
+awk '@{ print $(2*2) @}' mail-list
+@end example
+
+@command{awk} calcola l'espressione @samp{(2*2)} e usa il suo valore come
+numero del campo da stampare. Qui @samp{*} rappresenta la
+moltiplicazione, quindi l'espressione @samp{2*2} ha il valore quattro. Le
+parentesi vengono usate affinch@'e la moltiplicazione sia eseguita prima
+dell'operazione @samp{$}; sono necessarie ogni volta che c'@`e un operatore
+binario@footnote{A un @dfn{operatore binario}, come @samp{*} per la
+moltiplicazione, servono due operandi. La distinzione @`e necessaria poich@'e
+@command{awk} ha anche operatori unari (un operando) e ternari (tre
+operandi).}
+nell'espressione del numero di campo. Questo esempio, dunque, stampa il
+tipo di relazione (il quarto campo) per ogni riga del file
+@file{mail-list}. (Tutti gli operatori di @command{awk} sono elencati, in
+ordine decrescente di precedenza, in
+@ref{Precedenza}.)
+
+Se il numero di campo calcolato @`e zero, si ottiene l'intero record.
+Quindi, @samp{$(2-2)} ha lo stesso valore di @code{$0}. Numeri di campo
+negativi non sono consentiti; tentare di far riferimento a uno di essi
+normalmente fa terminare il programma. (Lo standard POSIX non chiarisce
+cosa succede quando si fa riferimento a un numero di campo negativo.
+@command{gawk} avvisa di questo e fa terminare il programma. Altre
+implementazioni di @command{awk} possono comportarsi in modo diverso.)
+
+Come accennato in @ref{Campi},
+@command{awk} memorizza il numero di campi del record corrente nella variabile
+predefinita @code{NF} (@pxref{Variabili predefinite}). Quindi,
+l'espressione @code{$NF} non @`e una funzionalit@`a speciale---@`e la diretta
+conseguenza della valutazione di @code{NF} e dell'uso di questo valore come
+numero di campo.
+
+@node Cambiare i campi
+@section Cambiare il contenuto di un campo
+
+@cindex campi, cambiare il contenuto dei
+Il contenuto di un campo, cos@`{@dotless{i}} come @`e visto da @command{awk}, pu@`o essere
+cambiato all'interno di un programma @command{awk}; questo cambia quello che
+@command{awk} percepisce come record in input corrente. (Il reale file in
+input non viene toccato; @command{awk} non modifica @emph{mai} il file in
+input).
+Si consideri il seguente esempio e il suo output:
+
+@example
+$ @kbd{awk '@{ numero_pacchi = $3 ; $3 = $3 - 10}
+> @kbd{print numero_pacchi, $3 @}' inventory-shipped}
+@print{} 25 15
+@print{} 32 22
+@print{} 24 14
+@dots{}
+@end example
+
+@noindent
+Il programma per prima cosa salva il valore originale del campo tre nella
+variabile @code{numero_pacchi}.
+Il segno @samp{-} rappresenta la sottrazione, cos@`{@dotless{i}} questo programma riassegna
+il campo tre, @code{$3}, come il valore originale del campo meno dieci:
+@samp{$3 - 10}. (@xref{Operatori aritmetici}.)
+Poi stampa il valore originale e quello nuovo del campo tre.
+(Qualcuno nel magazzino ha fatto un errore ricorrente nell'inventariare le
+scatole rosse.)
+
+Perch@'e questo funzioni, il testo in @code{$3} deve poter essere riconosciuto
+come un numero; la stringa di caratteri dev'essere convertita in un numero
+affich@'e il computer possa eseguire operazioni aritmetiche su di essa. Il
+numero che risulta dalla sottrazione viene nuovamente convertito in
+una stringa di caratteri che quindi diventa il campo tre.
+@xref{Conversione}.
+
+Quando il valore di un campo @`e cambiato (come percepito da @command{awk}), il
+testo del record in input viene ricalcolato per contenere il nuovo campo al
+posto di quello vecchio. In altre parole, @code{$0} cambia per riflettere il
+campo modificato. Questo programma
+stampa una copia del file in input, con 10 sottratto dal secondo campo di ogni
+riga:
+
+@example
+$ @kbd{awk '@{ $2 = $2 - 10; print $0 @}' inventory-shipped}
+@print{} Jan 3 25 15 115
+@print{} Feb 5 32 24 226
+@print{} Mar 5 24 34 228
+@dots{}
+@end example
+
+@`E possibile inoltre assegnare contenuti a campi che sono fuori
+intervallo. Per esempio:
+
+@example
+$ @kbd{awk '@{ $6 = ($5 + $4 + $3 + $2)}
+> @kbd{ print $6 @}' inventory-shipped}
+@print{} 168
+@print{} 297
+@print{} 301
+@dots{}
+@end example
+
+@cindex aggiungere, campi
+@cindex campi, aggiungere
+@noindent
+Abbiamo appena creato @code{$6}, il cui valore @`e la somma dei campi
+@code{$2}, @code{$3}, @code{$4} e @code{$5}. Il segno @samp{+}
+rappresenta l'addizione. Per il file @file{inventory-shipped}, @code{$6}
+rappresenta il numero totale di pacchi spediti in un determinato mese.
+
+La creazione di un nuovo campo cambia la copia interna di @command{awk} nel
+record in input corrente, che @`e il valore di @code{$0}. Cos@`{@dotless{i}}, se si scrive
+@samp{print $0} dopo aver aggiunto un campo, il record stampato include il
+nuovo campo, col numero di separatori di campo appropriati tra esso e i
+campi originariamente presenti.
+
+@cindex @code{OFS}, variabile
+@cindex output, separatore di campo, si veda @code{OFS}, variabile
+@cindex campo, separatori di, si veda anche @code{OFS}
+@cindex separatori di campo, si veda anche @code{OFS}
+Questa ridefinizione influenza ed @`e influenzata da
+@code{NF} (il numero dei campi; @pxref{Campi}).
+Per esempio, il valore di @code{NF} @`e impostato al numero del campo pi@`u
+elevato che @`e stato creato.
+Il formato preciso di @code{$0} @`e influenzato anche da una funzionalit@`a che
+non @`e ancora stata trattata: il @dfn{separatore di campo di output},
+@code{OFS}, usato per separare i campi (@pxref{Separatori di output}).
+
+Si noti, comunque, che il mero @emph{riferimento} a un campo fuori
+intervallo @emph{non} cambia il valore di @code{$0} o di @code{NF}.
+Far riferimento a un campo fuori intervallo produce solo una stringa nulla.
+Per esempio:
+
+@example
+if ($(NF+1) != "")
+ print "non @`e possibile"
+else
+ print "@`e tutto normale"
+@end example
+
+@noindent
+dovrebbe stampare @samp{@`e tutto normale}, perch@'e @code{NF+1} @`e certamente
+fuori intervallo. (@xref{Istruzione if}
+per maggiori informazioni sulle istruzioni @code{if-else} di @command{awk}.
+@xref{Tipi di variabile e confronti}
+per maggiori informazioni sull'operatore @samp{!=}.)
+
+@`E importante notare che facendo un assegnamento a un campo esistente cambia
+il valore di @code{$0} ma non cambia il valore di @code{NF},
+anche qualora si assegni a un campo la stringa nulla. Per esempio:
+
+@example
+$ @kbd{echo a b c d | awk '@{ OFS = ":"; $2 = ""}
+> @kbd{print $0; print NF @}'}
+@print{} a::c:d
+@print{} 4
+@end example
+
+@noindent
+Il campo @`e ancora l@`{@dotless{i}}; ha solo un valore vuoto, delimitato dai due "due punti"
+tra @samp{a} e @samp{c}.
+Questo esempio mostra cosa succede se si crea un nuovo campo:
+
+@example
+$ @kbd{echo a b c d | awk '@{ OFS = ":"; $2 = ""; $6 = "nuovo"}
+> @kbd{print $0; print NF @}'}
+@print{} a::c:d::nuovo
+@print{} 6
+@end example
+
+@noindent
+Il campo intermedio, @code{$5}, @`e creato con un valore vuoto
+(indicato dalla seconda coppia di due punti adiacenti),
+e @code{NF} @`e aggiornato col valore sei.
+
+@cindex angolo buio, variabile @code{NF}, decremento
+@cindex @code{NF}, variable, decremento
+Decrementando @code{NF} si eliminano i campi
+dopo il nuovo valore di @code{NF} e si ricalcola @code{$0}.
+@value{DARKCORNER}
+Vediamo un esempio:
+
+@example
+$ @kbd{echo a b c d e f | awk '@{ print "NF =", NF;}
+> @kbd{ NF = 3; print $0 @}'}
+@print{} NF = 6
+@print{} a b c
+@end example
+
+@cindex portabilit@`a, variabile @code{NF}@comma{} decremento
+@quotation ATTENZIONE
+Alcune versioni di @command{awk} non
+ricostruiscono @code{$0} quando @code{NF} viene diminuito.
+@end quotation
+
+Infine, ci sono casi in cui conviene forzare
+@command{awk} a ricostruire l'intero record, usando i valori correnti
+dei campi e @code{OFS}. Per far ci@`o, si usa
+l'apparentemente innocuo assegnamento:
+
+@example
+$1 = $1 # forza la ricostruzione del record
+print $0 # o qualsiasi altra cosa con $0
+@end example
+
+@noindent
+Questo forza @command{awk} a ricostruire il record. Aggiungere un commento
+rende tutto pi@`u chiaro, come abbiamo appena visto.
+
+C'@`e un rovescio della medaglia nella relazione tra @code{$0} e
+i campi. Qualsiasi assegnamento a @code{$0} fa s@`{@dotless{i}} che il record sia
+rianalizzato (sintatticamente) e ridiviso in campi usando il valore
+@emph{corrente} di @code{FS}. Questo si applica anche a qualsiasi funzione
+predefinita che aggiorna @code{$0}, come @code{sub()} e @code{gsub()}
+(@pxref{Funzioni per stringhe}).
+
+@sidebar Comprendere @code{$0}
+
+@`E importante ricordare che @code{$0} @`e @emph{l'intero}
+record, esattamente com'@`e stato letto dall'input, compresi tutti gli spazi
+vuoti iniziali e finali, e l'esatto spazio vuoto (o altri caratteri) che
+separa i campi.
+
+@`E un errore comune tentare di cambiare il separatore di campo in un record
+semplicemente impostando @code{FS} e @code{OFS}, e poi
+aspettarsi che un semplice @samp{print} or @samp{print $0} stampi il record
+modificato.
+
+Questo non funziona, poich@'e non @`e stato fatto niente per cambiare quello
+stesso record. Invece, si deve forzare la ricostruzione del record,
+tipicamente con un'istruzione come @samp{$1 = $1}, come descritto
+in precedenza.
+@end sidebar
+
+
+@node Separatori di campo
+@section Specificare come vengono separati i campi
+
+@menu
+* Separatori di campo di default:: Come di solito sono separati i campi.
+* Separare campi con @dfn{regexp}:: Usare @dfn{regexp} come separatori.
+* Campi di un solo carattere:: Fare di ogni carattere un campo
+ separato.
+* Separatori campo da riga di comando:: Assegnare @code{FS} dalla riga di
+ comando.
+* Campo intera riga:: Far s@`{@dotless{i}} che la riga intera sia un
+ campo solo.
+* Sommario sulla separazione campi:: Alcuni punti finali e una tavola di
+ sommario.
+@end menu
+
+@cindex @code{FS}, variabile
+@cindex campi, separare
+@cindex campo, separatori di
+Il @dfn{separatore di campo}, che @`e un carattere singolo o un'espressione
+regolare, controlla il modo in cui @command{awk} suddivide un record in input
+in campi. @command{awk} fa una scansione del record in input per trovare i
+caratteri che individuano il separatore; i campi sono il testo compreso tra i
+separatori trovati.
+
+Nell'esempio che segue, usiamo il simbolo del punto elenco (@bullet{}) per
+rappresentare gli spazi nell'output.
+Se il separatore di campo @`e @samp{oo}, la seguente riga:
+
+@example
+moo goo gai pan
+@end example
+
+@noindent
+@`e suddivisa in tre campi: @samp{m}, @samp{@bullet{}g}, e
+@samp{@bullet{}gai@bullet{}pan}.
+Notare gli spazi iniziali nei valori del secondo e del terzo campo.
+
+@cindex risoluzione di problemi, @command{awk} usa @code{FS} anzich@'e @code{IFS}
+@cindex problemi, risoluzione di, @command{awk} usa @code{FS} anzich@'e @code{IFS}
+Il separatore di campo @`e rappresentato dalla variable predefinita @code{FS}.
+I programmatori di shell notino: @command{awk} @emph{non} usa il
+nome @code{IFS} che @`e usato dalle shell conformi a POSIX (come
+la Unix Bourne shell, @command{sh}, o Bash).
+
+@cindex @code{FS}, variabile, cambiare il valore di una
+Il valore di @code{FS} si pu@`o cambiare nel programma @command{awk} con
+l'operatore di assegnamento, @samp{=} (@pxref{Operatori di assegnamento}).
+Spesso il momento giusto per far ci@`o @`e all'inizio dell'esecuzione
+prima che sia stato elaborato qualsiasi input, cos@`{@dotless{i}} che il primo record
+sia letto col separatore appropriato. Per far questo, si usa il modello di
+ricerca speciale
+@code{BEGIN}
+(@pxref{BEGIN/END}).
+Per esempio, qui impostiamo il valore di @code{FS} alla stringa
+@code{","}:
+
+@example
+awk 'BEGIN @{ FS = "," @} ; @{ print $2 @}'
+@end example
+
+@cindex @code{BEGIN}, criterio di ricerca
+@noindent
+Data la riga in input:
+
+@example
+John Q. Smith, 29 Oak St., Walamazoo, MI 42139
+@end example
+
+@noindent
+questo programma @command{awk} estrae e stampa la stringa
+@samp{@bullet{}29@bullet{}Oak@bullet{}St.}.
+
+@cindex separatori di campo, scelta dei
+@cindex espressioni regolari come separatori di campo
+@cindex separatori di campo, espressioni regolari come
+A volte i dati in input contengono caratteri separatori che non
+separano i campi nel modo in cui ci si sarebbe atteso. Per esempio, il
+nome della persona dell'esempio che abbiamo appena usato potrebbe avere un
+titolo o un suffisso annesso, come:
+
+@example
+John Q. Smith, LXIX, 29 Oak St., Walamazoo, MI 42139
+@end example
+
+@noindent
+Lo stesso programma estrarrebbe @samp{@bullet{}LXIX} invece di
+@samp{@bullet{}29@bullet{}Oak@bullet{}St.}.
+Se ci si aspetta che il programma stampi l'indirizzo,
+si rimarr@`a sorpresi. La morale @`e quella di scegliere la struttura dei dati
+e i caratteri di separazione attentamente per evitare questi problemi.
+(Se i dati non sono in una forma facile da elaborare, pu@`o darsi che
+si possano manipolare con un programma @command{awk} separato.)
+
+
+@node Separatori di campo di default
+@subsection Lo spazio vuoto normalmente separa i campi
+
+@cindex spazi vuoti, come separatori di campo
+I campi sono separati normalmente da spazi vuoti
+(spazi, tabulazioni e ritorni a capo), non solo da spazi singoli. Due spazi
+in una riga non delimitano un campo vuoto. Il valore di default del separatore
+di campo @code{FS} @`e una stringa contenente un singolo spazio, @w{@code{" "}}.
+Se @command{awk} interpretasse questo valore nel modo usuale, ogni carattere
+di spazio separerebbe campi, quindi due spazi in una riga creerebbero un campo
+vuoto tra di essi. Il motivo per cui questo non succede @`e perch@'e un singolo
+spazio come valore di @code{FS} @`e un caso particolare: @`e preso per specificare
+il modo di default di delimitare i campi.
+
+Se @code{FS} @`e qualsiasi altro carattere singolo, come @code{","}, ogni
+ricorrenza di quel carattere separa due campi. Due ricorrenze consecutive
+delimitano un campo vuoto. Se il carattere si trova all'inizio o alla fine
+della riga, anche quello delimita un campo vuoto. Il carattere di spazio @`e
+il solo carattere singolo che non segue queste
+regole.
+
+@node Separare campi con @dfn{regexp}
+@subsection Usare @dfn{regexp} come separatori di campo
+
+@cindex espressioni regolari, come separatori di campo
+@cindex separatori di campo, espressioni regolari come
+La precedente @value{SUBSECTION}
+ha illustrato l'uso di caratteri singoli o di stringhe semplici come
+valore di @code{FS}.
+Pi@`u in generale, il valore di @code{FS} pu@`o essere una stringa contenente
+qualsiasi espressione regolare. Se questo @`e il caso, ogni corrispondenza nel
+record con l'espressione regolare separa campi. Per esempio, l'assegnamento:
+
+@example
+FS = ", \t"
+@end example
+
+@noindent
+trasforma ogni parte di una riga in input che consiste di una virgola seguita
+da uno spazio e una tabulazione in un separatore di campo.
+@ifinfo
+(@samp{\t}
+@`e una @dfn{sequenza di protezione} che sta per un segno di tabulazione;
+@pxref{Sequenze di protezione},
+per l'elenco completo di sequenze di protezione simili.)
+@end ifinfo
+
+Per un esempio meno banale di espressione regolare, si provi a usare spazi
+singoli per separare campi nel modo in cui sono usate le virgole. @code{FS}
+pu@`o essere impostato a @w{@code{"[@ ]"}} (parentesi quadra sinistra, spazio,
+parentesi quadra destra). Quest'espressione regolare corrisponde a uno spazio
+@iftex
+singolo e niente pi@`u. (@pxrefil{Espressioni regolari}).
+@end iftex
+@ifnottex
+singolo e niente pi@`u. (@pxref{Espressioni regolari}).
+@end ifnottex
+C'@`e una differenza importante tra i due casi di @samp{FS = @w{" "}}
+(uno spazio singolo) e @samp{FS = @w{"[ \t\n]+"}}
+(un'espressione regolare che individua uno o pi@`u spazi, tabulazioni o
+ritorni a capo). Per entrambi i valori di @code{FS}, i campi sono
+separati da @dfn{serie} (ricorrenze adiacenti multiple) di spazi, tabulazioni
+e/o ritorni a capo. Comunque, quando il valore di @code{FS} @`e
+@w{@code{" "}}, @command{awk} prima toglie lo spazio vuoto iniziale e finale
+dal record e poi stabilisce dove sono i campi.
+Per esempio, la seguente @dfn{pipeline} stampa @samp{b}:
+
+@example
+$ @kbd{echo ' a b c d ' | awk '@{ print $2 @}'}
+@print{} b
+@end example
+
+@noindent
+Invece la @dfn{pipeline} che segue stampa @samp{a} (notare lo spazio extra
+intorno a ogni lettera):
+
+@example
+$ @kbd{echo ' a b c d ' | awk 'BEGIN @{ FS = "[ \t\n]+" @}}
+> @kbd{@{ print $2 @}'}
+@print{} a
+@end example
+
+@noindent
+@c @cindex null strings
+@cindex stringhe nulle
+@cindex stringhe vuote, si veda stringhe nulle
+In questo caso, il primo campo @`e nullo, o vuoto.
+Il taglio degli spazi vuoti iniziale e finale ha luogo anche
+ogniqualvolta @code{$0} @`e ricalcolato.
+Per esempio, si consideri questa @dfn{pipeline}:
+
+@example
+$ @kbd{echo ' a b c d' | awk '@{ print; $2 = $2; print @}'}
+@print{} a b c d
+@print{} a b c d
+@end example
+
+@noindent
+La prima istruzione @code{print} stampa il record cos@`{@dotless{i}} come @`e stato letto,
+con lo spazio vuoto intatto. L'assegnamento a @code{$2} ricostruisce
+@code{$0} concatenando insieme @code{$1} fino a @code{$NF},
+separati dal valore di @code{OFS} (che @`e uno spazio per default).
+Poich@'e lo spazio vuoto iniziale @`e stato ignorato quando si @`e trovato
+@code{$1}, esso non fa parte del nuovo @code{$0}. Alla fine, l'ultima
+istruzione @code{print} stampa il nuovo @code{$0}.
+
+@cindex @code{FS}, contenente @code{^}
+@cindex @code{^} (circonflesso), in @code{FS}
+@cindex angolo buio, @code{^}, in @code{FS}
+C'@`e un'ulteriore sottigliezza da considerare quando si usano le espressioni
+regolari per separare i campi.
+Non @`e ben specificato nello standard POSIX, n@'e altrove, cosa
+significhi @samp{^} nella divisione dei campi. Il @samp{^} cerca
+corrispondenze solo all'inizio dell'intero record? Oppure ogni separatore di
+campo @`e una nuova stringa? Di fatto versioni differenti di @command{awk}
+rispondono a questo quesito in modo diverso, e non si dovrebbe far affidamento
+su alcun comportamento specifico nei propri programmi.
+@value{DARKCORNER}
+
+@cindex Brian Kernighan, @command{awk} di
+Di sicuro, BWK @command{awk} individua con @samp{^}
+solo l'inizio del record. Anche @command{gawk}
+funziona in questo modo. Per esempio:
+
+@example
+$ @kbd{echo 'xxAA xxBxx C' |}
+> @kbd{gawk -F '(^x+)|( +)' '@{ for (i = 1; i <= NF; i++)}
+> @kbd{ printf "-->%s<--\n", $i @}'}
+@print{} --><--
+@print{} -->AA<--
+@print{} -->xxBxx<--
+@print{} -->C<--
+@end example
+
+@node Campi di un solo carattere
+@subsection Fare di ogni carattere un campo separato
+
+@cindex estensioni comuni, campi di un solo carattere
+@cindex comuni, estensioni, campi di un solo carattere
+@cindex differenze tra @command{awk} e @command{gawk}, campi di un solo carattere
+@cindex singolo carattere, campi
+@cindex campi di un solo carattere
+Ci sono casi in cui si abbia la necessit@`a di analizzare ciascun carattere di un
+record separatamente. Questo si pu@`o fare in @command{gawk} semplicemente
+assegnando la stringa nulla (@code{""}) a @code{FS}. @value{COMMONEXT}
+In questo caso,
+ogni singolo carattere nel record diventa un campo separato.
+Per esempio:
+
+@example
+$ @kbd{echo a b | gawk 'BEGIN @{ FS = "" @}}
+> @kbd{@{}
+> @kbd{for (i = 1; i <= NF; i = i + 1)}
+> @kbd{print "Il campo", i, "@`e", $i}
+> @kbd{@}'}
+@print{} Il campo 1 @`e a
+@print{} Il campo 2 @`e
+@print{} Il campo 3 @`e b
+@end example
+
+@cindex angolo buio, @code{FS} come stringa nulla
+@cindex @code{FS}, variabile, come stringa nulla
+Tradizionalmente, il comportamento di @code{FS} quando @`e impostato a
+@code{""} non @`e stato definito. In questo caso, la maggior parte delle
+versioni UNIX di @command{awk} trattano l'intero record come se avesse un
+unico campo.
+@value{DARKCORNER}
+In modalit@`a di compatibilit@`a
+(@pxref{Opzioni}),
+se @code{FS} @`e la stringa nulla, anche @command{gawk}
+si comporta in questo modo.
+
+@node Separatori campo da riga di comando
+@subsection Impostare @code{FS} dalla riga di comando
+@cindex @option{-F}, opzione sulla riga di comando
+@cindex separatore di campo, specificare sulla riga di comando
+@cindex riga di comando, impostare @code{FS} sulla
+@cindex @code{FS}, variabile, impostare da riga di comando
+
+@code{FS} pu@`o essere impostata sulla riga di comando. Per far questo si usa
+l'opzione @option{-F}. Per esempio:
+
+@example
+awk -F, '@var{programma}' @var{i-file-di-input}
+@end example
+
+@noindent
+imposta @code{FS} al carattere @samp{,}. Si noti che l'opzione richiede
+un carattere maiuscolo @samp{F} anzich@'e minuscolo @samp{f}. Quest'ultima
+opzione (@option{-f}) serve a specificare il file contenente un programma
+@command{awk}.
+
+Il valore usato per l'argomento di @option{-F} @`e elaborato esattamente nello
+stesso modo degli assegnamenti alla variabile predefinita @code{FS}. Qualsiasi
+carattere speciale nel separatore di campo dev'essere protetto in modo
+appropriato. Per esempio, per usare un @samp{\} come separatore di campo
+sulla riga di comando, si dovrebbe battere:
+
+@example
+# equivale a FS = "\\"
+awk -F\\\\ '@dots{}' file @dots{}
+@end example
+
+@noindent
+@cindex @code{\} (barra inversa), come separatore di campo
+@cindex barra inversa (@code{\}), come separatore di campo
+Poich@'e @samp{\} @`e usato nella shell per proteggere caratteri, a @command{awk}
+arriva @samp{-F\\}. Quindi @command{awk} elabora @samp{\\} per caratteri di
+protezione (@pxref{Sequenze di protezione}), producendo alla fine
+un unico @samp{\} da usare come separatore di campo.
+
+@c @cindex historical features
+Come caso particolare, in modalit@`a di compatibilit@`a
+(@pxref{Opzioni}),
+se l'argomento di @option{-F} @`e @samp{t}, @code{FS} @`e impostato al
+carattere di tabulazione. Se si immette @samp{-F\t} nella
+shell, senza che sia tra apici, @samp{\} viene cancellata,
+cos@`{@dotless{i}} @command{awk}
+conclude che si vuole realmente che i campi siano separati da tabulazioni e
+non da delle @samp{t}. Si usi @samp{-v FS="t"} o @samp{-F"[t]"} sulla riga di
+comando se si vuole separare i campi con delle @samp{t}.
+Quando non si @`e in modalit@`a di compatibilit@`a si deve usare @samp{-F '\t'} per
+specificare che le tabulazioni separano i campi.
+
+Come esempio, usiamo un file di programma @command{awk} chiamato
+@file{edu.awk} che contiene il criterio di ricerca @code{/edu/} e l'azione
+@samp{print $1}:
+
+@example
+/edu/ @{ print $1 @}
+@end example
+
+Impostiamo inoltre @code{FS} al carattere @samp{-} ed eseguiamo il programma
+sul file @file{mail-list}. Il seguente comando stampa un elenco dei nomi
+delle persone che lavorano all'universit@`a o che la frequentano, e le prime tre
+cifre dei loro numeri di telefono:
+
+@example
+$ @kbd{awk -F- -f edu.awk mail-list}
+@print{} Fabius 555
+@print{} Samuel 555
+@print{} Jean
+@end example
+
+@noindent
+Si noti la terza riga di output. La terza riga
+nel file originale @`e simile a questa:
+
+@example
+Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R
+@end example
+
+Il @samp{-} che fa parte del nome della persona @`e stato usato come
+separatore di campo, al posto del @samp{-} presente nel numero di telefono,
+che ci si aspettava venisse usato.
+Questo lascia intuire il motivo per cui si deve stare attenti nella scelta
+dei separatori di campo e di record.
+
+@cindex Unix @command{awk}, file di password, separatori di campo e
+Forse l'uso pi@`u comune di un solo carattere come separatore di campo avviene
+quando si elabora il file delle password di un sistema Unix. Su molti sistemi
+Unix, ogni utente @`e descritto da un elemento nel file delle password del
+sistema, che contiene una riga singola per ogni utente. In queste righe le
+informazioni sono separate da dei caratteri ":". Il
+primo campo @`e il nome di login dell'utente e il secondo @`e la password
+dell'utente criptata o oscurata (una password oscurata @`e indicata dalla
+presenza di una sola @samp{x} nel secondo campo). Una riga nel file delle
+password potrebbe essere simile a questa:
+
+@cindex Robbins, Arnold
+@example
+arnold:x:2076:10:Arnold Robbins:/home/arnold:/bin/bash
+@end example
+
+Il seguente programma esamina il file delle password di sistema e stampa le
+voci relative agli utenti il cui nome completo non @`e presente nel file:
+
+@example
+awk -F: '$5 == ""' /etc/passwd
+@end example
+
+@node Campo intera riga
+@subsection Fare di una riga intera un campo solo
+
+Occasionalmente, @`e utile trattare l'intera riga in input come un solo campo.
+Questo si pu@`o fare facilmente e in modo portabile semplicemente impostando
+@code{FS} a @code{"\n"} (un ritorno a capo).@footnote{Grazie ad
+Andrew Schorr per questo suggerimento.}
+
+@example
+awk -F'\n' '@var{programma}' @var{file @dots{}}
+@end example
+
+@noindent
+In questo caso, @code{$1} coincide con @code{$0}.
+
+
+@sidebar Cambiare @code{FS} non incide sui campi
+
+@cindex POSIX @command{awk}, separatori di campo e
+@cindex separatore di campo, POSIX e il
+Secondo lo standard POSIX, si suppone che @command{awk} si comporti
+come se ogni record sia stato diviso in campi nel momento in cui @`e stato
+letto. In particolare, ci@`o vuol dire che se si cambia il valore di
+@code{FS} dopo che un record @`e stato letto, il valore dei campi (cio@'e
+la loro suddivisione) sar@`a ancora quello ottenuto usando il precedente
+valore di @code{FS}, non quello nuovo.
+
+@cindex angolo buio, separatori di campo
+@cindex @command{sed}, programma di utilit@`a
+@cindex programma di utilit@`a @command{sed}
+@cindex editori di flusso
+Comunque, molte delle pi@`u vecchie implementazioni di @command{awk} non
+funzionano in questo modo. Invece, rimandano la divisione dei campi
+fino a quando si fa effettivamente riferimento a un campo. I campi sono
+divisi usando il valore @emph{corrente} di @code{FS}!
+@value{DARKCORNER}
+Questo comportamento pu@`o essere di difficile
+identificazione. Il seguente esempio illustra la differenza
+tra i due metodi. Lo script
+
+@example
+sed 1q /etc/passwd | awk '@{ FS = ":" ; print $1 @}'
+@end example
+
+@noindent
+normalmente stampa:
+
+@example
+@print{} root
+@end example
+
+@noindent
+su un'implementazione non standard di @command{awk}, mentre @command{gawk}
+stampa l'intera prima riga del file, qualcosa come:
+
+@example
+root:x:0:0:Root:/:
+@end example
+
+(Il comando @command{sed}@footnote{Il programma di utilit@`a @command{sed} @`e un
+``editore di flusso''. Anche il suo comportamento @`e definito dallo standard
+POSIX.} appena visto stampa solo la prima riga di @file{/etc/passwd}.)
+@end sidebar
+
+@node Sommario sulla separazione campi
+@subsection Sommario sulla separazione dei campi
+
+@`E importante ricordare che quando si assegna una costante stringa
+come valore di @code{FS}, questa subisce una normale elaborazione di stringa
+da parte di @command{awk}. Per esempio, con Unix @command{awk} e
+@command{gawk}, l'assegnamento @samp{FS = "\.."} assegna la stringa di
+caratteri @code{".."}
+a @code{FS} (la barra inversa @`e tolta). Questo crea un'espressione regolare
+che significa ``i campi sono separati da ricorrenze di due caratteri
+qualsiasi''. Se invece si vuole che i campi siano separati da un punto
+seguito da un qualsiasi carattere singolo, si deve usare @samp{FS = "\\.."}.
+
+Il seguente elenco riassume come i campi vengono divisi, in base al valore
+di @code{FS} (@samp{==} significa ``@`e uguale a''):
+
+@table @code
+@item FS == " "
+I campi sono separati da serie di spazi vuoti. Gli spazi vuoti iniziale e
+finale sono ignorati. Questo @`e il comportamento di default.
+
+@item FS == @var{qualsiasi altro carattere singolo}
+I campi sono separati da ogni ricorrenza del carattere. Ricorrenze
+successive multiple delimitano campi vuoti, e lo stesso fanno le ricorrenze
+iniziali e finali del carattere.
+Il carattere pu@`o essere anche un metacarattere di espressione regolare, che
+non @`e necessario proteggere.
+
+@item FS == @var{espressione regolare}
+I campi sono separati da ricorrenze di caratteri che corrispondono alla
+@var{espressione regolare}. Corrispondenze iniziali e finali della
+@dfn{regexp} delimitano campi vuoti.
+@item FS == ""
+Ogni sinngolo carattere nel record diventa un campo separato.
+(Questa @`e un'estensione comune; non @`e specificata dallo standard POSIX.)
+@end table
+
+@sidebar @code{FS} e @code{IGNORECASE}
+La variabile @code{IGNORECASE}
+(@pxref{Variabili modificabili dall'utente})
+influisce sulla divisione del campo @emph{solo} quando il valore di @code{FS}
+@`e un'espressione regolare. Non ha nessun effetto quando @code{FS} @`e un
+singolo carattere, anche se quel carattere @`e una lettera. Quindi, nel
+seguente codice:
+
+@example
+FS = "c"
+IGNORECASE = 1
+$0 = "aCa"
+print $1
+@end example
+
+@noindent
+L'output @`e @samp{aCa}. Se si vuol veramente dividere i campi su un carattere
+alfabetico ignorandone il maiuscolo/minuscolo, si deve usare un'espressione
+regolare che lo far@`a in automatico (p.es., @samp{FS = "[c]"}). In questo
+caso, @code{IGNORECASE} avr@`a effetto.
+@end sidebar
+
+
+@node Dimensione costante
+@section Leggere campi di larghezza costante
+
+
+@cindex campi di larghezza costante
+@cindex larghezza costante, campi di
+@cindex funzionalit@`a avanzate, campi di larghezza costante
+@c O'Reilly doesn't like it as a note the first thing in the section.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} tratta una funzionalit@`a avanzata
+di @command{gawk}. Se si @`e un utente alle prime armi di @command{awk},
+la si pu@`o saltare in prima lettura.
+
+@command{gawk} fornisce una funzionalit@`a per il trattamento di campi
+a larghezza fissa senza un separatore di campo distintivo. Per esempio,
+dati di questo tipo si trovano nell'input per vecchi programmi Fortran dove
+dei numeri sono elencati uno dopo l'altro, o nell'output di programmi che
+non prevedono che il loro output sia dato in input ad altri programmi.
+
+Un esempio di quest'ultimo caso @`e una tabella dove tutte le colonne sono
+allineate usando un numero variabile di spazi e dove @emph{i campi vuoti
+sono solo spazi}. Chiaramente, la normale divisione in campi di
+@command{awk} basata su @code{FS} non funziona bene in questa situazione.
+Sebbene un programma @command{awk}
+portabile possa usare una serie di chiamate @code{substr()} su @code{$0}
+(@pxref{Funzioni per stringhe}),
+questo @`e scomodo e inefficiente se il numero dei campi @`e elevato.
+
+@cindex risoluzione di problemi, errori fatali, specificare larghezza dei campi
+@cindex problemi, risoluzione di, errori fatali, specificare larghezza dei campi
+@cindex @command{w}, programma di utilit@`a
+@cindex programma di utilit@`a @command{w}
+@cindex @code{FIELDWIDTHS}, variabile
+@cindex @command{gawk}, variabile @code{FIELDWIDTHS} in
+La suddivisione di un record in input in campi a larghezza fissa viene
+specificata assegnando una stringa contenente numeri separati da spazi alla
+variabile predefinita @code{FIELDWIDTHS}. Ogni numero specifica la larghezza
+del campo, @emph{comprese} le colonne tra i campi. Se si vogliono ignorare le
+colonne tra i campi si pu@`o specificare la loro larghezza come un campo
+separato che verr@`a poi ignorato.
+@`E un errore fatale definire una larghezza di campo che abbia un valore
+negativo. I dati seguenti costituiscono l'output del programma di utilit@`a
+Unix @command{w}. @`E utile per spiegare l'uso di @code{FIELDWIDTHS}:
+
+@example
+@group
+ 10:06pm up 21 days, 14:04, 23 users
+User tty login@ idle JCPU PCPU what
+hzuo ttyV0 8:58pm 9 5 vi p24.tex
+hzang ttyV3 6:37pm 50 -csh
+eklye ttyV5 9:53pm 7 1 em thes.tex
+dportein ttyV6 8:17pm 1:47 -csh
+gierd ttyD3 10:00pm 1 elm
+dave ttyD4 9:47pm 4 4 w
+brent ttyp0 26Jun91 4:46 26:46 4:41 bash
+dave ttyq4 26Jun9115days 46 46 wnewmail
+@end group
+@end example
+
+Il seguente programma prende l'input sopra mostrato, converte il tempo di
+inattivit@`a
+in numero di secondi, e stampa i primi due campi e il tempo di inattivit@`a
+calcolato:
+
+@example
+BEGIN @{ FIELDWIDTHS = "9 6 10 6 7 7 35" @}
+NR > 2 @{
+ inat = $4
+ sub(/^ +/, "", inat) # togli spazi prima del valore
+ if (inat == "")
+ inat = 0
+ if (inat ~ /:/) @{
+ split(inat, t, ":")
+ inat = t[1] * 60 + t[2]
+ @}
+ if (inat ~ /days/)
+ inat *= 24 * 60 * 60
+
+ print $1, $2, inat
+@}
+@end example
+
+@quotation NOTA
+Questo programma usa diverse funzionalit@`a di @command{awk} non
+ancora trattate.
+@end quotation
+
+L'esecuzione del programma sui dati produce il seguente risultato:
+
+@example
+hzuo ttyV0 0
+hzang ttyV3 50
+eklye ttyV5 0
+dportein ttyV6 107
+gierd ttyD3 1
+dave ttyD4 0
+brent ttyp0 286
+dave ttyq4 1296000
+@end example
+
+Un altro esempio (forse pi@`u pratico) di dati di input con larghezza costante @`e
+l'input da un mazzo di schede elettorali. In alcune parti degli Stati Uniti,
+i votanti marcano le loro scelte perforando delle schede elettroniche.
+
+Queste schede vengono poi elaborate per contare i voti espressi per ogni
+singolo candidato o su ogni determinato quesito. Siccome un votante pu@`o
+scegliere di non votare su alcune questioni, qualsiasi colonna della scheda
+pu@`o essere vuota. Un programma @command{awk} per elaborare tali dati potrebbe
+usare la funzionalit@`a @code{FIELDWIDTHS} per semplificare la lettura dei dati.
+(Naturalmente, riuscire a eseguire @command{gawk} su un sistema con lettori di
+schede @`e un'altra storia!)
+
+@cindex @command{gawk}, separazione in campi e
+L'assegnazione di un valore a @code{FS} fa s@`{@dotless{i}} che @command{gawk} usi @code{FS}
+per separare nuovamente i campi. Si pu@`o usare @samp{FS = FS} per ottenere
+questo effetto, senza dover conoscere il valore corrente di @code{FS}.
+Per vedere quale tipo di separazione sia in atto,
+si pu@`o usare @code{PROCINFO["FS"]}
+(@pxref{Variabili auto-assegnate}).
+Il suo valore @`e @code{"FS"} se si usa la normale separazione in campi,
+o @code{"FIELDWIDTHS"} se si usa la separazione in campi a larghezza fissa:
+
+@example
+if (PROCINFO["FS"] == "FS")
+ @var{separazione in campi normale}@dots{}
+else if (PROCINFO["FS"] == "FIELDWIDTHS")
+ @var{separazione in campi a larghezza fissa}@dots{}
+else
+ @var{separazione dei campi in base al contenuto}@dots{} @ii{(si veda
+@ifnotinfo
+la @value{SECTION} successiva)}
+@end ifnotinfo
+@ifinfo
+il @value{SECTION} successivo)}
+@end ifinfo
+@end example
+
+Quest'informazione @`e utile quando si scrive una funzione che
+necessita di cambiare temporaneamente @code{FS} o @code{FIELDWIDTHS},
+leggere alcuni record, e poi ripristinare le impostazioni originali
+(@pxref{Funzioni Passwd},
+per un esempio di tale funzione).
+
+@node Separazione in base al contenuto
+@section Definire i campi in base al contenuto
+
+@c O'Reilly doesn't like it as a note the first thing in the section.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} tratta una funzionalit@`a avanzata
+di @command{gawk}. Se si @`e un utente alle prime armi di @command{awk},
+la si pu@`o saltare in prima lettura.
+
+@cindex funzionalit@`a avanzate, specificare il contenuto dei campi
+Normalmente, quando si usa @code{FS}, @command{gawk} definisce i campi come
+le parti del record che si trovano tra due separatori di campo. In altre
+parole, @code{FS} definisce cosa un campo @emph{non @`e}, invece di cosa
+@emph{@`e}.
+Tuttavia, ci sono casi in cui effettivamente si ha bisogno di definire i campi
+in base a cosa essi sono, e non in base a cosa non sono.
+
+Il caso pi@`u emblematico @`e quello dei dati cosiddetti @dfn{comma-separated
+value} (CSV). Molti fogli elettronici, per esempio, possono esportare i dati
+in file di testo, dove ogni record termina con un ritorno a capo e i campi
+sono separati tra loro da virgole. Se le virgole facessero solo da separatore
+fra i dati non ci sarebbero problemi. Il problema sorge se uno dei campi
+contiene una virgola @emph{al suo interno}.
+In queste situazioni, la maggioranza dei programmi include il campo fra
+doppi apici.@footnote{Il formato CSV non ha avuto, per molti anni, una
+definizione standard formale.
+@uref{http://www.ietf.org/rfc/rfc4180.txt, RFC 4180}
+standardizza le pratiche pi@`u comuni.}
+Cos@`{@dotless{i}}, potremmo avere dei dati di questo tipo:
+
+@example
+@c file eg/misc/addresses.csv
+Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
+@c endfile
+@end example
+
+@cindex @command{gawk}, variabile @code{FPAT} in
+@cindex @code{FPAT}, variabile
+La variabile @code{FPAT} offre una soluzione per casi come questo.
+Il valore di @code{FPAT} dovrebbe essere una stringa formata da un'espressione
+regolare. L'espressione regolare descrive il contenuto di ciascun campo.
+
+Nel caso dei dati CSV visti prima, ogni campo @`e ``qualsiasi cosa che non
+sia una virgola,'' oppure ``doppi apici, seguiti da qualsiasi cosa che non
+siano doppi apici, e doppi apici di chiusura''. Se fosse scritta come una
+costante @dfn{regexp}
+@iftex
+(@pxrefil{Espressioni regolari}),
+@end iftex
+@ifnottex
+(@pxref{Espressioni regolari}),
+@end ifnottex
+sarebbe @code{/([^,]+)|("[^"]+")/}.
+Dovendola scrivere come stringa si devono proteggere i doppi apici,
+e quindi si deve scrivere:
+
+@example
+FPAT = "([^,]+)|(\"[^\"]+\")"
+@end example
+
+Come esempio pratico, si pu@`o vedere questo semplice programma che analizza
+e divide i dati:
+
+@example
+@c file eg/misc/simple-csv.awk
+BEGIN @{
+ FPAT = "([^,]+)|(\"[^\"]+\")"
+@}
+
+@{
+ print "NF = ", NF
+ for (i = 1; i <= NF; i++) @{
+ printf("$%d = <%s>\n", i, $i)
+ @}
+@}
+@c endfile
+@end example
+
+Eseguendolo, avendo in input la riga vista sopra, si ottiene:
+
+@example
+$ @kbd{gawk -f simple-csv.awk addresses.csv}
+NF = 7
+$1 = <Robbins>
+$2 = <Arnold>
+$3 = <"1234 A Pretty Street, NE">
+$4 = <MyTown>
+$5 = <MyState>
+$6 = <12345-6789>
+$7 = <USA>
+@end example
+
+Si noti la virgola contenuta nel valore del campo @code{$3}.
+
+Un semplice miglioramento se si elaborano dati CSV di questo tipo potrebbe
+essere quello di rimuovere i doppi apici, se presenti, con del codice di
+questo tipo:
+
+@example
+if (substr($i, 1, 1) == "\"") @{
+ len = length($i)
+ $i = substr($i, 2, len - 2) # Ottiene il testo tra doppi apici
+@}
+@end example
+
+Come per @code{FS}, la variabile @code{IGNORECASE}
+(@pxref{Variabili modificabili dall'utente}) ha effetto sulla separazione dei
+campi con @code{FPAT}.
+
+Se si assegna un valore a @code{FPAT} la divisione in campi non viene
+effettuata utilizzando @code{FS} o @code{FIELDWIDTHS}.
+Analogamente a @code{FIELDWIDTHS}, il valore di @code{PROCINFO["FS"]}
+sar@`a @code{"FPAT"} se @`e in uso la suddivisione in campi in base al contenuto.
+
+@quotation NOTA
+Alcuni programmi esportano dei dati CSV che contengono dei ritorni a capo al
+loro interno in campi rinchiusi tra doppi apici. @command{gawk} non @`e in
+grado di trattare questi dati. Malgrado esista una specifica ufficiale
+per i dati CSV, non c'@`e molto da fare; il meccanismo di @code{FPAT} fornisce
+una soluzione elegante per la maggioranza dei casi, e per gli sviluppatori di
+@command{gawk} ci@`o pu@`o bastare.
+@end quotation
+
+Come visto, l'espressione regolare usata per @code{FPAT} richiede
+che ogni campo contenga almeno un carattere. Una semplice modifica
+(cambiare il primo @samp{+} con @samp{*}) permette che siano presenti dei
+campi vuoti:
+
+@example
+FPAT = "([^,]*)|(\"[^\"]+\")"
+@end example
+
+@c FIXME: 4/2015
+@c Consider use of FPAT = "([^,]*)|(\"[^\"]*\")"
+@c (star in latter part of value) to allow quoted strings to be empty.
+@c Per email from Ed Morton <mortoneccc@comcast.net>
+
+Infine, la funzione @code{patsplit()} rende la stessa funzionalit@`a disponibile
+per suddividere normali stringhe (@pxref{Funzioni per stringhe}).
+
+Per ricapitolare, @command{gawk} fornisce tre metodi indipendenti per
+suddividere in campi i record in input.
+Il meccanismo usato @`e determinato da quella tra le tre
+variabili---@code{FS}, @code{FIELDWIDTHS}, o @code{FPAT}---a cui
+sia stato assegnato un valore pi@`u recentemente.
+
+@node Righe multiple
+@section Record su righe multiple
+
+@cindex righe multiple, record su
+@cindex record multiriga
+@cindex input, record multiriga
+@cindex file, lettura dei record multiriga
+@cindex input, file in, si veda file in input
+In alcune banche-dati, una sola riga non pu@`o contenere in modo adeguato
+tutte le informazioni di una voce. In questi casi si possono usare record
+multiriga.
+Il primo passo @`e quello di scegliere il formato dei dati.
+
+@cindex separatori di record, per record multiriga
+Una tecnica @`e quella di usare un carattere o una stringa non usuali per
+separare i record. Per esempio, si pu@`o usare il carattere di interruzione di
+pagina (scritto @samp{\f} sia in @command{awk} che in C) per separarli,
+rendendo ogni record una pagina del file. Per far ci@`o, basta impostare la
+variabile @code{RS} a @code{"\f"} (una stringa contenente il carattere di
+interruzione di pagina). Si potrebbe ugualmente usare qualsiasi altro
+carattere, sempre che non faccia parte dei dati di un record.
+
+@cindex @code{RS}, variabile, record multiriga e
+Un'altra tecnica @`e quella di usare righe vuote per separare i record.
+Per una particolare
+convenzione, una stringa nulla come valore di @code{RS} indica che i record
+sono separati da una o pi@`u righe vuote. Quando @code{RS} @`e impostato alla
+stringa nulla, ogni record termina sempre alla prima riga vuota che @`e stata
+trovata. Il record successivo non inizia prima della successiva riga non
+vuota. Indipendentemente dal numero di righe vuote presenti in successione,
+esse costituiscono sempre un unico separatore di record.
+(Le righe vuote devono essere completamente vuote; righe che contengono
+spazi bianchi @emph{non} sono righe vuote.)
+
+@cindex stringa pi@`u lunga da sinistra, individuare la
+@cindex individuare la stringa pi@`u lunga da sinistra
+Si pu@`o ottenere lo stesso effetto di @samp{RS = ""} assegnando la stringa
+@code{"\n\n+"} a @code{RS}. Quest'espressione regolare individua
+il ritorno a capo alla fine del record e una o pi@`u righe vuote dopo il
+record. In aggiunta, un'espressione regolare individua sempre la sequenza pi@`u
+lunga possibile quando una tale stringa sia presente.
+(@pxref{Pi@`u lungo da sinistra}).
+Quindi, il record successivo non inizia prima della successiva riga non
+vuota; indipendentemente dal numero di righe vuote presenti in una voce di
+banca-dati, esse sono considerate come un unico separatore di record.
+
+@cindex angolo buio, record multiriga
+Comunque, c'@`e una sostanziale differenza tra @samp{RS = ""} e @samp{RS =
+"\n\n+"}. Nel primo caso, i ritorni a capo iniziali nel @value{DF} di
+input vengono ignorati, e se un file termina senza righe vuote aggiuntive dopo
+l'ultimo record, il ritorno a capo viene rimosso dal record. Nel secondo
+caso, questa particolare elaborazione non viene fatta.
+@value{DARKCORNER}
+
+@cindex separatore di campo, nei record multiriga
+@cindex @code{FS}, nei record multiriga
+Ora che l'input @`e separato in record, il secondo passo @`e quello di separare i
+campi all'interno dei record. Un modo per farlo @`e quello di dividere in
+campi ognuna delle righe in input
+nel modo solito. Questo viene fatto per default tramite una
+speciale funzionalit@`a. Quando @code{RS} @`e impostato alla stringa nulla
+@emph{e} @code{FS} @`e impostato a un solo carattere, il carattere di
+ritorno a capo agisce @emph{sempre} come separatore di campo.
+Questo in aggiunta a tutte le separazioni di campo che risultano da
+@code{FS}.@footnote{Quando @code{FS} @`e la stringa nulla (@code{""}), o
+un'espressione regolare, questa particolare funzionalit@`a di @code{RS} non
+viene applicata; si applica al separatore di campo quando @`e costituito da un
+solo spazio:
+@samp{FS = @w{" "}}.}
+
+La motivazione originale per questa particolare eccezione probabilmente era
+quella di prevedere un comportamento che fosse utile nel caso di default
+(cio@`e, @code{FS} uguale a @w{@code{" "}}). Questa funzionalit@`a pu@`o
+costituire un problema se non si vuole che il carattere di ritorno a capo
+faccia da separatore tra i campi, perch@'e non c'@`e alcun modo per impedirlo.
+Tuttavia, si pu@`o aggirare il problema usando la funzione @code{split()}
+per spezzare i record manualmente.
+(@pxref{Funzioni per stringhe}).
+Se si ha un separatore di campo costituito da un solo carattere, si pu@`o
+aggirare la funzionalit@`a speciale in modo diverso, trasformando @code{FS}
+in un'espressione regolare contenente
+quel carattere singolo. Per esempio, se il separatore di campo @`e
+un carattere di percentuale, al posto di
+@samp{FS = "%"}, si pu@`o usare @samp{FS = "[%]"}.
+
+Un altro modo per separare i campi @`e quello di
+mettere ciascun campo su una riga separata: per far questo basta impostare la
+variabile @code{FS} alla stringa @code{"\n"}.
+(Questo separatore di un solo carattere individua un singolo ritorno a capo.)
+Un esempio pratico di un @value{DF} organizzato in questo modo potrebbe essere
+un elenco di indirizzi, in cui delle righe vuote fungono da separatore fra
+record. Si consideri un elenco di indirizzi in un file chiamato
+@file{indirizzi}, simile a questo:
+
+@example
+Jane Doe
+123 Main Street
+Anywhere, SE 12345-6789
+
+John Smith
+456 Tree-lined Avenue
+Smallville, MW 98765-4321
+@dots{}
+@end example
+
+@noindent
+Un semplice programma per elaborare questo file @`e il seguente:
+
+@example
+# addrs.awk --- semplice programma per una lista di indirizzi postali
+
+# I record sono separati da righe bianche
+# Ogni riga @`e un campo.
+BEGIN @{ RS = "" ; FS = "\n" @}
+
+@{
+ print "Il nome @`e:", $1
+ print "L'indirizzo @`e:", $2
+ print "Citt@`a e Stato sono:", $3
+ print ""
+@}
+@end example
+
+L'esecuzione del programma produce questo output:
+
+@example
+$ @kbd{awk -f addrs.awk addresses}
+@print{} Il nome @`e: Jane Doe
+@print{} L'indirizzo @`e: 123 Main Street
+@print{} Citt@`a e Stato sono: Anywhere, SE 12345-6789
+@print{}
+@print{} Il nome @`e: John Smith
+@print{} L'indirizzo @`e: 456 Tree-lined Avenue
+@print{} Citt@`a e Stato sono: Smallville, MW 98765-4321
+@print{}
+@dots{}
+@end example
+
+@xref{Programma labels}, per un programma pi@`u realistico per gestire
+elenchi di indirizzi. Il seguente elenco riassume come sono divisi i record,
+a seconda del valore assunto da
+@ifinfo
+@code{RS}.
+(@samp{==} significa ``@`e uguale a.'')
+@end ifinfo
+@ifnotinfo
+@code{RS}:
+@end ifnotinfo
+
+@table @code
+@item RS == "\n"
+I record sono separati dal carattere di ritorno a capo (@samp{\n}). In
+effetti, ogni riga nel @value{DF} @`e un record separato, comprese le righe
+vuote. Questo @`e il comportamento di default.
+
+@item RS == @var{qualsiasi carattere singolo}
+I record sono separati da ogni ricorrenza del carattere specificato. Pi@`u
+ricorrenze adiacenti delimitano record vuoti.
+
+@item RS == ""
+I record sono separati da una o pi@`u righe vuote.
+Quando @code{FS} @`e un carattere singolo,
+il carattere di ritorno a capo
+serve sempre come separatore di campo, in aggiunta a qualunque valore possa
+avere @code{FS}. I ritorni a capo all'inizio e alla fine del file sono
+ignorati.
+
+@item RS == @var{regexp}
+I record sono separati da ricorrenze di caratteri corrispondenti a
+@var{regexp}. Le corrispondenze iniziali e finali di
+@var{regexp} designano record vuoti.
+(Questa @`e un'estensione di @command{gawk}; non @`e specificata dallo
+standard POSIX.)
+@end table
+
+@cindex @command{gawk}, @code{RT} variabile in
+@cindex @code{RT}, variabile
+Se non @`e eseguito in modalit@`a di compatibilit@`a (@pxref{Opzioni}),
+@command{gawk} imposta @code{RT} al testo di input corrispondente
+al valore specificato da @code{RS}.
+Ma se al termine del file in input non @`e stato trovato un testo che
+corrisponde a @code{RS}, @command{gawk} imposta @code{RT} alla stringa nulla.
+
+@node Getline
+@section Richiedere input usando @code{getline}
+
+@cindex @code{getline}, comando, input esplicito con
+@cindex input esplicito
+Finora abbiamo ottenuto i dati di input dal flusso di input principale di
+@command{awk}: lo standard input (normalmente la tastiera, a volte
+l'output di un altro programma) o i
+file indicati sulla riga di comando. Il linguaggio @command{awk} ha uno
+speciale comando predefinito chiamato @code{getline} che
+pu@`o essere usato per leggere l'input sotto il diretto controllo dell'utente.
+
+Il comando @code{getline} @`e usato in molti modi diversi e
+@emph{non} dovrebbe essere usato dai principianti.
+L'esempio che segue alla spiegazione del comando @code{getline}
+comprende del materiale che ancora non @`e stato trattato. Quindi, @`e meglio
+tornare indietro e studiare il comando @code{getline} @emph{dopo} aver rivisto
+il resto
+@ifinfo
+di questo @value{DOCUMENT}
+@end ifinfo
+@ifhtml
+di questo @value{DOCUMENT}
+@end ifhtml
+@ifnotinfo
+@ifnothtml
+delle Parti I e II
+@end ifnothtml
+@end ifnotinfo
+e avere acquisito una buona conoscenza di come funziona @command{awk}.
+
+@cindex @command{gawk}, variabile @code{ERRNO} in
+@cindex @code{ERRNO}, variabile, con comando @command{getline}
+@cindex differenze tra @command{awk} e @command{gawk}, comando @code{getline}
+@cindex @code{getline}, comando, valori di ritorno
+@cindex @option{--sandbox}, opzione, ridirezione dell'input con @code{getline}
+
+Il comando @code{getline} restituisce 1 se trova un record e 0 se
+trova la fine del file. Se si verifica qualche errore cercando di leggere
+un record, come un file che non pu@`o essere aperto, @code{getline}
+restituisce @minus{}1. In questo caso, @command{gawk} imposta la variabile
+@code{ERRNO} a una stringa che descrive l'errore in questione.
+
+Se il messaggio di errore @code{ERRNO} indica che l'operazione di I/O pu@`o
+essere ritentata e la variabile @code{PROCINFO["@var{input}", "RETRY"]} @`e
+impostata a 1, @code{getline} restituisce un codice di ritorno @minus{}2
+invece che @minus{}1, e si pu@`o provare a chiamare ulterioriormente
+@code{getline}. @xref{Proseguire dopo errore in input} per ulteriori
+informazioni riguardo a questa funzionalit@`a.
+
+Negli esempi seguenti, @var{comando} sta per un valore di stringa che
+rappresenta un comando della shell.
+
+@quotation NOTA
+Quando @`e stata specificata l'opzione @option{--sandbox} (@pxref{Opzioni}),
+la lettura di input da file, @dfn{pipe} e coprocessi non @`e possibile.
+@end quotation
+
+@menu
+* Getline semplice:: Usare @code{getline} senza argomenti.
+* Getline variabile:: Usare @code{getline} in una variabile.
+* Getline file:: Usare @code{getline} da un file.
+* Getline variabile file:: Usare @code{getline} in una variabile da un
+ file.
+* Getline @dfn{pipe}:: Usare @code{getline} da una @dfn{pipe}.
+* Getline variabile @dfn{pipe}:: Usare @code{getline} in una variabile da una
+ @dfn{pipe}.
+* Getline coprocesso:: Usare @code{getline} da un coprocesso.
+* Getline variabile coprocesso:: Usare @code{getline} in una variabile da un
+ coprocesso.
+* Note su getline:: Cose importanti da sapere su @code{getline}.
+* Sommario di getline:: Sommario delle varianti di @code{getline}.
+@end menu
+
+@node Getline semplice
+@subsection Usare @code{getline} senza argomenti
+
+Il comando @code{getline} pu@`o essere usato senza argomenti per leggere l'input
+dal file in input corrente. Tutto quel che fa in questo caso @`e leggere il
+record in input successivo e dividerlo in campi. Questo @`e utile se @`e
+finita l'elaborarezione del record corrente, e si vogliono fare delle
+elaborazioni particolari sul record successivo @emph{proprio adesso}.
+Per esempio:
+
+@example
+# rimuovere il testo tra /* e */, compresi
+@{
+ if ((i = index($0, "/*")) != 0) @{
+ prima = substr($0, 1, i - 1) # la parte iniziale della stringa
+ dopo = substr($0, i + 2) # ... */ ...
+ j = index(dopo, "*/") # */ @`e nella parte finale?
+ if (j > 0) @{
+ dopo = substr(dopo, j + 2) # rimozione del commento
+ @} else @{
+ while (j == 0) @{
+ # passa ai record seguenti
+ if (getline <= 0) @{
+ print("Fine file inattesa o errore:", ERRNO) > "/dev/stderr"
+ exit
+ @}
+ # incrementare la riga usando la concatenazione di stringhe
+ dopo = dopo $0
+ j = index(dopo, "*/") # @`e */ nella parte finale?
+ if (j != 0) @{
+ dopo = substr(dopo, j + 2)
+ break
+ @}
+ @}
+ @}
+ # incrementare la riga di output usando la concatenazione
+ # di stringhe
+ $0 = prima dopo
+ @}
+ 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
+
+Questo programma @command{awk} cancella i commenti in stile C
+(@samp{/* @dots{} */}) dall'input.
+Usa diverse funzionalit@`a che non sono ancora state trattate, incluse la
+concatenazione di stringhe
+(@pxref{Concatenazione})
+e le funzioni predefinite @code{index()} e @code{substr()}
+(@pxref{Funzioni per stringhe}).
+Sostituendo @samp{print $0} con altre
+istruzioni, si possono effettuare elaborazioni pi@`u complesse sull'input
+decommentato, come ricercare corrispondenze di un'espressione regolare.
+(Questo programma ha un piccolo problema: non funziona se c'@`e pi@`u di un
+commento che inizia e finisce
+sulla stessa riga.)
+
+Questa forma del comando @code{getline} imposta @code{NF},
+@code{NR}, @code{FNR}, @code{RT} e il valore di @code{$0}.
+
+@quotation NOTA
+Il nuovo valore di @code{$0} @`e usato per verificare
+le espressioni di ricerca di ogni regola successiva. Il valore originale
+di @code{$0} che ha attivato la regola che ha eseguito la @code{getline}
+viene perso.
+A differenza di @code{getline}, l'istruzione @code{next} legge un nuovo record
+ma inizia a elaborarlo normalmente, a partire dalla prima
+regola presente nel programma. @xref{Istruzione next}.
+@end quotation
+
+@node Getline variabile
+@subsection Usare @code{getline} in una variabile
+@cindex @code{getline} in una variabile
+@cindex variabili, usare in comando @code{getline}
+
+Si pu@`o usare @samp{getline @var{var}} per leggere il record successivo
+in input ad @command{awk} nella variabile @var{var}. Non vien fatta
+nessun'altra elaborazione.
+Per esempio, supponiamo che la riga successiva sia un commento o una stringa
+particolare, e la si voglia leggere senza innescare nessuna regola. Questa
+forma di @code{getline} permette di leggere quella riga e memorizzarla in una
+variabile in modo che il ciclo principale di @command{awk} che "legge una riga
+e controlla ogni regola" non la veda affatto.
+L'esempio seguente inverte tra loro a due a due le righe in input:
+
+@example
+@{
+ if ((getline tmp) > 0) @{
+ print tmp
+ print $0
+ @} else
+ print $0
+@}
+@end example
+
+@noindent
+Prende la seguente lista:
+
+@example
+wan
+tew
+free
+phore
+@end example
+
+@noindent
+e produce questo risultato:
+
+@example
+tew
+wan
+phore
+free
+@end example
+
+Il comando @code{getline} usato in questo modo imposta solo le variabili
+@code{NR}, @code{FNR} e @code{RT} (e, naturalmente, @var{var}).
+Il record non viene
+suddiviso in campi, e quindi i valori dei campi (compreso @code{$0}) e
+il valore di @code{NF} non cambiano.
+
+@node Getline file
+@subsection Usare @code{getline} da un file
+
+@cindex @code{getline} da un file
+@cindex input, ridirezione dell'
+@cindex ridirezione dell'input
+@cindex @code{<} (parentesi acuta sinistra), operatore @code{<} (I/O)
+@cindex parentesi acuta sinistra (@code{<}), operatore @code{<} (I/O)
+@cindex operatori di input/output
+Si usa @samp{getline < @var{file}} per leggere il record successivo da
+@var{file}. Qui, @var{file} @`e un'espressione di tipo stringa che
+specifica il @value{FN}. @samp{< @var{file}} @`e una cosidetta
+@dfn{ridirezione} perch@'e richiede che l'input provenga da un posto
+differente. Per esempio, il seguente programma
+legge il suo record in input dal file @file{secondary.input} quando
+trova un primo campo con un valore uguale a 10 nel file in input
+corrente:
+
+@example
+@{
+ if ($1 == 10) @{
+ getline < "secondary.input"
+ print
+ @} else
+ print
+@}
+@end example
+
+Poich@'e non viene usato il flusso principale di input, i valori di @code{NR} e
+@code{FNR} restano immutati. Comunque, il record in input viene diviso in
+modo normale, per cui vengono cambiati i valori di @code{$0} e degli altri
+campi, producendo un nuovo valore di @code{NF}.
+Viene impostato anche @code{RT}.
+
+@cindex POSIX @command{awk}, operatore @code{<} e
+@c Thanks to Paul Eggert for initial wording here
+Per lo standard POSIX, @samp{getline < @var{espressione}} @`e ambiguo se
+@var{espressione} contiene operatori che non sono all'interno di parentesi,
+ad esclusione di @samp{$}; per esempio, @samp{getline < dir "/" file} @`e
+ambiguo perch@'e l'operatore di concatenazione (non ancora trattato;
+@pxref{Concatenazione}) non @`e posto tra parentesi.
+Si dovrebbe scrivere invece @samp{getline < (dir "/" file)}, se il
+programma dev'essere portabile su tutte le implementazioni di @command{awk}.
+
+@node Getline variabile file
+@subsection Usare @code{getline} in una variabile da un file
+@cindex variabili, usare in comando @code{getline}
+
+Si usa @samp{getline @var{var} < @var{file}} per leggere l'input
+dal file
+@var{file}, e metterlo nella variabile @var{var}. Come prima, @var{file}
+@`e un'espressione di tipo stringa che specifica il file dal quale
+legggere.
+
+In questa versione di @code{getline}, nessuna delle variabili predefinite @`e
+cambiata e il record non @`e diviso in campi. La sola variabile cambiata @`e
+@var{var}.@footnote{Questo non @`e completamente vero. @code{RT} pu@`o essere
+cambiato se @code{RS} @`e un'espressione regolare.}
+Per esempio, il seguente programma copia tutti i file in input nell'output, ad
+eccezione dei record che dicono @w{@samp{@@include @var{nomefile}}}.
+Tale record @`e sostituito dal contenuto del file
+@var{nomefile}:
+
+@example
+@{
+ if (NF == 2 && $1 == "@@include") @{
+ while ((getline line < $2) > 0)
+ print line
+ close($2)
+ @} else
+ print
+@}
+@end example
+
+Si noti come il nome del file in input aggiuntivo non compaia all'interno del
+programma; @`e preso direttamente dai dati, e precisamente dal secondo campo
+della riga di @code{@@include}.
+
+La funzione @code{close()} viene chiamata per assicurarsi che se nell'input
+appaiono due righe @code{@@include} identiche, l'intero file specificato sia
+incluso ogni volta.
+@xref{Chiusura file e @dfn{pipe}}.
+
+Una carenza di questo programma @`e che non gestisce istruzioni
+@code{@@include} nidificate
+(cio@`e, istruzioni @code{@@include} contenute nei file inclusi)
+nel modo in cui ci si aspetta che funzioni un vero preelaboratore di macro.
+@xref{Programma igawk} per un programma
+che gestisce le istruzioni @code{@@include} nidificate.
+
+@node Getline @dfn{pipe}
+@subsection Usare @code{getline} da una @dfn{pipe}
+
+@c From private email, dated October 2, 1988. Used by permission, March 2013.
+@cindex Kernighan, Brian
+@quotation
+@i{L'onniscienza ha molti aspetti positivi.
+Se non si pu@`o ottenerla, l'attenzione ai dettagli pu@`o aiutare.}
+@author Brian Kernighan
+@end quotation
+
+@cindex @code{|} (barra verticale), operatore @code{|} (I/O)
+@cindex barra verticale (@code{|}), operatore @code{|} (I/O)
+@cindex input, @dfn{pipeline}
+@cindex @dfn{pipe}, input
+@cindex operatori, input/output
+L'output di un comando pu@`o anche essere convogliato in @code{getline}, usando
+@samp{@var{comando} | getline}. In
+questo caso, la stringa @var{comando} viene eseguita come comando di shell e
+il suo output @`e passato ad @command{awk} per essere usato come input.
+Questa forma di @code{getline} legge un record alla volta dalla @dfn{pipe}.
+Per esempio, il seguente programma copia il suo input nel suo output,
+ad eccezione delle righe che iniziano con @samp{@@execute}, che sono
+sostituite dall'output prodotto dall'esecuzione del resto della riga
+costituito da un comando di shell.
+
+@example
+@{
+ if ($1 == "@@execute") @{
+ tmp = substr($0, 10) # Rimuove "@@execute"
+ while ((tmp | getline) > 0)
+ print
+ close(tmp)
+ @} else
+ print
+@}
+@end example
+
+@noindent
+La funzione @code{close()} viene chiamata per assicurarsi che, se appaiono
+nell'input due righe @samp{@@execute} identiche, il comando sia eseguito per
+ciascuna di esse.
+@ifnottex
+@ifnotdocbook
+@xref{Chiusura file e @dfn{pipe}}.
+@end ifnotdocbook
+@end ifnottex
+@c This example is unrealistic, since you could just use system
+Dato l'input:
+
+@example
+pippo
+pluto
+paperino
+@@execute who
+gastone
+@end example
+
+@noindent
+il programma potrebbe produrre:
+
+@cindex Robbins, Bill
+@cindex Robbins, Miriam
+@cindex Robbins, Arnold
+@example
+pippo
+pluto
+paperino
+arnold ttyv0 Jul 13 14:22
+miriam ttyp0 Jul 13 14:23 (murphy:0)
+bill ttyp1 Jul 13 14:23 (murphy:0)
+gastone
+@end example
+
+@noindent
+Si osservi che questo programma ha eseguito @command{who} e stampato il
+risultato. (Eseguendo questo programma, @`e chiaro che ciascun utente otterr@`a
+risultati diversi, a seconda di chi @`e collegato al sistema.)
+
+Questa variante di @code{getline} divide il record in campi, imposta il valore
+di @code{NF}, e ricalcola il valore di @code{$0}. I valori di
+@code{NR} e @code{FNR} non vengono cambiati.
+Viene impostato @code{RT}.
+
+@cindex POSIX @command{awk}, operatore I/O @code{|} e
+@c Thanks to Paul Eggert for initial wording here
+Per lo standard POSIX, @samp{@var{espressione} | getline} @`e ambiguo se
+@var{espressione} contiene operatori che non sono all'interno di parentesi,
+ad esclusione di @samp{$}. Per esempio,
+@samp{@w{"echo "} "date" | getline} @`e ambiguo perch@'e
+l'operatore di concatenazione non @`e tra parentesi. Si dovrebbe scrivere
+invece @samp{(@w{"echo "} "date") | getline}, se il programma dev'essere
+portabile su tutte le implementazioni di @command{awk}.
+
+@cindex Brian Kernighan, @command{awk} di
+@cindex @command{mawk}, programma di utilit@`a
+@cindex programma di utilit@`a @command{mawk}
+@quotation NOTA
+Sfortunatamente, @command{gawk} non ha un comportamento uniforme nel
+trattare un costrutto come @samp{@w{"echo "} "date" | getline}.
+La maggior parte delle versioni, compresa la versione corrente, lo tratta
+come @samp{@w{("echo "} "date") | getline}.
+(Questo @`e anche il comportamento di BWK @command{awk}.)
+Alcune versioni invece lo trattano come
+@samp{@w{"echo "} ("date" | getline)}.
+(Questo @`e il comportamento di @command{mawk}.)
+In breve, per evitare problemi, @`e @emph{sempre} meglio usare parentesi
+esplicite.
+@end quotation
+
+@node Getline variabile @dfn{pipe}
+@subsection Usare @code{getline} in una variabile da una @dfn{pipe}
+@cindex variabili, usare in comando @code{getline}
+
+Quando si usa @samp{@var{comando} | getline @var{var}},
+l'output di @var{comando} @`e inviato tramite una @dfn{pipe} a
+@code{getline} ad una variabile @var{var}. Per esempio, il
+seguente programma legge la data e l'ora corrente nella variabile
+@code{current_time}, usando il programma di utilit@`a @command{date}, e poi lo
+stampa:
+
+@example
+BEGIN @{
+ "date" | getline current_time
+ close("date")
+ print "Report printed on " current_time
+@}
+@end example
+
+In questa versione di @code{getline}, nessuna delle variabili predefinite @`e
+cambiata e il record non @`e diviso in campi. In ogni caso, @code{RT} viene
+impostato.
+
+@ifinfo
+@c Thanks to Paul Eggert for initial wording here
+Per lo standard POSIX, @samp{@var{espressione} | getline @var{var}} @`e ambiguo
+se @var{espressione} contiene operatori che non sono all'interno di parentesi
+ad esclusione di @samp{$}; per esempio,
+@samp{@w{"echo "} "date" | getline @var{var}} @`e ambiguo
+perch@'e l'operatore di concatenazione non @`e tra parentesi. Si dovrebbe
+scrivere invece @samp{(@w{"echo "} "date") | getline @var{var}} se il
+programma dev'essere portabile su tutte le implementazioni di @command{awk}.
+@end ifinfo
+
+@node Getline coprocesso
+@subsection Usare @code{getline} da un coprocesso
+@cindex coprocessi, @code{getline} da
+@cindex @code{getline}, comando, coprocessi@comma{} usare dal
+@cindex @code{|} (barra verticale), operatore @code{|&} (I/O)
+@cindex barra verticale (@code{|}), operatore @code{|&} (I/O)
+@cindex operatori, input/output
+@cindex differenze tra @command{awk} e @command{gawk}, operatori di input/output
+
+Leggere dell'input in @code{getline} da una @dfn{pipe} @`e un'operazione
+unidirezionale.
+Il comando avviato con @samp{@var{comando} | getline} invia dati
+@emph{al} programma @command{awk}.
+
+Occasionalmente, si potrebbe avere la necessit@`a di inviare dei dati a un altro
+programma che li elabori, per poi leggere il risultato che esso genera.
+@command{gawk} permette di avviare un @dfn{coprocesso}, col quale sono
+possibili comunicazioni bidirezionali. Questo vien fatto con l'operatore
+@samp{|&}.
+Tipicamente, dapprima si inviano dati al coprocesso e poi si leggono
+i risultati da esso prodotto, come mostrato di seguito:
+
+@example
+print "@var{some query}" |& "db_server"
+"db_server" |& getline
+@end example
+
+@noindent
+esso invia una richiesta a @command{db_server} e poi legge i risultati.
+
+I valori di @code{NR} e
+@code{FNR} non vengono cambiati,
+perch@'e non @`e cambiato il flusso principale.
+In ogni caso, il record @`e diviso in campi
+nel solito modo, cambiando cos@`{@dotless{i}} i valori di @code{$0}, degli altri campi,
+e di @code{NF} e @code{RT}.
+
+I coprocessi sono una funzionalit@`a avanzata. Vengono trattati qui solo perch@'e
+@ifnotinfo
+questa @`e la
+@end ifnotinfo
+@ifinfo
+questo @`e il
+@end ifinfo
+@value{SECTION} su @code{getline}.
+@xref{I/O bidirezionale},
+dove i coprocessi vengono trattati pi@`u dettagliatamente.
+
+@node Getline variabile coprocesso
+@subsection Usare @code{getline} in una variabile da un coprocesso
+@cindex variabili, usare in comando @code{getline}
+
+Quando si usa @samp{@var{comando} |& getline @var{var}}, l'output dal
+coprocesso @var{comando} viene inviato tramite una @dfn{pipe} bidirezionale a
+@code{getline} e nella variabile @var{var}.
+
+In questa versione di @code{getline}, nessuna delle variabili predefinite
+viene cambiata e il record non viene diviso in campi. La sola variabile che
+cambia @`e @var{var}.
+In ogni caso, @code{RT} viene impostato.
+
+@ifinfo
+I coprocessi sono una funzionalit@`a avanzata. Vengono trattati qui solo perch@'e
+questo @`e il @value{SECTION} su @code{getline}.
+@xref{I/O bidirezionale},
+dove i coprocessi vengono trattati pi@`u dettagliatamente.
+@end ifinfo
+
+@node Note su getline
+@subsection Cose importanti da sapere riguardo a @code{getline}
+Qui sono elencate diverse considerazioni su @code{getline}
+da tener presenti:
+
+@itemize @value{BULLET}
+@item
+Quando @code{getline} cambia il valore di @code{$0} e @code{NF},
+@command{awk} @emph{non} salta automaticamente all'inizio del
+programma per iniziare a provare il nuovo record su ogni criterio di ricerca.
+Comunque, il nuovo record viene provato su ogni regola successiva.
+
+@cindex differenze tra @command{awk} e @command{gawk}, limitazioni di implementazione
+@cindex implementazione, problemi, @command{gawk}, limiti
+@cindex @command{awk}, implementazioni, limiti
+@cindex @command{gawk}, problemi di implementazioni, limiti
+@item
+Alcune tra le prime implementazioni di @command{awk} limitano a una sola il
+numero di @dfn{pipeline} che un programma @command{awk} pu@`o tenere aperte.
+In @command{gawk}, non c'@`e questo limite.
+Si possono aprire tante @dfn{pipeline} (e coprocessi) quante ne permette il
+sistema operativo in uso.
+
+@cindex effetti collaterali, variabile @code{FILENAME}
+@cindex @code{FILENAME}, variabile, impostare con @code{getline}
+@cindex angolo buio, variabile @code{FILENAME}
+@cindex @code{getline}, comando, variabile @code{FILENAME} e
+@cindex @code{BEGIN}, criterio di ricerca, @code{getline} e
+@item
+Un interessante effetto collaterale si ha se si usa @code{getline}, senza
+una ridirezione, all'interno di una regola @code{BEGIN}. Poich@'e una
+@code{getline} non ridiretta legge dai @value{DF} specificati nella riga di
+comando, il primo comando @code{getline} fa s@`{@dotless{i}} che @command{awk} imposti
+il valore di @code{FILENAME}. Normalmente, @code{FILENAME} non ha ancora un
+valore all'interno delle regole @code{BEGIN}, perch@'e non si @`e ancora
+iniziato a elaborare il
+@value{DF} della riga di comando.
+@value{DARKCORNER}
+(Si veda @ref{BEGIN/END};
+e @pxref{Variabili auto-assegnate}.)
+
+@item
+Usare @code{FILENAME} con @code{getline}
+(@samp{getline < FILENAME})
+pu@`o essere fonte di
+confusione. @command{awk} apre un flusso separato di input, diverso dal
+file in input corrente. Comunque, poich@'e non si usa una variabile,
+@code{$0} e @code{NF} vengono aggiornati. Se si sta facendo questo, @`e
+probabilmente per sbaglio, e si dovrebbe rivedere quello che si sta cercando
+di fare.
+
+@item
+@ifdocbook
+La prossima @value{SECTION}
+@end ifdocbook
+@ifnotdocbook
+@ref{Sommario di getline},
+@end ifnotdocbook
+contiene una tabella che sintetizza le
+varianti di @code{getline} e le variabili da esse modificate.
+@`E degno di nota che le varianti che non usano la ridirezione
+possono far s@`{@dotless{i}} che @code{FILENAME} venga aggiornato se chiedono ad
+@command{awk} di iniziare a leggere un nuovo file in input.
+
+@item
+@cindex Moore, Duncan
+Se la variabile assegnata @`e un'espressione con effetti collaterali, versioni
+differenti di @command{awk} si comportano in modo diverso quando trovano la
+fine-del-file [EOF]. Alcune versioni non valutano l'espressione; molte
+versioni (compreso @command{gawk}) lo fanno. Si veda un esempio, gentilmente
+fornito da Duncan Moore:
+
+@ignore
+Date: Sun, 01 Apr 2012 11:49:33 +0100
+From: Duncan Moore <duncan.moore@@gmx.com>
+@end ignore
+
+@example
+BEGIN @{
+ system("echo 1 > f")
+ while ((getline a[++c] < "f") > 0) @{ @}
+ print c
+@}
+@end example
+
+@noindent
+Qui l'effetto secondario @`e @samp{++c}. Se viene trovata la fine del file
+@emph{prima} di assegnare l'elemento @code{a}, @code{c} @`e incrementato o no?
+
+@command{gawk} tratta @code{getline} come una chiamata di funzione, e valuta
+l'espressione @samp{a[++c]} prima di cercare di leggere da @file{f}.
+Comunque, alcune versioni di @command{awk} valutano l'espressione solo
+se c'@`e un valore di stringa da assegnare.
+@end itemize
+
+@node Sommario di getline
+@subsection Sommario delle varianti di @code{getline}
+@cindex @code{getline}, comando, varianti
+
+La @ref{tabella-varianti-getline}
+riassume le otto varianti di @code{getline},
+elencando le variabili predefinite che sono impostate da ciascuna di esse,
+e se la variante @`e standard o @`e un'estensione di @command{gawk}.
+Nota: per ogni variante, @command{gawk} imposta la variabile predefinita
+@code{RT}.
+
+@float Tabella,tabella-varianti-getline
+@caption{Varianti di @code{getline} e variabili impostate da ognuna}
+@multitable @columnfractions .33 .38 .27
+@headitem Variante @tab Effetto @tab @command{awk} / @command{gawk}
+@item @code{getline} @tab Imposta @code{$0}, @code{NF}, @code{FNR}, @code{NR}, e @code{RT} @tab @command{awk}
+@item @code{getline} @var{var} @tab Imposta @var{var}, @code{FNR}, @code{NR}, e @code{RT} @tab @command{awk}
+@item @code{getline <} @var{file} @tab Imposta @code{$0}, @code{NF}, e @code{RT} @tab @command{awk}
+@item @code{getline @var{var} < @var{file}} @tab Imposta @var{var} e @code{RT} @tab @command{awk}
+@item @var{comando} @code{| getline} @tab Imposta @code{$0}, @code{NF}, e @code{RT} @tab @command{awk}
+@item @var{comando} @code{| getline} @var{var} @tab Imposta @var{var} e @code{RT} @tab @command{awk}
+@item @var{comando} @code{|& getline} @tab Imposta @code{$0}, @code{NF}, e @code{RT} @tab @command{gawk}
+@item @var{comando} @code{|& getline} @var{var} @tab Imposta @var{var} e @code{RT} @tab @command{gawk}
+@end multitable
+@end float
+
+@node Timeout in lettura
+@section Leggere input entro un tempo limite
+@cindex tempo limite, leggere input
+@cindex @dfn{timeout}, si veda tempo limite
+
+@cindex differenze tra @command{awk} e @command{gawk}, tempo limite per lettura
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive una funzionalit@`a disponibile solo in
+@command{gawk}.
+
+Si pu@`o specificare un tempo limite in millisecondi per leggere l'input dalla
+tastiera, da una @dfn{pipe} o da una comunicazione bidirezionale, compresi i
+@dfn{socket} TCP/IP. Questo pu@`o essere fatto per input, per comando o per
+connessione, impostando un elemento speciale nel vettore @code{PROCINFO}
+(@pxref{Variabili auto-assegnate}):
+
+@example
+PROCINFO["nome_input", "READ_TIMEOUT"] = @var{tempo limite in millisecondi}
+@end example
+
+Se @`e impostato, @command{gawk} smette di attendere una risposta e restituisce
+insuccesso se non sono disponibili dati da leggere entro il limite di tempo
+specificato. Per esempio, un cliente TCP pu@`o decidere di abbandonare se
+non riceve alcuna risposta dal server dopo un certo periodo di tempo:
+
+@example
+Service = "/inet/tcp/0/localhost/daytime"
+PROCINFO[Service, "READ_TIMEOUT"] = 100
+if ((Service |& getline) > 0)
+ print $0
+else if (ERRNO != "")
+ print ERRNO
+@end example
+
+Qui vediamo come ottenere dati interattivamente dall'utente@footnote{Questo
+presuppone che lo standard input provenga dalla tastiera.} aspettando per
+non pi@`u di cinque secondi:
+
+@example
+PROCINFO["/dev/stdin", "READ_TIMEOUT"] = 5000
+while ((getline < "/dev/stdin") > 0)
+ print $0
+@end example
+
+@command{gawk} termina l'operazione di lettura se l'input non
+arriva entro il periodo di tempo limite, restituisce insuccesso
+e imposta @code{ERRNO} a una stringa di valore adeguato.
+Un valore del tempo limite negativo o pari a zero equivale a non specificare
+affatto un tempo limite.
+
+Si pu@`o impostare un tempo limite anche per leggere dalla tastiera nel ciclo
+implicito che legge i record in input e li confronta coi criteri di ricerca,
+come:
+
+@example
+$ @kbd{gawk 'BEGIN @{ PROCINFO["-", "READ_TIMEOUT"] = 5000 @}}
+> @kbd{@{ print "You entered: " $0 @}'}
+@kbd{gawk}
+@print{} You entered: gawk
+@end example
+
+In questo caso, la mancata risposta entro cinque secondi d@`a luogo al seguente
+messaggio di errore:
+
+@example
+@c questo @`e l'output effettivo - Antonio
+@error{} gawk: linea com.:2: (FILENAME=- FNR=1) fatale: errore leggendo
+@error{} file in input `-': Connessione scaduta
+@end example
+
+Il tempo limite pu@`o essere impostato o cambiato in qualsiasi momento, e avr@`a
+effetto al tentativo successivo di leggere dal dispositivo di input. Nel
+seguente esempio, partiamo con un valore di tempo limite di un secondo e
+lo riduciamo progressivamente di un decimo di secondo finch@'e l'attesa
+per l'input diventa illimitata.
+
+@example
+PROCINFO[Service, "READ_TIMEOUT"] = 1000
+while ((Service |& getline) > 0) @{
+ print $0
+ PROCINFO[Service, "READ_TIMEOUT"] -= 100
+@}
+@end example
+
+@quotation NOTA
+Non si deve dare per scontato che l'operazione di lettura si blocchi
+esattamente dopo che @`e stato stampato il decimo record. @`E possibile che
+@command{gawk} legga e tenga in memoria i dati di pi@`u di un record
+la prima volta. Per questo, cambiare il valore del tempo
+limite come nell'esempio appena visto non @`e molto utile.
+@end quotation
+
+Se l'elemento di @code{PROCINFO} non @`e presente e la variabile d'ambiente
+@env{GAWK_READ_TIMEOUT} esiste,
+@command{gawk} usa il suo valore per inizializzare il valore di tempo limite.
+L'uso esclusivo della variabile d'ambiente per specificare il tempo limite
+ha lo svantaggio di non essere
+adattabile per ogni comando o per ogni connessione.
+
+@command{gawk} considera errore un superamento di tempo limite anche se
+il tentativo di leggere dal dispositivo sottostante potrebbe riuscire
+in un tentativo successivo. Questa @`e una limitazione, e inoltre
+significa che non @`e possibile usarlo per ottenere input multipli,
+provenienti da due o pi@`u sorgenti. @xref{Proseguire dopo errore in input}
+per una modalit@`a che consente di tentare ulteriori operazioni di I/O.
+
+Assegnare un valore di tempo limite previene un blocco a tempo indeterminato
+legato a operazioni di lettura. Si tenga per@`o presente che ci sono altre
+situazioni in cui @command{gawk} pu@`o restare bloccato in attesa che un
+dispositivo di input sia pronto. Un cliente di rete a volte pu@`o impiegare
+molto tempo per stabilire una
+connessione prima di poter iniziare a leggere qualsiasi dato,
+oppure il tentativo di aprire un file speciale FIFO in lettura pu@`o bloccarsi
+indefinitamente in attesa che qualche altro processo lo apra in scrittura.
+
+@node Proseguire dopo errore in input
+@section Elaborare ulteriore input dopo certi errori di I/O
+@cindex proseguire dopo errore in input
+@cindex errore in input, possibilit@`a di proseguire
+
+@cindex differenze tra @command{awk} e @command{gawk}, proseguire dopo errore in input
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive una funzionalit@`a disponibile solo in
+@command{gawk}.
+
+Qualora @command{gawk} incontri un errore durante la lettura dell'input,
+per default @code{getline} ha come codice di ritorno @minus{}1, e i
+successivi tentativi di leggere dallo stesso file restituiscono una
+indicazione di fine-file. @`E tuttavia possibile chiedere a
+@command{gawk} di consentire un ulteriore tentativo di lettura in presenza
+di certi errori, impostando uno speciale elemento del vettore
+@code{PROCINFO} (@pxref{Variabili auto-assegnate}):
+
+@example
+PROCINFO["@var{nome_input_file}", "RETRY"] = 1
+@end example
+
+Quando un tale elemento esiste, @command{gawk} controlla il valore della
+variabile di sistema
+(nel linguaggio C)
+@code{errno} quando si verifica un errore di I/O.
+Se @code{errno} indica che un ulteriore tentativo di lettura pu@`o
+terminare con successo, @code{getline} ha come codice di ritorno @minus{}2
+e ulteriori chiamate a @code{getline} possono terminare correttamente.
+Questo vale per i seguenti valori di @code{errno}: @code{EAGAIN},
+@code{EWOULDBLOCK}, @code{EINTR}, e @code{ETIMEDOUT}.
+
+Questa funzionalit@`a @`e utile quando si assegna un valore all'elemento
+@code{PROCINFO["@var{nome_input_file}", "READ_TIMEOUT"]} o in situazioni
+in cui un descrittore di file sia stato configurato per comportarsi in
+modo non bloccante.
+
+@node Directory su riga di comando
+@section Directory sulla riga di comando
+@cindex differenze tra @command{awk} e @command{gawk}, directory sulla riga di comando
+@cindex directory, riga di comando
+@cindex riga di comando, directory su
+
+Per lo standard POSIX, i file che compaiono sulla riga di comando di
+@command{awk} devono essere file di testo; @`e un errore fatale se non lo sono.
+La maggior parte delle versioni di @command{awk} genera un errore fatale
+quando trova una directory sulla riga di comando.
+
+Per default, @command{gawk} emette un avvertimento se c'@`e una directory sulla
+riga di comando, e in ogni caso la ignora. Questo rende pi@`u facile usare
+metacaratteri di shell col proprio programma @command{awk}:
+
+@example
+$ @kbd{gawk -f whizprog.awk *} @ii{Le directory potrebbero far fallire il programma}
+@end example
+
+Se viene data una delle opzioni @option{--posix}
+o @option{--traditional}, @command{gawk} considera invece
+una directory sulla riga di comando come un errore fatale.
+
+@xref{Esempio di estensione Readdir} per un modo di trattare le directory
+come dati usabili da un programma @command{awk}.
+
+@sp 2
+@node Sommario di Input
+@section Sommario di Input
+
+@itemize @value{BULLET}
+@item
+L'input @`e diviso in record in base al valore di @code{RS}.
+Le possibilit@`a sono le seguenti:
+
+@multitable @columnfractions .28 .45 .40
+@headitem Valore di @code{RS} @tab Record separati da @dots{} @tab @command{awk} / @command{gawk}
+@item Un carattere singolo @tab Quel carattere @tab @command{awk}
+@item La stringa nulla (@code{""}) @tab Serie di due o pi@`u ritorni a capo @tab @command{awk}
+@item Un'espressione regolare @tab Testo corrispondente alla @dfn{regexp} @tab @command{gawk}
+@end multitable
+
+@item
+@code{FNR} indica quanti record sono stati letti dal file in input corrente;
+@code{NR} indica quanti record sono stati letti in totale.
+
+@item
+@command{gawk} imposta @code{RT} al testo individuato da @code{RS}.
+
+@item
+Dopo la divisione dell'input in record, @command{awk} divide
+i record in singoli campi, chiamati @code{$1}, @code{$2} e cos@`{@dotless{i}}
+via. @code{$0} @`e l'intero record, e @code{NF} indica quanti campi
+contiene. Il metodo di default per dividere i campi utilizza i
+caratteri di spazio vuoto.
+
+@item Si pu@`o far riferimento ai campi usando una variabile, come in @code{$NF}.
+Ai campi possono anche essere assegnati dei valori, e questo implica che il
+valore di @code{$0} sia ricalcolato se ad esso si fa riferimento in seguito.
+Fare un assegnamento a un campo con un numero maggiore di @code{NF} crea il
+campo e ricostruisce il record, usando @code{OFS} per separare i campi.
+Incrementare @code{NF} fa la stessa cosa. Decrementare @code{NF} scarta dei
+campi e ricostruisce il record.
+
+@item
+Separare i campi @`e pi@`u complicato che separare i record.
+
+@multitable @columnfractions .40 .40 .20
+@headitem Valore del separatore di campo @tab Campi separati @dots{} @tab @command{awk} / @command{gawk}
+@item @code{FS == " "} @tab Da serie di spazi vuoti @tab @command{awk}
+@item @code{FS == @var{un solo carattere}} @tab Da quel carattere @tab @command{awk}
+@item @code{FS == @var{espr. reg.}} @tab Dal testo che corrisponde alla @dfn{regexp} @tab @command{awk}
+@item @code{FS == ""} @tab Cos@`{@dotless{i}} ogni singolo carattere @`e un campo separato @tab @command{gawk}
+@item @code{FIELDWIDTHS == @var{lista di colonne}} @tab Basata sulla posizione del carattere @tab @command{gawk}
+@item @code{FPAT == @var{regexp}} @tab Dal testo attorno al testo corrispondente alla @dfn{regexp} @tab @command{gawk}
+@end multitable
+
+@item
+Usando @samp{FS = "\n"} l'intero record sar@`a un unico campo
+(nell'ipotesi che i record siano separati da caratteri di ritorno a capo).
+
+@item
+@code{FS} pu@`o essere impostato dalla riga di comando con l'opzione
+@option{-F}.
+Si pu@`o fare la stessa cosa usando un assegnamento di variabile da riga di
+comando.
+
+@item
+@code{PROCINFO["FS"]} permette di sapere come i campi sono separati.
+
+@item
+@code{getline} nelle sue diverse forme serve per leggere record aggiuntivi
+provenienti dal flusso di input di default, da un file, o da una @dfn{pipe}
+o da un coprocesso.
+
+@item
+@code{PROCINFO[@var{file}, "READ_TIMEOUT"]} si pu@`o usare per impostare un
+tempo limite alle operazioni di lettura da @var{file}.
+
+@item
+Le directory sulla riga di comando generano un errore fatale per
+@command{awk} standard;
+@command{gawk} le ignora se non @`e in modalit@`a POSIX.
+
+@end itemize
+
+@c EXCLUDE START
+@node Esercizi su Input
+@section Esercizi
+
+@enumerate
+@item
+Usando la variabile @code{FIELDWIDTHS} (@pxref{Dimensione costante}),
+scrivere un programma per leggere i dati delle elezioni, dove ogni record
+rappresenta i voti di un votante. Trovare un modo per definire quali colonne
+sono associate a ogni quesito elettorale, e stampare i voti totali,
+comprese le astensioni, per ciascun quesito.
+@item
+La @ref{Getline semplice}, ha illustrato un programma per rimuovere i commenti
+in stile C (@samp{/* @dots{} */}) dall'input. Quel programma
+non funziona se un commento termina in una riga e il successivo commento
+inizia nella stessa riga.
+Il problema si pu@`o risolvere con una semplice modifica. Quale?
+
+@end enumerate
+@c EXCLUDE END
+
+@node Stampare
+@chapter Stampare in output
+
+@cindex stampare
+@cindex output, stampare, si veda stampare
+Una delle azioni che un programma fa pi@`u comunemente, @`e quella di produrre
+@dfn{stampe}, ossia scrivere in output l'input letto, tutto o in parte.
+Si pu@`o usare l'istruzione @code{print} per una stampa semplice, e l'istruzione
+@code{printf} per una formattazione dell'output pi@`u sofisticata.
+L'istruzione @code{print} non ha un limite al numero di elementi quando
+calcola @emph{quali} valori stampare. Peraltro, con due eccezioni,
+non @`e possibile specificare @emph{come} stamparli: quante
+colonne, se usare una notazione esponenziale o no, etc.
+(Per le eccezioni, @pxref{Separatori di output} e
+la @ref{OFMT}.)
+Per stampare fornendo delle specifiche, @`e necessario usare
+l'istruzione @code{printf}
+(@pxref{Printf}).
+
+@cindex istruzione @code{print}
+@cindex istruzione @code{printf}
+Oltre alla stampa semplice e formattata, questo @value{CHAPTER}
+esamina anche le ridirezioni di I/O verso file e @dfn{pipe}, introduce
+i @value{FNS} speciali che @command{gawk} elabora internamente,
+e parla della funzione predefinita @code{close()}.
+
+@menu
+* Print:: L'istruzione @code{print}.
+* Esempi su print:: Semplici esempi di
+ istruzioni @code{print}.
+* Separatori di output:: I separatori di output e come
+ modificarli.
+* OFMT:: Controllare l'output di numeri con
+ @code{print}.
+* Printf:: l'istruzione @code{printf}.
+* Ridirezione:: Come ridirigere l'output a diversi
+ file e @dfn{pipe}.
+* FD speciali:: I/O con FD [Descrittori File]
+ speciali.
+* File speciali:: Interpretazione nomi file in
+ @command{gawk}. @command{gawk}
+ Permette di accedere a descrittori
+ file gi@`a aperti a inizio esecuzione
+* Chiusura file e @dfn{pipe}:: Chiudere file in input e di output e
+ @dfn{pipe}.
+* Continuazione dopo errori:: Abilitare continuazione dopo errori
+ in output.
+* Sommario di Output:: Sommario di Output.
+* Esercizi su Output:: Esercizi.
+@end menu
+
+@node Print
+@section L'istruzione @code{print}
+
+L'istruzione @code{print} si usa per produrre dell'output formattato in
+maniera semplice, standardizzata. Si
+specificano solo le stringhe o i numeri
+da stampare, in una lista separata da virgole. Questi elementi sono stampati,
+separati tra loro da spazi singoli, e alla fine viene stampato un ritorno a
+capo. L'istruzione @`e simile a questa:
+
+@example
+print @var{elemento1}, @var{elemento2}, @dots{}
+@end example
+
+@noindent
+L'intera lista di elementi pu@`o facoltativamente essere racchiusa fra
+parentesi. Le parentesi sono obbligatorie se qualche espressione presente
+in uno degli elementi usa l'operatore relazionale @samp{>}, che potrebbe
+essere confuso con una ridirezione dell'output (@pxref{Ridirezione}).
+
+Gli elementi da stampare possono essere stringhe costanti o numeri, campi
+del record corrente (come @code{$1}), variabili, o quasiasi espressione
+@command{awk}. I valori numerici sono convertiti in stringhe prima di essere
+stampati.
+
+@cindex record, stampare
+@cindex righe, vuote, stampare
+@cindex testo, stampare
+Una semplice istruzione @samp{print} senza specificare elementi equivale a
+@samp{print $0}: stampa l'intero record corrente. Per stampare una riga
+vuota, si usa @samp{print ""}.
+Per stampare un testo che non cambia, si usi come elemento una costante
+stringa, per esempio @w{@code{"Non v'allarmate"}}. Dimenticandosi di mettere
+i doppi apici, il testo @`e preso per un'espressione @command{awk},
+e probabilmente verr@`a emesso un messaggio di errore. Occorre tener presente
+che tra ogni coppia di elementi viene stampato uno spazio.
+
+Si noti che l'istruzione @code{print} @`e un'istruzione, e non
+un'espressione: non @`e possibile usarla nella parte modello [di ricerca] di
+un'istruzione @dfn{criterio di ricerca--azione}, per esempio.
+
+@node Esempi su print
+@section Esempi di istruzioni @code{print}
+
+Ogni istruzione @code{print} produce almeno una riga in output. Comunque,
+non @`e limitata a una sola riga. Se il valore di un elemento @`e una stringa
+che contiene un ritorno a capo, il ritorno a capo @`e stampato insieme al
+resto della stringa. Una
+singola istruzione @code{print} pu@`o in questo modo generare un numero
+qualsiasi di righe.
+
+@cindex ritorno a capo, stampare un
+Quel che segue @`e un esempio di stampa di una stringa che contiene al suo
+interno dei
+@ifinfo
+ritorni a capo
+(la @samp{\n} @`e una sequenza di protezione, che si usa per rappresentare il
+carattere di ritorno a capo; @pxref{Sequenze di protezione}):
+@end ifinfo
+@ifhtml
+ritorni a capo
+(la @samp{\n} @`e una sequenza di protezione, che si usa per rappresentare il
+carattere di ritorno a capo; @pxref{Sequenze di protezione}):
+@end ifhtml
+@ifnotinfo
+@ifnothtml
+ritorni a capo:
+@end ifnothtml
+@end ifnotinfo
+
+@example
+$ @kbd{awk 'BEGIN @{ print "riga uno\nriga due\nriga tre" @}'}
+@print{} riga uno
+@print{} riga due
+@print{} riga tre
+@end example
+
+@cindex campi, stampare
+Il prossimo esempio, eseguito sul file @file{inventory-shipped},
+stampa i primi due campi di ogni record in input, separandoli con uno
+spazio:
+
+@example
+$ @kbd{awk '@{ print $1, $2 @}' inventory-shipped}
+@print{} Jan 13
+@print{} Feb 15
+@print{} Mar 15
+@dots{}
+@end example
+
+@cindex istruzione @code{print}, virgole, omettere
+@cindex debug, istruzione @code{print}@comma{} omissione virgole
+Un errore frequente usando l'istruzione @code{print} @`e quello di tralasciare
+la virgola tra due elementi. Questo ha spesso come risultato la stampa di
+elementi attaccati tra loro, senza lo spazio di separazione. Il motivo per
+cui ci@`o accade @`e che la scrittura di due
+espressioni di stringa in @command{awk} ne indica la concatenazione. Qui si
+vede l'effetto dello stesso programma,
+senza le virgole:
+
+@example
+$ @kbd{awk '@{ print $1 $2 @}' inventory-shipped}
+@print{} Jan13
+@print{} Feb15
+@print{} Mar15
+@dots{}
+@end example
+
+@cindex @code{BEGIN}, criterio di ricerca, intestazioni, aggiungere
+Per chi non conosce il file @file{inventory-shipped} nessuno
+dei due output di esempio risulta molto comprensibile. Una riga iniziale di
+intestazione li renderebbe pi@`u chiari.
+Aggiungiamo qualche intestazione alla nostra tabella dei mesi
+(@code{$1}) e dei contenitori verdi spediti (@code{$2}). Lo facciamo usando
+una regola @code{BEGIN} (@pxref{BEGIN/END}) in modo che le intestazioni siano
+stampate una volta sola:
+
+@example
+awk 'BEGIN @{ print "Mese Contenitori"
+ print "----- -----------" @}
+ @{ print $1, $2 @}' inventory-shipped
+@end example
+
+@noindent
+Una volta eseguito, il programma stampa questo:
+
+@example
+Mese Contenitori
+----- -----------
+Jan 13
+Feb 15
+Mar 15
+@dots{}
+@end example
+
+@noindent
+Il solo problema, in effetti, @`e che le intestazioni e i dati della tabella
+non sono allineati! Possiamo provvedere stampando alcuni spazi tra i due
+campi:
+
+@example
+@group
+awk 'BEGIN @{ print "Mese Contenitori"
+ print "----- -----------" @}
+ @{ print $1, " ", $2 @}' inventory-shipped
+@end group
+@end example
+
+@cindex istruzione @code{printf}, colonne@comma{} allineamento
+@cindex colonne, allineamento
+Allineare le colonne in questo modo pu@`o diventare piuttosto
+complicato, quando ci sono parecchie colonne da tenere allineate. Contare gli
+spazi per due o tre colonne @`e semplice, ma oltre questo limite comincia a
+volerci molto tempo. Ecco perch@'e @`e disponibile l'istruzione @code{printf}
+(@pxref{Printf});
+una delle possibilit@`a che offre @`e quella di allineare colonne di dati.
+
+@cindex continuazione di riga, in istruzione @code{print}
+@cindex istruzione @code{print}, continuazione di riga e
+@cindex @code{print}, istruzione, continuazione di riga e
+@quotation NOTA
+Si pu@`o continuare su pi@`u righe sia l'istruzione @code{print} che l'istruzione
+@code{printf} semplicemente mettendo un ritorno a capo dopo una virgola
+qualsiasi
+(@pxref{Istruzioni/Righe}).
+@end quotation
+
+@node Separatori di output
+@section I separatori di output e come modificarli
+
+@cindex variabile @code{OFS}
+Come detto sopra, un'istruzione @code{print} contiene una lista di elementi
+separati da virgole. Nell'output, gli elementi sono solitamente separati
+da spazi singoli. Non @`e detto tuttavia che debba sempre essere cos@`{@dotless{i}}; uno
+spazio singolo @`e semplicemnte il valore di default. Qualsiasi stringa di
+caratteri pu@`o essere usata come
+@dfn{separatore di campo in output} impostando la variabile
+predefinita @code{OFS}. Il valore iniziale di questa variabile @`e
+la stringa @w{@code{" "}} (cio@`e, uno spazio singolo).
+
+L'output di un'istruzione @code{print} completa @`e detto un @dfn{record di
+output}. Ogni istruzione @code{print} stampa un record di output, e alla fine
+ci aggiunge una stringa detta @dfn{separatore record in output} (o
+@code{ORS}). Il valore iniziale di @code{ORS} @`e la stringa @code{"\n"}
+(cio@`e, un carattere di ritorno a capo). Quindi, ogni istruzione
+@code{print} normalmente genera [almeno] una riga a s@'e stante.
+
+@cindex output, record
+@cindex separatore di record in output, si veda @code{ORS}, variabile
+@cindex @code{ORS}, variabile
+@cindex @code{BEGIN}, criterio di ricerca, variabili @code{OFS}/@code{ORS}, assegnare valori a
+Per cambiare il tipo di separazione in output di campi e record, si impostano
+valori differenti alle variabili @code{OFS} e @code{ORS}. Il posto pi@`u
+indicato per farlo @`e nella regola @code{BEGIN}
+(@pxref{BEGIN/END}), in modo che l'assegnazione abbia effetto prima
+dell'elaborazione di ogni record in input. Questi valori si possono
+anche impostare dalla riga di comando, prima della lista dei file in input,
+oppure usando l'opzione della riga di comando @option{-v}
+(@pxref{Opzioni}).
+L'esempio seguente stampa il primo e il secondo campo di ogni record in input,
+separati da un punto e virgola, con una riga vuota aggiunta dopo ogni
+ritorno a capo:
+
+
+@example
+$ @kbd{awk 'BEGIN @{ OFS = ";"; ORS = "\n\n" @}}
+> @kbd{@{ print $1, $2 @}' mail-list}
+@print{} Amelia;555-5553
+@print{}
+@print{} Anthony;555-3412
+@print{}
+@print{} Becky;555-7685
+@print{}
+@print{} Bill;555-1675
+@print{}
+@print{} Broderick;555-0542
+@print{}
+@print{} Camilla;555-2912
+@print{}
+@print{} Fabius;555-1234
+@print{}
+@print{} Julie;555-6699
+@print{}
+@print{} Martin;555-6480
+@print{}
+@print{} Samuel;555-3430
+@print{}
+@print{} Jean-Paul;555-2127
+@print{}
+@end example
+
+Se il valore di @code{ORS} non contiene un ritorno a capo, l'output del
+programma viene scritto tutto su un'unica riga.
+
+@node OFMT
+@section Controllare l'output di numeri con @code{print}
+@cindex numerico, formato di output
+@cindex formati numerici di output
+Quando si stampano valori numerici con l'istruzione @code{print},
+@command{awk} converte internamente ogni numero in una stringa di caratteri
+e stampa quella stringa. @command{awk} usa la funzione @code{sprintf()}
+per effettuare questa conversione
+(@pxref{Funzioni per stringhe}).
+Per ora, basta dire che la funzione @code{sprintf()}
+accetta una @dfn{specifica di formato} che indica come formattare
+i numeri (o le stringhe), e che ci sono svariati modi per formattare i
+numeri. Le differenti specifiche di formato sono trattate pi@`u
+esaurientemente
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Lettere di controllo}.
+
+@cindexawkfunc{sprintf}
+@cindex @code{OFMT}, variabile
+@cindex output, specificatore di formato@comma{} @code{OFMT}
+La variabile predefinita @code{OFMT} contiene la specifica di formato
+che @code{print} usa con @code{sprintf()} per convertire un numero in
+una stringa per poterla stampare.
+Il valore di default di @code{OFMT} @`e @code{"%.6g"}.
+Il modo in cui @code{print} stampa i numeri si pu@`o cambiare
+fornendo una specifica di formato differente
+per il valore di @code{OFMT}, come mostrato nell'esempio seguente:
+
+@example
+$ @kbd{awk 'BEGIN @{}
+> @kbd{OFMT = "%.0f" # Stampa numeri come interi (arrotonda)}
+> @kbd{print 17.23, 17.54 @}'}
+@print{} 17 18
+@end example
+
+@noindent
+@cindex angolo buio, variabile @code{OFMT}
+@cindex POSIX @command{awk}, variabile @code{OFMT} e
+@cindex variabile @code{OFMT}, POSIX @command{awk} e
+Per lo standard POSIX, il comportamento di @command{awk} @`e indefinito
+se @code{OFMT} contiene qualcosa di diverso da una specifica di conversione
+di un numero a virgola mobile.
+@value{DARKCORNER}
+
+@node Printf
+@section Usare l'istruzione @code{printf} per stampe sofisticate
+
+@cindex istruzione @code{printf}
+@cindex @code{printf}, istruzione
+@cindex output, formattato
+@cindex formattare l'output
+Per un controllo pi@`u ampio sul formato di output di quello fornito da
+@code{print}, si pu@`o usare @code{printf}.
+Con @code{printf} si pu@`o
+specificare lo spazio da utilizzare per ogni elemento, e anche le varie
+scelte di formattazione disponibile per i numeri (come la base da usare in
+output, se stampare con notazione esponenziale, se inserire un segno, e quante
+cifre stampare dopo il separatore decimale).
+
+@menu
+* Printf Fondamenti:: Sintassi dell'istruzione
+ @code{printf}.
+* Lettere di controllo:: Lettere di controllo del formato.
+* Modificatori di formato:: Modificatori specifiche di formato.
+* Esempi su printf:: Numerosi esempi.
+@end menu
+
+@node Printf Fondamenti
+@subsection Sintassi dell'istruzione @code{printf}
+
+@cindex istruzione @code{printf}, sintassi dell'
+@cindex @code{printf}, sintassi dell'istruzione
+Una semplice istruzione @code{printf} @`e qualcosa di simile a questo:
+
+@example
+printf @var{formato}, @var{elemento1}, @var{elemento2}, @dots{}
+@end example
+
+@noindent
+Come nel caso di @code{print}, l'intera lista degli argomenti pu@`o
+facoltativamente essere racchiusa fra
+parentesi. Anche qui, le parentesi sono obbligatorie se l'espressione di
+qualche elemento usa l'operatore
+relazionale @samp{>}, che potrebbe
+essere confuso con una ridirezione dell'output (@pxref{Ridirezione}).
+
+@cindex specificatori di formato
+La differenza tra @code{printf} e @code{print} @`e l'argomento @var{formato}.
+Questo @`e un'espressione il cui valore @`e visto come una stringa;
+specifica come scrivere in output ognuno degli altri argomenti. @`E chiamata
+@dfn{stringa di formato}.
+
+La stringa di formato @`e molto simile a quella usata dalla funzione di
+libreria ISO C @code{printf()}. Buona parte del @var{formato} @`e testo da
+stampare cos@`{@dotless{i}} come @`e scritto.
+All'interno di questo testo ci sono degli @dfn{specificatori di formato},
+uno per ogni elemento da stampare.
+Ogni specificatore di formato richiede di stampare l'elemento successivo
+nella lista degli argomenti
+in quella posizione del formato.
+
+L'istruzione @code{printf} non aggiunge in automatico un ritorno a capo
+al suo output. Scrive solo quanto specificato dalla stringa di formato.
+Quindi, se serve un ritorno a capo, questo va incluso nella stringa di formato.
+Le variabili di separazione dell'output @code{OFS} e @code{ORS} non hanno
+effetto sulle istruzioni @code{printf}.
+Per esempio:
+
+@example
+$ @kbd{awk 'BEGIN @{}
+> @kbd{ORS = "\nAHI!\n"; OFS = "+"}
+> @kbd{msg = "Non v\47allarmate!"}
+> @kbd{printf "%s\n", msg}
+> @kbd{@}'}
+@print{} Non v'allarmate!
+@end example
+
+@noindent
+Qui, n@'e il @samp{+} n@'e l'esclamazione @samp{AHI!} compaiono nel messaggio
+in output.
+
+@node Lettere di controllo
+@subsection Lettere di controllo del formato
+@cindex istruzione @code{printf}, lettere di controllo del formato
+@cindex @code{printf}, istruzione, lettere di controllo del formato
+@cindex specificatori di formato, istruzione @code{printf}
+
+Uno specificatore di formato inizia col carattere @samp{%} e termina con
+una @dfn{lettera di controllo del formato}; e dice all'istruzione
+@code{printf} come stampare un elemento. La lettera di controllo del
+formato specifica che @emph{tipo}
+di valore stampare. Il resto dello specificatore di formato @`e costituito da
+@dfn{modificatori} facoltativi che controllano @emph{come} stampare il valore,
+per esempio stabilendo la larghezza del campo. Ecco una lista delle
+lettere di controllo del formato:
+
+@c @asis for docbook to come out right
+@table @asis
+@item @code{%c}
+Stampa un numero come un carattere; quindi, @samp{printf "%c",
+65} stampa la lettera @samp{A}. L'output per un valore costituito da una
+stringa @`e il primo carattere della stringa stessa.
+
+@cindex angolo buio, caratteri di controllo del formato
+@cindex @command{gawk}, caratteri di controllo del formato
+@quotation NOTA
+Lo standard POSIX richiede che il primo carattere di una stringa sia stampato.
+In localizzazioni con caratteri multibyte, @command{gawk} tenta di
+convertire i primi byte della stringa in un carattere multibyte valido
+e poi di stampare la codifica multibyte di quel carattere.
+Analogamente, nella stampa di un valore numerico, @command{gawk} ammette che
+il valore appartenga all'intervallo numerico di valori che possono essere
+contenuti in un carattere multibyte.
+Se la conversione alla codifica multibyte non riesce, @command{gawk}
+usa gli ultimi otto bit della cifra (quelli meno significativi) come
+carattere da stampare.
+
+Altre versioni di @command{awk} generalmente si limitano a stampare
+il primo byte di una stringa o i valori numerici che possono essere
+rappresentati in un singolo byte (0--255).
+@end quotation
+
+
+@item @code{%d}, @code{%i}
+Stampa un numero intero in base decimale.
+Le due lettere di controllo sono equivalenti.
+(La specificazione @samp{%i} @`e ammessa per compatibilit@`a con ISO C.)
+
+@item @code{%e}, @code{%E}
+Stampa un numero nella notazione scientifica (con uso di esponente).
+Per esempio:
+
+@example
+printf "%4.3e\n", 1950
+@end example
+
+@noindent
+stampa @samp{1.950e+03}, con un totale di quattro cifre significative, tre
+delle quali
+seguono il punto che separa la parte intera da quella decimale
+[in Italia si usa la virgola al posto del punto]
+(L'espressione @samp{4.3} rappresenta due modificatori,
+introdotti nella prossima @value{SUBSECTION}).
+@samp{%E} usa @samp{E} invece di @samp{e} nell'output.
+
+@item @code{%f}
+Stampa un numero in notazione a virgola mobile.
+Per esempio:
+
+@example
+printf "%4.3f", 1950
+@end example
+
+@noindent
+stampa @samp{1950.000}, con un totale di quattro cifre significative, tre
+delle quali vengono dopo il punto decimale.
+(L'espressione @samp{4.3} rappresenta due modificatori,
+introdotti nella prossima @value{SUBSECTION}).
+
+In sistemi che implementano il formato a virgola mobile, come specificato
+dallo standard IEEE 754, il valore infinito negativo @`e rappresentato come
+@samp{-inf} o @samp{-infinity},
+e l'infinito positivo come
+@samp{inf} o @samp{infinity}.
+Il valore speciale ``not a number'' [non @`e un numero] viene scritto come
+@samp{-nan} o @samp{nan}
+(@pxref{Definizioni matematiche}).
+
+@item @code{%F}
+Come @samp{%f}, ma i valori di infinito e di ``not a number'' sono scritti
+in lettere maiuscole.
+
+Il formato @samp{%F} @`e un'estensione POSIX allo standard ISO C; non tutti
+i sistemi lo prevedono. In tali casi,
+@command{gawk} usa il formato @samp{%f}.
+
+@item @code{%g}, @code{%G}
+Stampa un numero usando o la notazione scientifica o quella a virgola
+mobile, scegliendo la forma pi@`u concisa; se il risultato @`e stampato usando la
+notazione scientifica, @samp{%G} usa @samp{E} invece di @samp{e}.
+
+@item @code{%o}
+Stampa un numero intero in ottale, senza segno
+(@pxref{Numeri non-decimali}).
+
+@item @code{%s}
+Stampa una stringa.
+
+@item @code{%u}
+Stampa un numero intero decimale, senza segno.
+(Questo formato @`e poco usato, perch@'e tutti i numeri in @command{awk}
+sono a virgola mobile; @`e disponibile principalmente per compatibilit@`a col
+linguaggio C.)
+
+@item @code{%x}, @code{%X}
+Stampa un intero esadecimale senza segno;
+@samp{%X} usa le lettere da @samp{A} a @samp{F}
+invece che da @samp{a} a @samp{f}
+(@pxref{Numeri non-decimali}).
+
+@item @code{%%}
+Stampa un solo carattere @samp{%}.
+Questa notazione non serve per stampare alcun
+argomento e ignora eventuali modificatori.
+@end table
+
+@cindex angolo buio, caratteri di controllo del formato
+@cindex @command{gawk}, caratteri di controllo del formato
+@quotation NOTA
+Quando si usano lettere di controllo del formato per numeri interi
+per stampare valori esterni all'intervallo massimo disponibile nel
+linguaggio C per i numeri interi,
+@command{gawk} usa lo
+specificatore di formato @samp{%g}. Se si specifica l'opzione @option{--lint}
+sulla riga di comando (@pxref{Opzioni}), @command{gawk}
+emette un messaggio di avvertimento. Altre versioni di @command{awk} possono
+stampare valori non validi, o comportarsi in modo completamente differente.
+@value{DARKCORNER}
+@end quotation
+
+@node Modificatori di formato
+@subsection Modificatori per specifiche di formato @code{printf}
+
+@cindex istruzione @code{printf}, modificatori
+@cindex @code{printf}, istruzione, modificatori
+@cindex modificatori@comma{} in specificatori di formato
+Una specifica di formato pu@`o anche includere dei @dfn{modificatori} che
+possono controllare che parte stampare del valore dell'elemento, e anche
+quanto spazio utilizzare per stamparlo.
+I modificatori sono posizionati tra il @samp{%} e la lettera che controlla
+il formato.
+Negli esempi seguenti verr@`a usato il simbolo del punto elenco ``@bullet{}'' per
+rappresentare
+spazi nell'output. Questi sono i modificatori previsti, nell'ordine in
+cui possono apparire:
+
+@table @asis
+@cindex differenze tra @command{awk} e @command{gawk}, tra istruzioni @code{print} e @code{printf}
+@cindex istruzione @code{printf}, specificatori posizionali
+@cindex @code{printf}, istruzione, specificatori posizionali
+@c the code{} does NOT start a secondary
+@cindex specificatori posizionali, istruzione @code{printf}
+@item @code{@var{N}$}
+Una costante intera seguita da un @samp{$} @`e uno @dfn{specificatore posizionale}.
+Normalmente, le specifiche di formato sono applicate agli argomenti
+nell'ordine in cui appaiono nella stringa di formato. Con uno specificatore
+posizionale, la specifica di formato @`e applicata a un argomento
+indicato per numero, invece che a quello che
+sarebbe il prossimo argomento nella lista. Gli specificatori posizionali
+iniziano a contare partendo da uno. Quindi:
+
+@example
+printf "%s %s\n", "Non", "v'allarmate"
+printf "%2$s %1$s\n", "v'allarmate", "Non"
+@end example
+
+@noindent
+stampa per due volte il famoso consiglio amichevole.
+
+A prima vista, questa funzionalit@`a non sembra di grande utilit@`a.
+Si tratta in effetti di un'estensione @command{gawk}, pensata per essere
+usata nella traduzione di messaggi emessi in fase di esecuzione.
+@xref{Ordinamento di printf},
+che descrive come e perch@'e usare specificatori posizionali.
+Per ora li possiamo ignorare.
+
+@item - @code{-} (Segno meno)
+Il segno meno, usato prima del modificatore di larghezza (si veda pi@`u avanti
+in questa lista),
+richiede di allineare a sinistra
+l'argomento mantenendo la larghezza specificata. Normalmente, l'argomento
+@`e stampato allineato a destra, con la larghezza specificata. Quindi:
+
+@example
+printf "%-6s", "pippo"
+@end example
+
+@noindent
+stampa @samp{pippo@bullet{}}.
+
+@item @var{spazio}
+Applicabile a conversioni numeriche, richiede di inserire uno spazio prima
+dei valori positivi e un segno meno prima di quelli negativi.
+
+@item @code{+}
+Il segno pi@`u, usato prima del modificatore di larghezza (si veda pi@`u avanti
+in questa lista),
+richiede di mettere sempre un segno nelle conversioni numeriche, anche se
+il dato da formattare ha valore positivo. Il @samp{+} prevale sul
+modificatore @dfn{spazio}.
+
+@item @code{#}
+Richiede di usare una ``forma alternativa'' per alcune lettere di controllo.
+Per @samp{%o}, preporre uno zero.
+Per @samp{%x} e @samp{%X}, preporre @samp{0x} o @samp{0X} se il
+numero @`e diverso da zero.
+Per @samp{%e}, @samp{%E}, @samp{%f}, e @samp{%F}, il risultato deve contenere
+sempre un separatore decimale.
+Per @code{%g} e @code{%G}, gli zeri finali non significativi non sono
+tolti dal numero stampato.
+
+@item @code{0}
+Uno @samp{0} (zero) iniziale serve a richiedere che l'output sia
+riempito con zeri (invece che con spazi), prima delle cifre significative.
+Questo si applica solo ai formati di output di tipo numerico.
+Questo @dfn{flag} ha un effetto solo se la larghezza del campo @`e maggiore
+di quella del valore da stampare.
+
+@item @code{'}
+Un carattere di apice singolo o un apostrofo @`e un'estensione POSIX allo
+standard ISO C.
+Indica che la parte intera di un valore a virgola mobile, o la parte intera
+di un valore decimale intero, ha un carattere di separazione delle migliaia.
+Ci@`o @`e applicabile solo alle localizzazioni che prevedono un tale carattere.
+Per esempio:
+
+@example
+$ @kbd{cat migliaia.awk} @ii{Visualizza il programma sorgente}
+@print{} BEGIN @{ printf "%'d\n", 1234567 @}
+$ @kbd{LC_ALL=C gawk -f migliaia.awk}
+@print{} 1234567 @ii{Risultato nella localizzazione} "C"
+$ @kbd{LC_ALL=en_US.UTF-8 gawk -f migliaia.awk}
+@print{} 1,234,567 @ii{Risultato nella localizzazione UTF inglese americana}
+@end example
+
+@noindent
+Per maggiori informazioni relative a localizzazioni e internazionalizzazioni,
+si veda @ref{Localizzazioni}.
+
+@quotation NOTA
+Il @dfn{flag} @samp{'} @`e una funzionalit@`a interessante, ma utilizza un
+carattere che @`e fonte di complicazioni, perch@'e risulta difficila da usare nei
+programmi scritti direttamente sulla riga di comando. Per informazioni sui
+metodi appropriati per gestire la cosa, si veda @ref{Protezione}.
+@end quotation
+
+@item @var{larghezza}
+Questo @`e un numero che specifica la larghezza minima che deve occupare un
+campo. L'inserimento di un numero tra il segno @samp{%} e il carattere
+di controllo del formato fa s@`{@dotless{i}} che il campo si espanda a quella larghezza.
+Il modo di default per fare questo @`e di aggiungere degli spazi a
+sinistra. Per esempio:
+
+@example
+printf "%6s", "pippo"
+@end example
+
+@noindent
+stampa @samp{@bullet{}pippo}.
+
+il valore di @var{larghezza} indica la larghezza minima, non la massima. Se
+il valore dell'elemento richiede pi@`u caratteri della @var{larghezza}
+specificata, questa pu@`o essere aumentata secondo necessit@`a.
+Quindi, per esempio:
+
+@example
+printf "%6s", "pippo-pluto"
+@end example
+
+@noindent
+stampa @samp{pippo-pluto}.
+
+Anteponendo un segno meno alla @var{larghezza} si richiede che l'output sia
+esteso con spazi a destra, invece che a sinistra.
+
+@item @code{.@var{precisione}}
+Un punto, seguito da una costante intera
+specifica la precisione da usare nella stampa.
+Il tipo di precisione varia a seconda della lettera di controllo:
+
+@table @asis
+@item @code{%d}, @code{%i}, @code{%o}, @code{%u}, @code{%x}, @code{%X}
+Minimo numero di cifre da stampare.
+
+@item @code{%e}, @code{%E}, @code{%f}, @code{%F}
+Numero di cifre alla destra del separatore decimale.
+
+@item @code{%g}, @code{%G}
+Massimo numero di cifre significative.
+
+@item @code{%s}
+Massimo numero di caratteri della stringa che possono essere stampati.
+@end table
+
+Quindi, l'istruzione:
+
+@example
+printf "%.4s", "foobar"
+@end example
+
+@noindent
+stampa @samp{foob}.
+@end table
+
+Le funzionalit@`a di @var{larghezza} e @var{precisione} dinamiche (cio@`e,
+@code{"%*.*s"}) disponibili nell'istruzione @code{printf} della libreria C sono
+utilizzabili.
+Invece che fornire esplicitamente una @var{larghezza} e/o una @var{precisione}
+nella stringa di formato, queste sono fornite come parte della lista degli
+argomenti. Per esempio:
+
+@example
+w = 5
+p = 3
+s = "abcdefg"
+printf "%*.*s\n", w, p, s
+@end example
+
+@noindent
+equivale esattamente a:
+
+@example
+s = "abcdefg"
+printf "%5.3s\n", s
+@end example
+
+@noindent
+Entrambi i programmi stampano @samp{@w{@bullet{}@bullet{}abc}}.
+Versioni pi@`u datate di @command{awk} non consentivano questa possibilit@`a.
+Dovendo usare una di queste versioni, @`e possibile simulare questa
+funzionalit@`a usando la concatenazione per costruire una stringa di formato,
+come per esempio:
+
+@example
+w = 5
+p = 3
+s = "abcdefg"
+printf "%" w "." p "s\n", s
+@end example
+
+@noindent
+Questo codice non @`e di facile lettura, ma funziona.
+
+@c @cindex controlli @command @{lint}
+@cindex debug, errori fatali, @code{printf}, stringhe di formato
+@cindex POSIX @command{awk}, stringhe di formato @code{printf} e
+Chi programma in C probabilmente @`e abituato a specificare modificatori
+addizionali (@samp{h}, @samp{j}, @samp{l}, @samp{L}, @samp{t} e @samp{z}) nelle
+stringhe di formato di @code{printf}. Questi modificatori non sono validi
+in @command{awk}. La maggior parte della implementazioni di @command{awk} li
+ignora senza emettere messaggi. Se si specifica l'opzione @option{--lint}
+sulla riga di comando (@pxref{Opzioni}), @command{gawk} emette un messaggio
+di avvertimento quando li si usa. Se si specifica l'opzione @option{--posix},
+il loro uso genera un errore fatale.
+
+@node Esempi su printf
+@subsection Esempi d'uso di @code{printf}
+
+Il seguente semplice esempio mostra
+come usare @code{printf} per preparare una tabella allineata:
+
+@example
+awk '@{ printf "%-10s %s\n", $1, $2 @}' mail-list
+@end example
+
+@noindent
+Questo comando
+stampa i nomi delle persone (@code{$1}) nel file
+@file{mail-list} come una stringa di 10 caratteri allineati a sinistra.
+Stampa anche i numeri telefonici (@code{$2}) a fianco, sulla stessa riga.
+Il risultato @`e una tabella allineata, contenente due colonne, di nomi e numeri
+telefonici, come si pu@`o vedere qui:
+
+@example
+$ @kbd{awk '@{ printf "%-10s %s\n", $1, $2 @}' mail-list}
+@print{} Amelia 555-5553
+@print{} Anthony 555-3412
+@print{} Becky 555-7685
+@print{} Bill 555-1675
+@print{} Broderick 555-0542
+@print{} Camilla 555-2912
+@print{} Fabius 555-1234
+@print{} Julie 555-6699
+@print{} Martin 555-6480
+@print{} Samuel 555-3430
+@print{} Jean-Paul 555-2127
+@end example
+
+In questo caso, i numeri telefonici debbono essere stampati come stringhe,
+poich@'e includono un trattino. Una stampa dei numeri telefonici come numeri
+semplici avrebbe visualizzato solo le prime tre cifre: @samp{555},
+e questo non sarebbe stato di grande utilit@`a.
+
+Non era necessario specificare una larghezza per i numeri telefonici poich@'e
+sono nell'ultima colonnna di ogni riga. Non c'@`e bisogno di avere un
+allineamento di spazi dopo di loro.
+
+La tabella avrebbe potuto essere resa pi@`u leggibile aggiungendo
+intestazioni in cima
+alle colonne. Questo si pu@`o fare usando una regola @code{BEGIN}
+(@pxref{BEGIN/END})
+in modo che le intestazioni siano stampate una sola volta, all'inizio del
+programma @command{awk}:
+
+@example
+awk 'BEGIN @{ print "Nome Numero"
+ print "---- ------" @}
+ @{ printf "%-10s %s\n", $1, $2 @}' mail-list
+@end example
+
+L'esempio precedente usa sia l'istruzione @code{print} che l'istruzione
+@code{printf} nello stesso programma. Si possono ottenere gli stessi
+risultati usando solo istruzioni @code{printf}:
+
+@example
+awk 'BEGIN @{ printf "%-10s %s\n", "Nome", "Numero"
+ printf "%-10s %s\n", "----", "------" @}
+ @{ printf "%-10s %s\n", $1, $2 @}' mail-list
+@end example
+
+@noindent
+Stampare ogni intestazione di colonna con la stessa specifica di formato
+usata per gli elementi delle colonne ci d@`a la certezza che le intestazioni
+sono allineate esattamente come le colonne.
+
+Il fatto che usiamo per tre volte la stessa specifica di formato si pu@`o
+evidenziare memorizzandola in una variabile, cos@`{@dotless{i}}:
+
+@example
+awk 'BEGIN @{ format = "%-10s %s\n"
+ printf format, "Nome", "Numero"
+ printf format, "----", "------" @}
+ @{ printf format, $1, $2 @}' mail-list
+@end example
+
+
+@node Ridirezione
+@section Ridirigere l'output di @code{print} e @code{printf}
+
+@cindex output, ridirezione
+@cindex ridirezione dell'output
+@cindex @option{--sandbox}, opzione, ridirezione dell'output con @code{print}, @code{printf}
+Finora, l'output di @code{print} e @code{printf} @`e stato diretto
+verso lo standard output,
+che di solito @`e lo schermo. Sia @code{print} che @code{printf} possono
+anche inviare il loro output in altre direzioni.
+@`E quel che si chiama @dfn{ridirezione}.
+
+@quotation NOTA
+Quando si specifica @option{--sandbox} (@pxref{Opzioni}),
+la ridirezione dell'output verso file, @dfn{pipe} e coprocessi non @`e
+consentita.
+@end quotation
+
+Una ridirezione @`e posta dopo l'istruzione @code{print} o @code{printf}.
+Le ridirezioni in @command{awk} sono scritte come le ridirezioni nei
+comandi della shell, l'unica differenza @`e che si trovano all'interno di
+un programma @command{awk}.
+
+@c the commas here are part of the see also
+@cindex istruzione @code{print}, si veda anche ridirezione dell'output
+@cindex istruzione @code{printf}, si veda anche ridirezione dell'output
+Ci sono quattro forme di ridirezione dell'output:
+output scritto su un file,
+output aggiunto in fondo a un file,
+output che fa da input a un altro comando (usando una @dfn{pipe}) e
+output diretto a un coprocesso.
+Vengono descritti per l'istruzione @code{print},
+ma funzionano allo stesso modo per @code{printf}:
+
+@table @code
+@cindex @code{>} (parentesi acuta destra), operatore @code{>} (I/O)
+@cindex parentesi acuta destra (@code{>}), operatore @code{>} (I/O)
+@cindex operatori, input/output
+@item print @var{elementi} > @var{output-file}
+Questa ridirezione stampa gli elementi nel file di output chiamato
+@var{output-file}. Il @value{FN} @var{output-file} pu@`o essere
+una qualsiasi espressione. Il suo valore @`e trasformato in una stringa e
+quindi usato come
+@iftex
+@value{FN} (@pxrefil{Espressioni}).
+@end iftex
+@ifnottex
+@value{FN} (@pxref{Espressioni}).
+@end ifnottex
+Quando si usa questo tipo di ridirezione, il file @var{output-file} viene
+cancellato prima che su di esso sia stato scritto il primo record in uscita.
+Le successive scritture verso lo stesso file @var{output-file} non cancellano
+@var{output-file}, ma continuano ad aggiungervi record.
+(Questo comportamento @`e differente da quello delle ridirezioni usate negli
+script della shell.)
+Se @var{output-file} non esiste, viene creato. Per esempio, ecco
+come un programma @command{awk} pu@`o scrivere una lista di nomi di persone
+su un file di nome @file{lista-nomi}, e una lista di numeri telefonici
+su un altro file di nome @file{lista-telefoni}:
+
+@example
+$ @kbd{awk '@{ print $2 > "lista-telefoni"}
+> @kbd{print $1 > "lista-nomi" @}' mail-list}
+$ @kbd{cat lista-telefoni}
+@print{} 555-5553
+@print{} 555-3412
+@dots{}
+$ @kbd{cat lista-nomi}
+@print{} Amelia
+@print{} Anthony
+@dots{}
+@end example
+
+@noindent
+Ogni file in output contiene un nome o un numero su ogni riga.
+
+@cindex @code{>} (parentesi acuta destra), operatore @code{>>} (I/O)
+@cindex parentesi acuta destra (@code{>}), operatore @code{>>} (I/O)
+@item print @var{elementi} >> @var{output-file}
+Questa ridirezione stampa gli elementi in un file di output preesistente,
+di nome @var{output-file}. La differenza tra questa ridirezione e quella
+con un solo @samp{>} @`e che il precedente contenuto (se esiste) di
+@var{output-file} non viene cancellato. Invece, l'output di @command{awk} @`e
+aggiunto in fondo al file.
+Se @var{output-file} non esiste, viene creato.
+
+@cindex @code{|} (barra verticale), operatore @code{|} (I/O)
+@cindex @dfn{pipe}, output
+@cindex output, a @dfn{pipe}
+@item print @var{elementi} | @var{comando}
+@`E possibile inviare output a un altro programma usando una @dfn{pipe}
+invece di inviarlo a un file. Questa ridirezione apre una @dfn{pipe} verso
+@var{comando}, e invia i valori di @var{elementi}, tramite questa
+@dfn{pipe}, a un altro processo creato per eseguire @var{comando}.
+
+L'argomento @var{comando}, verso cui @`e rivolta la ridirezione, @`e in realt@`a
+un'espressione
+@command{awk}. Il suo valore @`e convertito in una stringa il cui contenuto
+costituisce un comando della shell che deve essere eseguito. Per esempio,
+il seguente programma produce due file, una lista non ordinata di nomi di
+persone e una lista ordinata in ordine alfabetico inverso:
+
+@ignore
+10/2000:
+This isn't the best style, since COMMAND is assigned for each
+record. It's done to avoid overfull hboxes in TeX. Leave it
+alone for now and let's hope no-one notices.
+@end ignore
+
+@example
+awk '@{ print $1 > "nomi.non.ordinati"
+ comando = "sort -r > nomi.ordinati"
+ print $1 | comando @}' mail-list
+@end example
+
+La lista non ordinata @`e scritta usando una ridirezione normale, mentre
+la lista ordinata @`e scritta inviando una @dfn{pipe} in input al programma
+di utilit@`a @command{sort}.
+
+Il prossimo esempio usa la ridirezione per inviare un messaggio alla
+mailing list @code{bug-sistema}. Questo pu@`o tornare utile se si hanno
+problemi con uno script @command{awk} eseguito periodicamente per la
+manutenzione del sistema:
+
+@example
+report = "mail bug-sistema"
+print("Script awk in errore:", $0) | report
+print("al record numero", FNR, "di", NOME_FILE) | report
+close(report)
+@end example
+
+La funzione @code{close()} @`e stata chiamata perch@'e @`e una buona idea chiudere
+la @dfn{pipe} non appena tutto l'output da inviare alla @dfn{pipe} @`e stato
+inviato. @xref{Chiusura file e @dfn{pipe}}
+per maggiori informazioni.
+
+Questo esempio illustra anche l'uso di una variabile per rappresentare
+un @var{file} o un @var{comando}; non @`e necessario usare sempre
+una costante stringa. Usare una variabile @`e di solito una buona idea,
+perch@'e (se si vuole riusare lo stesso file o comando)
+@command{awk} richiede che il valore della stringa sia sempre scritto
+esattamente nello stesso modo.
+
+@cindex coprocessi
+@cindex @code{|} (barra verticale), operatore @code{|&} (I/O)
+@cindex operatori, input/output
+@cindex differenze tra @command{awk} e @command{gawk}, operatori di input/output
+@item print @var{elementi} |& @var{comando}
+Questa ridirezione stampa gli elementi nell'input di @var{comando}.
+La differenza tra questa ridirezione e quella
+con la sola @samp{|} @`e che l'output da @var{comando}
+pu@`o essere letto tramite @code{getline}.
+Quindi, @var{comando} @`e un @dfn{coprocesso}, che lavora in parallelo al
+programma @command{awk}, ma @`e al suo servizio.
+
+Questa funzionalit@`a @`e un'estensione @command{gawk}, e non @`e disponibile in
+POSIX @command{awk}.
+@ifnotdocbook
+@xref{Getline coprocesso},
+per una breve spiegazione.
+@ref{I/O bidirezionale}
+per un'esposizione pi@`u esauriente.
+@end ifnotdocbook
+@ifdocbook
+@xref{Getline coprocesso}
+per una breve spiegazione.
+@xref{I/O bidirezionale}
+per un'esposizione pi@`u esauriente.
+@end ifdocbook
+@end table
+
+Ridirigere l'output usando @samp{>}, @samp{>>}, @samp{|} o @samp{|&}
+richiede al sistema di aprire un file, una @dfn{pipe} o un coprocesso solo se
+il particolare @var{file} o @var{comando} che si @`e specificato non @`e gi@`a
+stato utilizzato in scrittura dal programma o se @`e stato chiuso
+dopo l'ultima scrittura.
+
+@cindex debug, stampare
+@`E un errore comune usare la ridirezione @samp{>} per la prima istruzione
+@code{print} verso un file, e in seguito usare @samp{>>} per le successive
+scritture in output:
+
+@example
+# inizializza il file
+print "Non v'allarmate" > "guida.txt"
+@dots{}
+# aggiungi in fondo al file
+print "Evitate generatori di improbabilit@`a" >> "guide.txt"
+@end example
+
+@noindent
+Questo @`e il modo in cui le ridirezioni devono essere usate lavorando
+con la shell. Ma in @command{awk} ci@`o non @`e necessario. In casi di questo
+genere, un programma dovrebbe
+usare @samp{>} per tutte le istruzioni @code{print}, perch@'e il file di
+output @`e aperto una sola volta.
+(Usando sia @samp{>} che @samp{>>} nello stesso programma, l'output @`e prodotto
+nell'ordine atteso.
+Tuttavia il mischiare gli operatori per lo stesso file @`e sintomo di uno
+stile di programmazione inelegante, e pu@`o causare confusione in chi legge
+il programma.)
+
+@cindex differenze tra @command{awk} e @command{gawk}, limitazioni di implementazione
+@cindex problemi di implementazione, @command{gawk}, limitazioni
+@cindex @command{awk}, problemi di implementazione, @dfn{pipe}
+@cindex @command{gawk}, problemi di implementazione, @dfn{pipe}
+@ifnotinfo
+Come visto in precedenza
+(@pxref{Note su getline}),
+molte
+@end ifnotinfo
+@ifnottex
+@ifnotdocbook
+@ifnothtml
+Molte
+@end ifnothtml
+@end ifnotdocbook
+@end ifnottex
+tra le pi@`u vecchie implementazioni di
+@command{awk} limitano il numero di @dfn{pipeline} che un programma
+@command{awk} pu@`o mantenere aperte a una soltanto! In @command{gawk}, non c'@`e
+un tale limite. @command{gawk} consente a un programma di
+aprire tante @dfn{pipeline} quante ne consente il sistema operativo su cui
+viene eseguito.
+
+@sidebar Inviare @dfn{pipe} alla @command{sh}
+@cindex shell, inviare comandi tramite @dfn{pipe} alla
+
+Una maniera particolarmente efficace di usare la ridirezione @`e quella di
+preparare righe di comando da passare
+come @dfn{pipe} alla shell,
+@command{sh}. Per esempio, si supponga di avere una lista di file provenienti
+da un sistema in cui tutti i
+@value{FNS} sono memorizzari in maiuscolo, e di volerli rinominare
+in modo da avere nomi tutti in
+minuscolo. Il seguente programma @`e
+sia semplice che efficiente:
+
+@c @cindex @command{mv} utility
+@example
+@{ printf("mv %s %s\n", $0, tolower($0)) | "sh" @}
+
+END @{ close("sh") @}
+@end example
+
+La funzione @code{tolower()} restituisce la stringa che gli viene passata
+come argomento con tutti i caratteri maiuscoli convertiti in minuscolo
+(@pxref{Funzioni per stringhe}).
+Il programma costruisce una lista di righe di comando,
+usando il programma di utilit@`a @command{mv} per rinominare i file.
+Poi invia la lista alla shell per l'elaborazione.
+
+@xref{Apici alla shell} per una funzione che pu@`o essere utile nel generare
+righe di comando da passare alla shell.
+@end sidebar
+
+@node FD speciali
+@section File speciali per flussi standard di dati pre-aperti
+@cindex standard input
+@cindex input, standard
+@cindex standard output
+@cindex output, standard
+@cindex errore, output
+@cindex standard error
+@cindex descrittori di file
+@cindex file, descrittori, si veda descrittori di file
+
+I programmi in esecuzione hanno convenzionalmente tre flussi di input e
+output a disposizione, gi@`a aperti per la lettura e la scrittura.
+Questi sono noti come
+lo @dfn{standard input}, lo @dfn{standard output} e lo @dfn{standard
+error output}. A questi flussi aperti (e a tutti gli altri file aperti o
+@dfn{pipe}) si fa spesso riferimento usando il termine tecnico
+@dfn{descrittori di file} [FD].
+
+Questi flussi sono, per default, associati alla tastiera e allo schermo,
+ma spesso sono ridiretti, nella shell, utilizzando gli operatori
+@samp{<}, @samp{<<}, @samp{>}, @samp{>>}, @samp{>&} e @samp{|}.
+Lo standard error @`e tipicamente usato per scrivere messaggi di errore;
+la ragione per cui ci sono due flussi distinti,
+standard output e standard error, @`e per poterli ridirigere indipendentemente
+l'uno dall'altro.
+
+@cindex differenze tra @command{awk} e @command{gawk}, messaggi di errore
+@cindex gestione errori
+@cindex errori, gestione degli
+Nelle tradizionali implementazioni di @command{awk}, il solo modo per
+scrivere un messaggio di errore allo
+standard error in un programma @command{awk} @`e il seguente:
+
+@example
+print "Ho trovato un errore grave!" | "cat 1>&2"
+@end example
+
+@noindent
+Con quest'istruzione si apre una @dfn{pipeline} verso un comando della shell
+che @`e in grado di accedere al flusso di standard error che eredita dal
+processo @command{awk}.
+@c 8/2014: Mike Brennan says not to cite this as inefficient. So, fixed.
+Questo @`e molto poco elegante, e richiede anche di innescare un processo
+separato. Per questo chi scrive programmi @command{awk} spesso
+non usa questo metodo. Invece, invia i messaggi di errore allo
+schermo, in questo modo:
+
+@example
+print "Ho trovato un errore grave!" > "/dev/tty"
+@end example
+
+@noindent
+(@file{/dev/tty} @`e un file speciale fornito dal sistema operativo
+ed @`e connesso alla tastiera e allo schermo. Rappresenta il
+``terminale'',@footnote{``tty'' in @file{/dev/tty} @`e un'abbreviazione di
+``TeleTYpe'' [telescrivente], un terminale seriale.} che nei sistemi odierni
+@`e una tastiera e uno schermo, e non una @dfn{console} seriale).
+Questo ha generalmente lo stesso effetto, ma non @`e sempre detto: sebbene il
+flusso di standard error sia solitamente diretto allo schermo, potrebbe
+essere stato
+ridiretto; se questo @`e il caso, scrivere verso lo schermo non serve. In
+effetti, se @command{awk} @`e chiamato da un lavoro che non @`e eseguito
+interattivamente,
+pu@`o non avere a disposizione alcun terminale su cui scrivere.
+In quel caso, l'apertura di @file{/dev/tty} genera un errore.
+
+@command{gawk}, BWK @command{awk}, e @command{mawk} mettono a disposizione
+speciali @value{FNS} per accedere ai tre flussi standard.
+Se il @value{FN} coincide con uno di questi nomi speciali, quando
+@command{gawk} (o uno degli altri) ridirige l'input o l'output, usa
+direttamente il descrittore di file identificato dal @value{FN}. Questi
+@value{FNS} sono gestiti cos@`{@dotless{i}} in tutti i sistemi operativi nei quali
+@command{gawk} @`e disponibile, e non solo in quelli che aderiscono allo
+standard POSIX:
+
+@cindex estensioni comuni, file speciale @code{/dev/stdin}
+@cindex estensioni comuni, file speciale @code{/dev/stdout}
+@cindex estensioni comuni, file speciale @code{/dev/stderr}
+@c @cindex comuni, estensioni@comma{} file speciale @code{/dev/stdin}
+@c @cindex comuni, estensioni@comma{} file speciale @code{/dev/stdout}
+@c @cindex comuni, estensioni@comma{} file speciale @code{/dev/stderr}
+@cindex nomi di file, flussi standard in @command{gawk}
+@cindex @code{/dev/@dots{}}, file speciali
+@cindex file, file speciali @code{/dev/@dots{}}
+@cindex @code{/dev/fd/@var{N}}, file speciali (in @command{gawk})
+@table @file
+@item /dev/stdin
+Lo standard input (descrittore di file 0).
+
+@item /dev/stdout
+Lo standard output (descrittore di file 1).
+
+@item /dev/stderr
+Lo standard error output (descrittore di file 2).
+@end table
+
+Usando questa funzionalit@`a
+la maniera corretta di scrivere un messaggio di errore diviene quindi:
+
+@example
+print "Ho trovato un errore grave!" > "/dev/stderr"
+@end example
+
+@cindex debug, doppio apice con nomi di file
+Si noti l'uso di doppi apici per racchiudere il @value{FN}.
+Come per ogni altra ridirezione, il valore dev'essere una stringa.
+@`E un errore comune omettere i doppi apici, il che conduce a
+risultati inattesi.
+
+@command{gawk} non tratta questi @value{FNS} come speciali quando opera
+in modalit@`a di compatibilit@`a POSIX. Comunque, poich@'e BWK @command{awk}
+li prevede, @command{gawk} li ammette anche quando viene
+invocato con l'opzione @option{--traditional} (@pxref{Opzioni}).
+
+@node File speciali
+@section @value{FFNS} speciali in @command{gawk}
+@cindex @command{gawk}, nomi di file in
+
+Oltre all'accesso a standard input, standard output e standard error,
+@command{gawk} consente di accedere a ogni descrittore di file aperto.
+In pi@`u, ci sono dei @value{FNS} speciali riservati per accedere a
+reti TCP/IP.
+
+@menu
+* Altri file ereditati:: Accedere ad altri file aperti con
+ @command{gawk}.
+* Reti speciali:: File speciali per comunicazioni con la rete.
+* Avvertimenti speciali:: Cose a cui prestare attenzione.
+@end menu
+
+@node Altri file ereditati
+@subsection Accedere ad altri file aperti con @command{gawk}
+
+Oltre ai valori speciali di @value{FNS}
+@code{/dev/stdin}, @code{/dev/stdout} e @code{/dev/stderr}
+gi@`a menzionati, @command{gawk} prevede una sintassi
+per accedere a ogni altro file aperto ereditato:
+
+@table @file
+@item /dev/fd/@var{N}
+Il file associato al descrittore di file @var{N}. Il file indicato deve
+essere aperto dal programma che inizia l'esecuzione di @command{awk}
+(tipicamente la shell). Se non sono state poste in essere iniziative
+speciali nella shell da cui @command{gawk} @`e stato invocato, solo i
+descrittori 0, 1, e 2 sono disponibili.
+@end table
+
+I @value{FNS} @file{/dev/stdin}, @file{/dev/stdout} e @file{/dev/stderr}
+sono essenzialmente alias per @file{/dev/fd/0}, @file{/dev/fd/1} e
+@file{/dev/fd/2}, rispettivamente. Comunque, i primi nomi sono pi@`u
+autoesplicativi.
+
+Si noti che l'uso di @code{close()} su un @value{FN} della forma
+@code{"/dev/fd/@var{N}"}, per numeri di descrittore di file
+oltre il due, effettivamente chiude il descrittore di file specificato.
+
+@node Reti speciali
+@subsection File speciali per comunicazioni con la rete
+@cindex reti, funzionalit@`a per
+@cindex TCP/IP, funzionalit@`a per
+
+I programmi @command{gawk}
+possono aprire una connessione bidirezionale
+TCP/IP, fungendo o da @dfn{client} o da @dfn{server}.
+Questo avviene usando uno speciale @value{FN} della forma:
+
+@example
+@file{/@var{tipo-rete}/@var{protocollo}/@var{porta-locale}/@var{host-remoto}/@var{porta-remota}}
+@end example
+
+il @var{tipo-rete} pu@`o essere @samp{inet}, @samp{inet4} o @samp{inet6}.
+Il @var{protocollo} pu@`o essere @samp{tcp} o @samp{udp},
+e gli altri campi rappresentano gli altri dati essenziali
+necessari per realizzare una connessione di rete.
+Questi @value{FNS} sono usati con l'operatore @samp{|&} per comunicare
+con un coprocesso
+(@pxref{I/O bidirezionale}).
+Questa @`e una funzionalit@`a avanzata, qui riferita solo per completezza.
+Una spiegazione esauriente sar@`a fornita nella
+@ref{Reti TCP/IP}.
+
+@node Avvertimenti speciali
+@subsection Avvertimenti speciali sui @value{FNS}
+
+Sono qui elencate alcune cose da tener presente usando i
+@value{FNS} speciali forniti da @command{gawk}:
+
+@itemize @value{BULLET}
+@cindex modalit@`a compatibile di (@command{gawk}), nomi di file
+@cindex nomi di file, nella modalit@`a compatibile di @command{gawk}
+@item
+Il riconoscimento dei @value{FNS} per i tre file standard pre-aperti
+@`e disabilitato solo in modalit@`a POSIX.
+
+@item
+Il riconoscimento degli altri @value{FNS} speciali @`e disabilitato se
+@command{gawk} @`e in modalit@`a compatibile
+(o @option{--traditional} o @option{--posix};
+@pxref{Opzioni}).
+
+@item
+@command{gawk} interpreta @emph{sempre}
+questi @value{FNS} speciali.
+Per esempio, se si usa @samp{/dev/fd/4}
+per l'output, si scrive realmente sul descrittore di file 4, e non su un nuovo
+descrittore di file generato duplicando (con @code{dup()}) il descrittore
+file 4. Solitamente questo non ha importanza; comunque, @`e importante
+@emph{non} chiudere alcun file correlato ai descrittori di file 0, 1 e 2.
+Se lo si fa, il comportamente risultante @`e imprevedibile.
+@end itemize
+
+@node Chiusura file e @dfn{pipe}
+@section Chiudere ridirezioni in input e in output
+@cindex output, file in, si veda file in output
+@cindex input, file in, chiusura
+@cindex output, file in, chiusura
+@cindex @dfn{pipe}, chiusura
+@cindex coprocessi, chiusura
+@cindex @code{getline}, comando, coprocessi@comma{} usare dal
+
+Se lo stesso @value{FN} o lo stesso comando di shell @`e usato con @code{getline}
+pi@`u di una volta durante l'esecuzione di un programma @command{awk}
+(@pxref{Getline}),
+il file viene aperto (o il comando viene eseguito) solo la prima volta.
+A quel punto, il primo record in input @`e letto da quel file o comando.
+La prossima volta che lo stesso file o comando @`e usato con @code{getline},
+un altro record @`e letto da esso, e cos@`{@dotless{i}} via.
+
+Analogamente, quando un file o una @dfn{pipe} sono aperti in output,
+@command{awk} ricorda
+il @value{FN} o comando a essi associato, e le successive
+scritture verso lo stesso file o comando sono accodate alle precedenti
+scritture.
+Il file o la @dfn{pipe} rimangono aperti fino al termine dell'esecuzione
+di @command{awk}.
+
+@cindexawkfunc{close}
+Questo implica che sono necessari dei passi speciali per rileggere nuovamente
+lo stesso file dall'inizio, o per eseguire di nuovo un comando di shell
+(invece che leggere ulteriore output dal precedente comando). La funzione
+@code{close()} rende possibile fare queste cose:
+
+@example
+close(@var{NOME_FILE})
+@end example
+
+@noindent
+o:
+
+@example
+close(@var{comando})
+@end example
+
+l'argomento @var{NOME_FILE} o @var{comando} pu@`o essere qualsiasi espressione,
+il cui valore dev'essere @emph{esattamente} uguale alla stringa
+usata per aprire il file o eseguire il comando (spazi e altri caratteri
+``irrilevanti'' inclusi). Per esempio, se si apre una @dfn{pipe} cos@`{@dotless{i}}:
+
+@example
+"sort -r nomi" | getline pippo
+@end example
+
+@noindent
+essa va chiusa in questo modo:
+
+@example
+close("sort -r nomi")
+@end example
+
+Una volta eseguita questa chiamata di funzione, la successiva @code{getline}
+da quel file o comando, o la successiva @code{print} o @code{printf} verso quel
+file o comando, riaprono il file o eseguono nuovamente il comando.
+Poich@'e l'espressione da usare per chiudere un file o una @dfn{pipeline} deve
+essere uguale all'espressione usata per aprire il file o eseguire il comando,
+@`e buona norma usare una variabile che contenga il @value{FN} o il comando.
+Il precedente esempio cambia come segue:
+
+@example
+sortcom = "sort -r nomi"
+sortcom | getline pippo
+@dots{}
+close(sortcom)
+@end example
+
+@noindent
+Questo aiuta a evitare nei programmi @command{awk} errori di battitura
+difficili da scoprire. Queste sono alcune delle ragioni per cui @`e bene
+chiudere un file di output:
+
+@itemize @value{BULLET}
+@item
+Scrivere un file e rileggerlo in seguito all'interno dello stesso programma
+@command{awk}. Occorre chiudere il file dopo aver finito di scriverlo, e poi
+iniziare a rileggerlo con @code{getline}.
+
+@item
+Per scrivere numerosi file, uno dopo l'altro, nello stesso programma
+@command{awk}. Se i file non vengono chiusi, prima o poi @command{awk} pu@`o
+superare il limite di sistema per il numero di file aperti in un processo.
+@`E meglio chiudere ogni file quando il programma ha finito di scriverlo.
+
+@item
+Per terminare un comando. Quando l'output @`e ridiretto usando una @dfn{pipe},
+il comando che legge la @dfn{pipe} normalmente continua a tentare di leggere
+input finch@'e la @dfn{pipe} rimane aperta. Spesso questo vuol dire che
+il comando non pu@`o eseguire il compito a lui assegnato finch@'e la @dfn{pipe}
+non viene chiusa. Per esempio, se l'output @`e ridiretto al programma
+@command{mail}, il messaggio non @`e effettivamente inviato finch@'e la @dfn{pipe}
+non viene chiusa.
+
+@item
+Eseguire lo stesso programma una seconda volta, con gli stessi argomenti.
+Questo non equivale a fornire ulteriore input alla prima esecuzione!
+
+Per esempio, si supponga che una programma invii tramite una @dfn{pipe}
+dell'output al programma @command{mail}.
+Se invia parecchie linee ridirigendole a questa @dfn{pipe} senza chiuderla,
+queste costituiscono un solo messaggio di parecchie righe. Invece, se il
+programma chiude la @dfn{pipe} dopo ogni riga dell'output, allora ogni riga
+costituisce un messaggio separato.
+@end itemize
+
+@cindex differenze tra @command{awk} e @command{gawk}, funzione @code{close()}
+@cindex portabilit@`a, funzione @code{close()}
+@cindex funzione @code{close()}, portabilit@`a
+@cindex @code{close()}, funzione, portabilit@`a
+Se si usano file in numero superiore a quelli che il sistema permette
+di mantenere aperti,
+@command{gawk} tenta di riutilizzare i file aperti disponibili fra
+i @value{DF}. La possibilit@`a che @command{gawk} lo faccia dipende dalle
+funzionalit@`a del sistema operativo, e quindi non @`e detto che questo riesca
+sempre. @`E quindi sia una buona pratica
+che un buon suggerimento per la portabilit@`a quello di usare sempre
+@code{close()} sui file, una volta che si @`e finito di operare su di essi.
+In effetti, se si usano molte @dfn{pipe}, @`e fondamentale che i comandi
+vengano chiusi, una volta finita la loro elaborazione. Per esempio, si
+consideri qualcosa del tipo:
+
+@example
+@{
+ @dots{}
+ comando = ("grep " $1 " /qualche/file | un_mio_programma -q " $3)
+ while ((comando | getline) > 0) @{
+ @var{elabora output di} comando
+ @}
+ # qui serve close(comando)
+@}
+@end example
+
+Questo esempio crea una nuova @dfn{pipeline} a seconda dei dati contenuti in
+@emph{ogni} record.
+Senza la chiamata a @code{close()} indicata come commento, @command{awk}
+genera processi-figlio per eseguire i comandi, fino a che non finisce per
+esaurire i descrittori di file
+necessari per creare ulteriori @dfn{pipeline}.
+
+Sebbene ogni comando sia stato completato (come si deduce dal codice di
+fine-file restituito dalla @code{getline}), il processo-figlio non @`e
+terminato;@footnote{La terminologia tecnica @`e piuttosto macabra.
+Il processo-figlio terminato @`e chiamato ``zombie,'' e la pulizia alla fine
+dello stesso @`e chiamata ``reaping'' [mietitura].}
+@c Good old UNIX: give the marketing guys fits, that's the ticket
+inoltre, e questo @`e ci@`o che pi@`u ci interessa, il descrittore di file
+per la @dfn{pipe} non @`e chiuso e liberato finch@'e non si chiama
+@code{close()} o finch@'e il programma @command{awk} non termina.
+
+@code{close()} non fa nulla (e non emette messaggi) se le viene fornito come
+argomento una stringa che non rappresenta un file, una @dfn{pipe} o un
+coprocesso che sia stato aperto mediante una ridirezione. In quel caso,
+@code{close()} restituisce un valore di ritorno negativo, che indica un
+errore. Inoltre, @command{gawk} imposta @code{ERRNO}
+a una stringa che indica il tipo di errore.
+
+Si noti anche che @samp{close(NOME_FILE)} non ha effetti ``magici'' sul ciclo
+implicito che legge ogni record dei file indicati nella riga di comando.
+Si tratta, con ogni probabilit@`a, della chiusura di un file che non era mai
+stato aperto con una ridirezione,
+e per questo @command{awk} silenziosamente non fa nulla, tranne impostare un
+codice di ritorno negativo.
+
+@cindex @code{|} (barra verticale), operatore @code{|&} (I/O), @dfn{pipe}@comma{} chiusura
+Quando si usa l'operatore @samp{|&} per comunicare con un coprocesso,
+@`e talora utile essere in grado di chiudere un lato della @dfn{pipe}
+bidirezionale, senza chiudere l'altro lato.
+Questo @`e possibile fornendo un secondo argomento a @code{close()}.
+Come in ogni altra invocazione di @code{close()},
+il primo argomento @`e il nome del comando o file speciale usato
+per iniziare il coprocesso.
+Il secondo argomento dovrebbe essere una stringa, con uno dei due valori
+@code{"to"} [a] oppure @code{"from"} [da]. Maiuscolo/minuscolo non fa
+differenza. Poich@'e questa @`e una funzionalit@`a avanzata, la trattazione @`e
+rinviata alla
+@ref{I/O bidirezionale},
+che ne parla pi@`u dettagliatamente e fornisce un esempio.
+
+@sidebar Usare il valore di ritorno di @code{close()}
+@cindex angolo buio, funzione @code{close()}
+@cindex funzione @code{close()}, valore di ritorno
+@cindex @code{close()}, funzione, valore di ritorno
+@cindex valore di ritorno@comma{} funzione @code{close()}
+@cindex differenze tra @command{awk} e @command{gawk}, funzione @code{close()}
+@cindex Unix @command{awk}, funzione @code{close()} e
+
+In molte versioni di Unix @command{awk}, la funzione @code{close()}
+@`e in realt@`a un'istruzione.
+@value{DARKCORNER}
+@`E un errore di sintassi tentare di usare il valore
+di ritorno da @code{close()}:
+
+@example
+comando = "@dots{}"
+comando | getline info
+retval = close(comando) # errore di sintassi in parecchi Unix awk
+@end example
+
+@cindex @command{gawk}, variabile @code{ERRNO} in
+@cindex variabile @code{ERRNO}, con funzione @command{close()}
+@cindex @code{ERRNO}, variabile, con funzione @command{close()}
+@command{gawk} gestisce @code{close()} come una funzione.
+Il valore di ritorno @`e @minus{}1 se l'argomento designa un file
+che non era mai stato aperto con una ridirezione, o se c'@`e un problema di
+sistema nella chiusura del file o del processo.
+In tal caso, @command{gawk} imposta la variabile predefinita
+@code{ERRNO} a una stringa che descrive il problema.
+
+In @command{gawk}, a partire dalla @value{PVERSION} 4.2,
+quando si chiude una @dfn{pipe} o un coprocesso (in input o in output),
+il valore di ritorno @`e quello restituito dal comando,
+come descritto in @ref{table-close-pipe-return-values}.@footnote{Prima
+della @value{PVERSION} 4.2, il valore di ritorno dopo la chiusura di
+una @dfn{pipe} o di un coprocesso era una cifra di due byte (16-bit),
+contenente il valore restituito dalla chiamata di sistema @code{wait()}}.
+Altrimenti, @`e il valore di ritorno dalla chiamata alle funzione
+di sistema @code{close()} o alla funzione C @code{fclose()}
+se si sta chiudendo un file in input o in output, rispettivamente.
+Questo valore @`e zero se la chiusura riesce, o @minus{}1 se non riesce.
+
+@float Tabella,table-close-pipe-return-values
+@caption{Valori di ritorno dalla @code{close()} di una @dfn{pipe}}
+@multitable @columnfractions .50 .50
+@headitem Situazione @tab Valore restituito da @code{close()}
+@item Uscita normale dal comando @tab Il codice di ritorno del comando
+@item Uscita dal comando per @dfn{signal} @tab 256 + numero del segnale assassino
+@item Uscita dal comando per @dfn{signal} con @dfn{dump} @tab 512 + numero del segnale assassino
+@item Errore di qualsiasi tipo @tab @minus{}1
+@end multitable
+@end float
+
+Lo standard POSIX @`e molto generico; dice che @code{close()}
+restituisce zero se @`e terminata correttamente, e un valore diverso da zero
+nell'altro caso. In generale,
+implementazioni differenti variano in quel che restituiscono chiudendo una
+@dfn{pipe}; quindi, il valore di ritorno non pu@`o essere usato in modo
+portabile.
+@value{DARKCORNER}
+In modalit@`a POSIX (@pxref{Opzioni}), @command{gawk} restituisce solo zero
+quando chiude una @dfn{pipe}.
+@end sidebar
+
+@node Continuazione dopo errori
+@section Abilitare continuazione dopo errori in output
+
+Questa @value{SECTION} descrive una funzionalit@`a specifica di @command{gawk}.
+
+In @command{awk} standard, l'output con @code{print} o @code{printf}
+a un file che non esiste, o qualche altro errore di I/O (come p.es.
+esaurire lo spazio disponibile su disco) @`e un errore fatale (termina
+l'esecuzione del programma).
+
+@example
+$ @kbd{gawk 'BEGIN @{ print "ciao" > "/file/non/esistente" @}'}
+@error{} gawk: riga com.:1: fatale: non riesco a ri-dirigere a
+@error{} `/file/non/esistente' (/file o directory non esistente)
+@end example
+
+@command{gawk} rende possibile accorgersi che c'@`e stato un errore,
+permettendo di tentare di rimediare, o almeno di stampare un messaggio
+di errore prima di terminare il programma.
+@`E possibile fare questo in due modi differenti:
+
+@itemize @bullet
+@item
+Per tutti i file in output, assegnando un valore qualsiasi a
+@code{PROCINFO["NONFATAL"]}.
+
+@item
+Specificamente per un solo file, assegnando un valore qualsiasi a
+@code{PROCINFO[@var{nome_file}, "NONFATAL"]}.
+@var{nome_file} @`e il nome del file per il quale
+si desidera che l'errore di output non faccia terminare il programma.
+@end itemize
+
+Una volta abilitata la continuazione dopo un errore di output, si dovr@`a
+controllare la variabile @code{ERRNO} dopo ogni istruzione
+@code{print} o @code{printf} diretta a quel file, per controllare che
+tutto sia andato a buon fine. @`E anche una buona idea inizializzare
+@code{ERRNO} a zero prima di tentare l'operazione di scrittura.
+Per esempio:
+
+@example
+$ @kbd{gawk '}
+> @kbd{BEGIN @{}
+> @kbd{ PROCINFO["NONFATAL"] = 1}
+> @kbd{ ERRNO = 0}
+> @kbd{ print "ciao" > "/file/non/esistente"}
+> @kbd{ if (ERRNO) @{}
+> @kbd{ print("Output non riuscito:", ERRNO) > "/dev/stderr"}
+> @kbd{ exit 1}
+> @kbd{ @}}
+> @kbd{@}'}
+@error{} Output non riuscito: No such file or directory
+@end example
+
+@command{gawk} non genera un errore fatale; permette invece
+al programma @command{awk} di rendersi conto del problema e di gestirlo.
+
+Questo meccanismo si applica anche allo standard output e allo standard error.
+Per lo standard output, si pu@`o usare @code{PROCINFO["-", "NONFATAL"]}
+o @code{PROCINFO["/dev/stdout", "NONFATAL"]}.
+Per lo standard error, occorre
+usare @code{PROCINFO["/dev/stderr", "NONFATAL"]}.
+
+Se si tenta di aprire un @dfn{socket} TCP/IP (@pxref{Reti TCP/IP}),
+@command{gawk} tenta di farlo per un certo numero di volte.
+La variabile d'ambiente @env{GAWK_SOCK_RETRIES}
+(@pxref{Altre variabili d'ambiente}) consente di alterare il numero di
+tentativi che @command{gawk} farebbe per default. Tuttavia,
+una volta abilitata la continuazione dopo un errore di I/O per un certo
+@dfn{socket}, @command{gawk} si limita a un solo tentativo,
+lasciando al codice del programma @command{awk} il compito di gestire
+l'eventuale problema.
+
+@node Sommario di Output
+@section Sommario.
+
+@itemize @value{BULLET}
+@item
+L'istruzione @code{print} stampa una lista di espressioni separate da virgole.
+Le espressioni sono separate tra loro dal valore di @code{OFS} e completate
+dal valore di @code{ORS}. @code{OFMT} fornisce il formato di conversione
+dei valori numerici per l'istruzione @code{print}.
+
+@item
+L'istruzione @code{printf} fornisce un controllo pi@`u preciso sull'output,
+con lettere di controllo del formato per diversi tipi di dati e vari
+modificatori
+che cambiano il comportamento delle lettere di controllo del formato.
+
+@item
+L'output sia di @code{print} che di @code{printf} pu@`o essere ridiretto a
+file, @dfn{pipe}, e coprocessi.
+
+@item
+@command{gawk} fornisce @value{FNS} speciali per accedere allo
+standard input, standard output e standard error, e per comunicazioni di rete.
+
+@item
+Usare @code{close()} per chiudere file aperti, @dfn{pipe} e ridirezioni a
+coprocessi.
+Per i coprocessi, @`e possibile chiudere anche soltanto una delle due
+direzioni di comunicazione.
+
+@item
+Normalmente se si verificano errori eseguendo istruzioni @code{print} o
+@code{printf}, questi causano la fine del programma.
+@command{gawk} consente di proseguire l'elaborazione anche in questo
+caso, o per un errore su qualsiasi file in output, o per un errore
+relativo a qualche file in particolare.
+Resta a carico del programma controllare se si sono verificati errori
+dopo l'esecuzione di ogni istruzione di output interessata.
+
+@end itemize
+
+@c EXCLUDE START
+@node Esercizi su Output
+@section Esercizi
+
+@enumerate
+@item
+Riscrivere il programma:
+
+@example
+awk 'BEGIN @{ print "Mese Contenitori"
+ print "----- -----------" @}
+ @{ print $1, $2 @}' inventory-shipped
+@end example
+
+@noindent
+come
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Separatori di output}, usando un nuovo valore per @code{OFS}.
+
+@item
+Usare l'istruzione @code{printf} per allineare le intestazioni e i dati
+della tabella
+per il file di esempio @file{inventory-shipped} utilizzato nella @ref{Print}.
+
+@item
+Spiegare cosa succede se si dimenticano i doppi apici ridirigendo l'output,
+come nel caso che segue:
+
+@example
+BEGIN @{ print "Ho trovato un errore grave!" > /dev/stderr @}
+@end example
+
+@end enumerate
+@c EXCLUDE END
+
+
+@node Espressioni
+@chapter Espressioni
+@cindex espressioni
+
+Le espressioni sono i mattoni fondamentali dei modelli di ricerca e delle
+azioni di @command{awk}. Un'espressione genera un valore che si
+pu@`o stampare, verificare o passare a una funzione. Oltre a ci@`o, un'espressione
+pu@`o assegnare un nuovo valore a una variabile o a un campo usando un operatore
+di assegnamento.
+
+Un'espressione pu@`o servire come modello di ricerca o istruzione di azione a
+s@'e stante. La maggior parte degli altri tipi di istruzione contengono una o
+pi@`u espressioni che specificano i dati sui quali operare. Come in altri
+linguaggi, le espressioni in @command{awk} possono includere variabili,
+riferimenti a vettori e a costanti, e chiamate di funzione, come pure
+combinazioni tra questi usando diversi operatori.
+
+@menu
+* Valori:: Costanti, variabili ed espressioni regolari.
+* Tutti gli operatori:: Gli operatori di @command{gawk}.
+* Valori e condizioni di verit@`a:: Determinare Vero/Falso.
+* Chiamate di funzione:: Una chiamata di funzione pu@`o essere
+ un'espressione.
+* Precedenza:: Come si nidificano i vari operatori.
+* Localizzazioni:: Come la localizzazione influenza la
+ gestione dati.
+* Sommario delle espressioni:: Sommario delle espressioni.
+@end menu
+
+@node Valori
+@section Costanti, variabili e conversioni
+
+Le espressioni sono costruite a partire da valori e dalle operazioni eseguite
+su di essi. Questa @value{SECTION} descrive gli oggetti elementari
+che forniscono i valori usati nelle espressioni.
+
+@menu
+* Costanti:: Costanti di tipo stringa, numeriche ed
+ espressioni regolari
+* Usare le costanti @dfn{regexp}:: Quando e come usare una costante
+ specificata tramite espressioni regolari
+* Variabili:: Le variabili permettono di
+ definire valori da usare in seguito.
+* Conversione:: La conversione di stringhe in numeri
+ e viceversa.
+@end menu
+
+@node Costanti
+@subsection Espressioni costanti
+
+@cindex costanti, tipi di
+
+Il tipo di espressione pi@`u semplice @`e una @dfn{costante}, che ha sempre lo
+stesso valore. Ci sono tre tipi di costanti: numeriche, di stringa e di
+espressione regolare.
+
+Ognuna di esse si usa nel contesto appropriato quando occorre assegnare ai
+dati un valore che non dovr@`a essere cambiato. Le costanti numeriche possono
+avere forme diverse, ma sono memorizzate internamente sempre allo stesso modo.
+
+@menu
+* Costanti scalari:: Costanti numeriche e stringhe.
+* Numeri non-decimali:: Cosa sono i numeri ottali ed esadecimali.
+* Costanti come espressioni regolari:: Costanti fornite tramite espressioni
+ regolari.
+@end menu
+
+@node Costanti scalari
+@subsubsection Costanti numeriche e stringhe
+
+@cindex costanti numeriche
+@cindex numeriche, costanti
+Una @dfn{costante numerica} @`e un numero. Questo numero pu@`o essere un
+numero intero, una frazione decimale o un numero in notazione scientifica
+(esponenziale).@footnote{La rappresentazione interna di tutti i numeri,
+compresi gli interi, usa numeri in virgola mobile a doppia precisione.
+Sui sistemi pi@`u moderni, questi sono nel formato standard IEEE 754.
+@xref{Calcolo con precisione arbitraria}, per maggiori informazioni.}
+Ecco alcuni esempi di costanti numeriche che hanno tutte lo stesso
+valore:
+
+@example
+105
+1.05e+2
+1050e-1
+@end example
+
+@cindex costanti stringa
+Una @dfn{costante stringa} @`e formata da una sequenza di caratteri racchiusi tra
+doppi apici. Per esempio:
+
+@example
+"pappagallo"
+@end example
+
+@noindent
+@cindex differenze tra @command{awk} e @command{gawk}, stringhe
+@cindex stringhe, limitazioni della lunghezza
+rappresenta la stringa il cui contenuto @`e la parola @samp{pappagallo}.
+Le stringhe in
+@command{gawk} possono essere di qualsiasi lunghezza, e possono contenere
+tutti i possibili caratteri ASCII a otto bit, compreso il carattere ASCII
+@sc{nul} (carattere con codice zero).
+Altre implementazioni di @command{awk} possono avere difficolt@`a con alcuni
+particolari codici di carattere.
+
+@node Numeri non-decimali
+@subsubsection Numeri ottali ed esadecimali
+@cindex ottali, numeri
+@cindex esadecimali, numeri
+@cindex numeri ottali
+@cindex numeri esadecimali
+
+In @command{awk}, tutti i numeri sono espressi nel sistema decimale (cio@`e a
+base 10).
+Molti altri linguaggi di programmazione consentono di specificare i numeri in
+altre basi, spesso in ottale (base 8) e in esadecimale (base 16).
+Nel sistema ottale i numeri hanno la sequenza 0, 1, 2, 3, 4, 5, 6, 7, 10, 11,
+12, e cos@`{@dotless{i}} via. Come @samp{11} decimale @`e una volta 10 pi@`u 1, cos@`{@dotless{i}}
+@samp{11} ottale @`e una volta 8 pi@`u 1. Questo equivale a 9 nel sistema decimale.
+Nell'esadecimale ci sono 16 cifre. Poich@'e l'usuale sistema numerico decimale
+ha solo dieci cifre (@samp{0}--@samp{9}), le lettere da
+@samp{a} a @samp{f} rappresentano le cifre ulteriori.
+(normalmente @`e irrilevante se le lettere sono maiuscole o minuscole; gli
+esadecimali @samp{a} e @samp{A} hanno lo stesso valore).
+Cos@`{@dotless{i}}, @samp{11} esadecimale @`e 1 volta 16 pi@`u 1,
+il che equivale a 17 decimale.
+
+Guardando solamente un @samp{11} puro e semplice, non si capisce in quale base
+sia. Cos@`{@dotless{i}}, in C, C++, e in altri linguaggi derivati da C,
+@c such as PERL, but we won't mention that....
+c'@`e una speciale notazione per esprimere la base.
+I numeri ottali iniziano con uno @samp{0},
+e i numeri esadecimali iniziano con uno @samp{0x} o @samp{0X}:
+
+@table @code
+@item 11
+Valore decimale 11
+
+@item 011
+11 ottale, valore decimale 9
+
+@item 0x11
+11 esadecimale, valore decimale 17
+@end table
+
+Quest'esempio mostra le differenze:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "%d, %d, %d\n", 011, 11, 0x11 @}'}
+@print{} 9, 11, 17
+@end example
+
+Poter usare costanti ottali ed esadecimali nei propri programmi @`e molto utile
+quando si lavora con dati che non possono essere rappresentati
+convenientemente come caratteri o come numeri regolari, come i dati binari di
+vario tipo.
+
+@cindex @command{gawk}, numeri ottali e
+@cindex @command{gawk}, numeri esadecimali e
+@command{gawk} permette l'uso di costanti ottali ed esadecimali nel testo di
+un programma. Comunque, se numeri non-decimali sono presenti tra i dati in
+input, essi non sono trattati in maniera speciale; trattarli in modo speciale
+per default significherebbe che vecchi programmi @command{awk} produrrebbero
+risultati errati.
+(Se si vuole che i numeri siano trattati in maniera speciale, si deve
+specificare l'opzione da riga di comando
+@option{--non-decimal-data};
+@pxref{Dati non decimali}.)
+Se si devono gestire dati ottali o esadecimali,
+si pu@`o usare la funzione @code{strtonum()}
+(@pxref{Funzioni per stringhe})
+per convertire i dati in numeri.
+La maggior parte delle volte, le costanti ottali o esadecimali si usano quando
+si lavora con le funzioni predefinite di manipolazione di bit;
+si veda @ref{Funzioni a livello di bit}
+per maggiori informazioni.
+
+Diversamente da alcune tra le prime implementazioni di C, @samp{8} e @samp{9}
+non sono cifre valide nelle costanti ottali. Per esempio, @command{gawk}
+tratta @samp{018} come un 18 decimale:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print "021 @`e", 021 ; print 018 @}'}
+@print{} 021 @`e 17
+@print{} 18
+@end example
+
+@cindex modalit@`a compatibile di (@command{gawk}), numeri ottali
+@cindex numeri ottali nella modalit@`a compatibile di (@command{gawk})
+@cindex modalit@`a compatibile di (@command{gawk}), numeri esadecimali
+@cindex numeri esadecimali nella modalit@`a compatibile di (@command{gawk})
+@cindex compatibile, modalit@`a (@command{gawk}), numeri ottali
+@cindex compatibile, modalit@`a (@command{gawk}), numeri esadecimali
+Le costanti ottali ed esadecimali nel codice sorgente sono un'estensione di
+@command{gawk}. Se @command{gawk} @`e in modalit@`a compatibile
+(@pxref{Opzioni}),
+non sono disponibili.
+
+@sidebar La base di una costante non influisce sul suo valore
+
+Una volta che una costante numerica @`e stata
+convertita internamente in un numero [decimale],
+@command{gawk} non considera pi@`u
+la forma originale della costante; viene sempre usato il valore
+interno. Questo ha delle precise conseguenze per la conversione dei
+numeri in stringhe:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "0x11 vale <%s>\n", 0x11 @}'}
+@print{} 0x11 vale <17>
+@end example
+@end sidebar
+
+@node Costanti come espressioni regolari
+@subsubsection Costanti fornite tramite espressioni regolari
+
+@cindex @dfn{regexp}, costanti
+@cindex costanti @dfn{regexp}
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+Una @dfn{costante regexp} @`e la descrizione di un'espressione regolare
+delimitata
+da barre, come @code{@w{/^inizio e fine$/}}. La maggior parte delle
+@dfn{regexp} usate nei programmi @command{awk} sono costanti, ma gli operatori
+di confronto @samp{~} e @samp{!~} possono confrontare anche @dfn{regexp}
+calcolate o dinamiche (che tipicamente sono solo stringhe ordinarie o
+variabili che contengono un'espressione regolare, ma potrebbero anche essere
+espressioni pi@`u complesse).
+
+@node Usare le costanti @dfn{regexp}
+@subsection Usare espressioni regolari come costanti
+
+Le costanti @dfn{regexp} sono costituite da testo che descrive un'espressione
+regolare, racchiusa fra barre (come p.e. @code{/la +risposta/}).
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} tratta del comportamento di tali costanti in
+POSIX @command{awk} e in @command{gawk}, e prosegue descrivendo le
+@dfn{costanti @dfn{regexp} fortemente tipizzate}, che sono
+un'estensione @command{gawk}.
+
+@menu
+* Costanti @dfn{regexp} normali:: Costanti @dfn{regexp} normali in
+ @command{awk}.
+* Costanti @dfn{regexp} forti:: Costanti @dfn{regexp} fortemente tipizzate.
+@end menu
+
+@node Costanti @dfn{regexp} normali
+@subsubsection Costanti @dfn{regexp} normali in @command{awk}.
+
+@cindex angolo buio, costanti @dfn{regexp}
+Quand'@`e usata a destra degli operatori @samp{~} o @samp{!~},
+una costante @dfn{regexp} rappresenta semplicemente l'espressione regolare che
+dev'essere confrontata. Comunque, le costanti @dfn{regexp} (come @code{/pippo/})
+possono essere usate come semplici espressioni.
+Quando una
+costante @dfn{regexp} compare da sola, ha lo stesso significato di quando
+compare in un criterio di ricerca (cio@`e @samp{($0 ~ /pippo/)}).
+@value{DARKCORNER}
+@xref{Espressioni come criteri di ricerca}.
+Ci@`o vuol dire che i due frammenti di codice seguenti:
+
+@example
+if ($0 ~ /barfly/ || $0 ~ /camelot/)
+ print "trovato"
+@end example
+
+@noindent
+e:
+
+@example
+if (/barfly/ || /camelot/)
+ print "trovato"
+@end example
+
+@noindent
+sono esattamente equivalenti.
+Una conseguenza piuttosto bizzarra di questa regola @`e che la seguente
+espressione booleana @`e valida, ma non fa quel che probabilmente l'autore
+si aspettava:
+
+@example
+# Notare che /pippo/ @`e alla @emph{sinistra} della ~
+if (/pippo/ ~ $1) print "trovato pippo"
+@end example
+
+@c @cindex automatic warnings
+@c @cindex warnings, automatic
+@cindex @command{gawk}, costanti @dfn{regexp} e
+@cindex costanti @dfn{regexp}, in @command{gawk}
+@noindent
+Questo codice ``ovviamente'' intende verificare se @code{$1} contiene
+l'espressione regolare @code{/pippo/}. Ma in effetti l'espressione
+@samp{/pippo/ ~ $1} significa realmente @samp{($0 ~ /pippo/) ~ $1}. In altre
+parole, prima confronta il record in input con l'espressione regolare
+@code{/pippo/}. Il risultato @`e zero o uno, a seconda che il confronto dia esito
+positivo o negativo. Questo risultato
+@`e poi confrontato col primo campo nel record.
+Siccome @`e improbabile che qualcuno voglia mai fare realmente questo genere di
+test, @command{gawk} emette un avvertimento quando vede questo costrutto in
+un programma.
+Un'altra conseguenza di questa regola @`e che l'istruzione di assegnamento:
+
+@example
+confronta = /pippo/
+@end example
+
+@noindent
+assegna zero o uno alla variabile @code{confronta}, a seconda
+del contenuto del record in input corrente.
+
+@cindex differenze tra @command{awk} e @command{gawk}, costanti @dfn{regexp}
+@cindex angolo buio, costanti @dfn{regexp}, come argomenti a funzioni definite dall'utente
+@cindexgawkfunc{gensub}
+@cindexawkfunc{sub}
+@cindexawkfunc{gsub}
+Le espressioni regolari costanti possono essere usate anche come primo
+argomento delle
+funzioni @code{gensub()}, @code{sub()}, e @code{gsub()}, come secondo argomento
+della funzione @code{match()},
+e come terzo argomento delle funzioni @code{split()} e @code{patsplit()}
+(@pxref{Funzioni per stringhe}).
+Le moderne implementazioni di @command{awk}, incluso @command{gawk}, permettono
+di usare come terzo argomento di @code{split()} una costante @dfn{regexp}, ma
+alcune implementazioni pi@`u vecchie non lo consentono.
+@value{DARKCORNER}
+Poich@'e alcune funzioni predefinite accettano costanti @dfn{regexp} come
+argomenti, pu@`o generare confusione l'uso di costanti @dfn{regexp} come
+argomenti di funzioni definite dall'utente
+(@pxref{Funzioni definite dall'utente}). Per esempio:
+
+@example
+function mysub(modello, sostituzione, stringa, globale)
+@{
+ if (globale)
+ gsub(modello, sostituzione, stringa)
+ else
+ sub(modello, sostituzione, stringa)
+ return stringa
+@}
+
+@{
+ @dots{}
+ text = "salve! salve a te!"
+ mysub(/salve/, "ciao", text, 1)
+ @dots{}
+@}
+@end example
+
+@c @cindex automatic warnings
+@c @cindex warnings, automatic
+In quest'esempio, il programmatore vuol passare una costante @dfn{regexp} alla
+funzione definita dall'utente @code{mysub()}, che a sua volta la passa o a
+@code{sub()} o a @code{gsub()}. Comunque, quel che realmente succede @`e che
+al parametro @code{modello} @`e assegnato un valore di uno o zero, a seconda
+che @code{$0} corrisponda a @code{/salve/} o no.
+@command{gawk} emette un avvertimento quando vede una costante @dfn{regexp}
+usata come parametro di una funzione definita dall'utente, poich@'e
+passare un valore vero/falso in questo modo probabilmente non @`e quello che
+si intendeva fare.
+
+@node Costanti @dfn{regexp} forti
+@subsubsection Costanti @dfn{regexp} fortemente tipizzate
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive una funzionalit@`a specifica di @command{gawk}.
+
+Come visto
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ifdocbook
+@value{SECTION}
+@end ifdocbook
+precedente,
+le costanti @dfn{regexp} (@code{/@dots{}/}) hanno uno strano posto nel
+linguaggio @command{awk}. In molti contesti, si comportano come
+un'espressione:
+@samp{$0 ~ /@dots{}/}. In altri contesti, denotano solo una @dfn{regexp} da
+individuare. In nessun caso esse sono davvero ``cittadine di serie A'' del
+linguaggio. Ovvero, non @`e possibile definire una variabile scalare il cui
+tipo sia ``@dfn{regexp}'' nello stesso senso in cui si pu@`o definire una
+variabile che sia un numero o una stringa:
+
+@example
+num = 42 @ii{Variabile numerica}
+str = "hi" @ii{Variabile di tipo stringa}
+re = /pippo/ @ii{Errore!} re @ii{@`e il risultato di} $0 ~ /pippo/
+@end example
+
+Per alcuni casi di uso pi@`u avanzati,
+sarebbe bello poter avere costanti @dfn{regexp} che sono
+@dfn{fortemente tipizzate}; in altre parole, che sostituiscono
+una @dfn{regexp} utile per effettuare dei confronti,
+e non una semplice espressione regolare.
+
+@command{gawk} prevede questa funzionalit@`a. Un'espressione regolare
+fortemente tipizzata @`e molto simile a un'espressione regolare normale,
+tranne per il fatto di essere preceduta dal simbolo @samp{@@}:
+
+@example
+re = @@/foo/ @ii{variabile @dfn{regexp} fortemente tipizzata}
+@end example
+
+Le variabili @dfn{regexp} fortemente tipizzate @emph{non possono} essere
+usate in ogni istruzione in cui compare un'espressione regolare normale.
+perch@'e ci@`o renderebbe il linguaggio ancora pi@`u fuorviante.
+Queste espressioni possono essere usate solo in alcuni contesti:
+
+@itemize @bullet
+@item
+Sul lato destro degli operatori @samp{~} e @samp{!~}:
+@samp{qualche_variabile ~ @@/foo/}
+(@pxref{Uso di @dfn{regexp}}).
+
+@item
+Nella parte @code{case} di un'istruzione @code{switch}
+(@pxref{Istruzione switch}).
+
+@item
+Come argomento in una delle funzioni predefinite che possono utilizzare
+costanti @dfn{regexp}:
+@code{gensub()},
+@code{gsub()},
+@code{match()},
+@code{patsplit()},
+@code{split()}
+e
+@code{sub()}
+(@pxref{Funzioni per stringhe}).
+
+@item
+Come parametro in una chiamata a una funzione definita dall'utente
+(@pxref{Funzioni definite dall'utente}).
+
+@item
+Sul lato destro di un assegnamento di variabile:
+@samp{qualche_variabile = @@/foo/}.
+In tal caso, @code{qualche_variabile} @`e di tipo @dfn{regexp}.
+Inoltre, @code{qualche_variabile}
+pu@`o essere usata con gli operatori @samp{~} e @samp{!~}, passata a una
+delle funzioni predefinite sopra elencate o passata come parametro
+a una funzione definita dall'utente.
+@end itemize
+
+Si pu@`o usare la funzione predefinita @code{typeof()}
+(@pxref{Funzioni per i tipi})
+per determinare se un parametro passato a una funzione
+@`e una variabile di tipo @dfn{regexp}.
+
+La vera efficacia di questa funzionalit@`a consiste nella capacit@`a di creare
+variabili il cui tipo @`e @dfn{regexp}. Tali variabili possono essere passate
+a funzioni definite dall'utente, senza gli inconvenenti che si hanno usando
+espressioni regolari calcolate, a partire da stringhe o da costanti di tipo
+stringa. Queste variabili possono anche essere passate utilizzando chiamate
+indirette a funzioni (@pxref{Chiamate indirette}) e alle funzioni predefinite
+che accettano costanti di tipo @dfn{regesp}.
+
+Quando sono usate per effettuare conversioni numeriche, le variabili
+@dfn{regexp} fortemente tipizzate vengono convertite alla cifra zero.
+Quando sono usate per effettuare conversioni a stringhe, vengono convertite
+al valore di stringa del testo della @dfn{regexp} originale.
+
+@node Variabili
+@subsection Variabili
+
+@cindex variabili definite dall'utente
+@cindex definite dall'utente, variabili
+Le @dfn{variabili} consentono di memorizzare valori in un certo punto di un
+programma, per usarli pi@`u tardi in un'altra parte del programma. Le variabili
+possono essere gestite interamente all'interno del testo del programma, ma
+ad esse possono essere assegnati valori sulla riga di comando, in fase di
+invocazione di @command{awk}.
+
+@menu
+* Usare variabili:: Usare variabili nei propri programmi.
+* Opzioni di assegnamento:: Impostare variabili dalla riga di
+ comando, e un sommario della sintassi
+ della riga di comando.
+ Questo @`e un metodo di input avanzato.
+@end menu
+
+@node Usare variabili
+@subsubsection Usare variabili in un programma
+
+Le variabili permettono di dare nomi ai valori e di far riferimento ad essi in
+un secondo momento. Alcune variabili sono gi@`a state usate in molti degli
+esempi.
+Il nome di una variabile dev'essere una sequenza di lettere, cifre o trattini
+bassi, e non deve iniziare con una cifra.
+Qui, una @dfn{lettera} @`e una qualsiasi delle 52 lettere maiuscole e minuscole
+dell'alfabeto inglese. Altri caratteri che possono essere definiti come
+lettere in localizzazioni non inglesi non sono validi nei nomi di variabile.
+Il maiuscolo o minuscolo sono significativi nei nomi di variabile;
+@code{a} e @code{A} sono variabili diverse.
+
+Un nome di variabile @`e un'espressione valida in se stessa; rappresenta il
+valore corrente della variabile. I valori delle variabili possono essere
+modificati tramite @dfn{operatori di assegnamento}, @dfn{operatori di
+incremento} e @dfn{operatori di decremento}
+(@xref{Operatori di assegnamento}).
+Inoltre, le funzioni @code{sub()} e @code{gsub()} possono cambiare il valore
+di una variabile e le funzioni
+@code{match()}, @code{split()}, e @code{patsplit()} possono cambiare il
+contenuto dei loro parametri che sono
+costituiti da vettori
+(@pxref{Funzioni per stringhe}).
+
+@cindex variabili, predefinite
+@cindex variabili, inizializzazione
+Alcune variabili hanno un significato speciale predefinito, come @code{FS}
+(il separatore di campo) e @code{NF} (il numero di campi nel record di input
+corrente). @xref{Variabili predefinite} per un elenco delle variabili
+predefinite. Queste variabili predefinite possono essere usate e possono
+ricevere assegnamenti come tutte le altre variabili, ma i loro valori sono
+anche usati o cambiati automaticamente da @command{awk}. Tutti i nomi delle
+variabili predefinite sono in caratteri maiuscoli.
+
+Alle variabili in @command{awk} possono essere assegnati valori numerici o
+valori di stringa. Il tipo di valore che una variabile contiene pu@`o cambiare
+durante la vita di un programma. Per default, le variabili sono inizializzate
+alla stringa nulla, che vale zero se viene convertita in un numero. Non c'@`e
+alcuna
+necessit@`a di inizializzare esplicitamente una variabile in @command{awk},
+come invece occorre fare in C e nella maggior parte dei linguaggi
+tradizionali.
+
+@node Opzioni di assegnamento
+@subsubsection Assegnare una variabile dalla riga di comando
+@cindex variabili, assegnare da riga di comando
+@cindex riga di comando, variabili@comma{} assegnare da
+
+Si pu@`o impostare qualsiasi variabile @command{awk} includendo un
+@dfn{assegnamento di variabile} tra gli argomenti sulla riga di comando quando
+viene invocato @command{awk} (@pxref{Altri argomenti}).
+Tale assegnamento ha la seguente forma:
+
+@example
+@var{variabile}=@var{testo}
+@end example
+
+@cindex @option{-v}, opzione
+@noindent
+Con questo assegnamento, una variabile viene impostata o all'inizio
+dell'esecuzione di @command{awk} o tra la lettura di un file in input e il
+successivo file in input.
+Quando l'assegnamento @`e preceduto dall'opzione @option{-v},
+come nel seguente esempio:
+
+@example
+-v @var{variabile}=@var{testo}
+@end example
+
+@noindent
+la variabile @`e impostata proprio all'inizio, ancor prima che sia eseguita la
+regola @code{BEGIN}. L'opzione @option{-v} e il suo assegnamento
+deve precedere tutti gli argomenti @value{FN}, e anche il testo del programma.
+(@xref{Opzioni} per maggiori informazioni sull'opzione
+@option{-v}.)
+In alternativa, l'assegnamento di variabile @`e effettuata in un momento
+determinato
+dalla posizione dell'opzione tra gli argomenti "file in input", cio@`e dopo
+l'elaborazione del precedente argomento "file in input". Per esempio:
+
+@example
+awk '@{ print $n @}' n=4 inventory-shipped n=2 mail-list
+@end example
+
+@noindent
+stampa il valore del campo numero @code{n} per tutti i record in input. Prima
+che venga letto il primo file, la riga di comando imposta la variabile @code{n}
+al valore quattro. Questo fa s@`{@dotless{i}} che venga stampato il quarto campo delle righe
+del file @file{inventory-shipped}. Dopo la fine del primo file, ma prima
+che inizi il secondo file, @code{n} viene impostato a due, e quindi poi
+viene stampato il secondo campo delle righe di @file{mail-list}:
+
+@example
+$ @kbd{awk '@{ print $n @}' n=4 inventory-shipped n=2 mail-list}
+@print{} 15
+@print{} 24
+@dots{}
+@print{} 555-5553
+@print{} 555-3412
+@dots{}
+@end example
+
+@cindex angolo buio, argomenti da riga di comando
+Gli argomenti da riga di comando sono resi disponibili dal programma
+@command{awk} nel vettore @code{ARGV} per poter essere esaminati esplicitamente
+(@pxref{ARGC e ARGV}).
+@command{awk} elabora i valori degli assegnamenti da riga di comando per
+sequenze di protezione
+(@pxref{Sequenze di protezione}).
+@value{DARKCORNER}
+
+@node Conversione
+@subsection Conversione di stringhe e numeri
+
+Le conversioni di numeri in stringhe e di stringhe in numeri sono generalmente
+semplici. Ci possono essere delle sottigliezze che bisogna tenere presenti;
+questa @value{SECTION} tratta di quest'importante sfaccettatura di @command{awk}.
+
+@menu
+* Stringhe e numeri:: Come @command{awk} converte tra
+ stringhe e numeri.
+* Localizzazione e conversioni:: Come la localizzazione pu@`o influire
+ sulle conversioni.
+@end menu
+
+@node Stringhe e numeri
+@subsubsection Come @command{awk} converte tra stringhe e numeri
+
+@cindex conversione da stringhe a numeri
+@cindex stringhe, conversione
+@cindex numeri, conversione in stringhe
+@cindex conversione da numeri a stringhe
+Le stringhe sono convertite in numeri e i numeri sono convertiti in stringhe,
+se il contesto del programma @command{awk} lo richiede. Per esempio, se il
+valore di @code{pippo} o @code{pluto} nell'espressione @samp{pippo + pluto}
+@`e una stringa, viene convertita in un numero prima di eseguire l'addizione.
+Se in una concatenazione di stringhe ci sono valori numerici, questi sono
+convertiti in stringhe. Si consideri il seguente esempio:
+
+@example
+due = 2; tre = 3
+print (due tre) + 4
+@end example
+
+@noindent
+Stampa il valore (numerico) di 27. I valori numerici delle
+variabili @code{due} e @code{tre} sono convertiti in stringhe e
+concatenati insieme. La stringa risultante @`e riconvertita nel
+numero 23, al quale poi viene aggiunto 4.
+
+@cindex stringhe nulle, conversione da tipo numerico a tipo stringa
+@cindex conversione di tipo variabile
+@cindex variabile, conversione di tipo
+Se, per qualche ragione, si vuole forzare la conversione di un numero in
+una stringa, basta concatenare a quel numero la stringa nulla, @code{""}.
+Per forzare la conversione di una stringa in un numero, basta aggiungere zero
+a quella stringa. Una stringa viene convertita in un numero interpretando
+qualsiasi prefisso numerico della stringa come numero:
+@code{"2.5"} si converte in 2.5, @code{"1e3"} si converte in 1000, e
+@code{"25fix"} ha un valore numerico di 25.
+Le stringhe che non possono essere interpretate come numeri validi vengono
+convertite al valore zero.
+
+@cindex @code{CONVFMT}, variabile
+Il modo esatto in cui i numeri sono convertiti in stringhe @`e controllato dalla
+variabile predefinita di @command{awk} @code{CONVFMT}
+(@pxref{Variabili predefinite}). I numeri vengono convertiti usando la
+funzione @code{sprintf()}
+con @code{CONVFMT} come specificatore di formato
+(@pxref{Funzioni per stringhe}).
+
+Il valore di default di @code{CONVFMT} @`e @code{"%.6g"}, che crea un valore con
+un massimo di sei cifre significative. Per alcune applicazioni potrebbe essere
+opportuno cambiare questo valore per ottenere una maggiore precisione.
+Sulla maggior parte delle macchine moderne
+normalmente bastano 17 cifre per esprimere esattamente il valore di un numero
+in virgola mobile.@footnote{Per casi eccezionali possono essere richieste fino
+a 752 cifre (!), non sembra che sia il caso di preoccuparsene qui.}
+
+@cindex angolo buio, variabile @code{CONVFMT}
+Si possono avere strani risultati se si imposta @code{CONVFMT} a una stringa
+che non indica a @code{sprintf()} come formattare i numeri in virgola mobile
+in un modo utile. Per esempio, se ci si dimentica la @samp{%} nel formato,
+@command{awk} converte tutti i numeri alla stessa stringa costante.
+
+Come caso particolare, per un numero intero, il risultato della conversione
+a una stringa @`e @emph{sempre} un numero intero, indipendentemente da quale
+sia il valore di @code{CONVFMT}. Dato il seguente fammento di codice:
+
+@example
+CONVFMT = "%2.2f"
+a = 12
+b = a ""
+@end example
+
+@noindent
+@code{b} ha valore @code{"12"}, non @code{"12.00"}.
+@value{DARKCORNER}
+
+@sidebar @command{awk} prima di POSIX usava @code{OFMT} per la conversione di stringhe
+@cindex POSIX @command{awk}, variabile @code{OFMT} e
+@cindex @code{OFMT}, variabile
+@cindex portabilit@`a, nuovo @command{awk} vs.@: vecchio @command{awk}
+@cindex @command{awk}, nuovo vs.@: vecchio, variabile @code{OFMT}
+Prima dello standard POSIX, @command{awk} usava il valore di @code{OFMT} per
+convertire i numeri in stringhe. @code{OFMT} specifica il formato di output da
+usare per la stampa dei numeri con @code{print}. @code{CONVFMT} fu introdotto
+per separare la semantica della conversione dalla semantica della stampa. Sia
+@code{CONVFMT} che @code{OFMT} hanno lo stesso valore di dafault:
+@code{"%.6g"}. Nella stragrande maggioranza dei casi, i vecchi programmi di
+@command{awk} non cambiano questo comportamento.
+@xref{Print} per maggiori informazioni sull'istruzione @code{print}.
+@end sidebar
+
+@node Localizzazione e conversioni
+@subsubsection Le localizzazioni possono influire sulle conversioni
+
+Il luogo dove si @`e pu@`o avere importanza quando si tratta di convertire numeri e
+stringhe. La lingua e i caratteri---la @dfn{localizzazione}---possono
+influire sui formati numerici. In particolare, per i programmi @command{awk},
+influiscono sui caratteri separatore decimale e separatore delle migliaia.
+La localizzazione @code{"C"}, e la maggior parte delle localizzazioni inglesi,
+usano il punto (@samp{.}) come separatore decimale e non prevedono un
+separatore delle
+migliaia. Tuttavia, molte (se non la maggior parte) delle localizzazioni
+europee e non inglesi usano la virgola (@samp{,}) come separatore dei decimali.
+Le localizzazioni europee spesso usano o lo spazio o il punto come separatore
+delle migliaia, all'occorrenza.
+
+@cindex angolo buio, carattere di separazione dei decimali nelle localizzazioni
+Lo standard POSIX prevede che @command{awk} usi sempre il punto come separatore
+dei decimali nel codice sorgente del programma @command{awk}, e per
+gli assegnamenti di variabile da riga di comando (@pxref{Altri argomenti}).
+Tuttavia, nell'interpretazione dei dati in input, per l'output di
+@code{print} e @code{printf}, e per la conversione da numeri a stringhe,
+viene usato il
+separatore decimale locale. @value{DARKCORNER} In ogni caso, i numeri nel
+codice sorgente e nei dati di input non possono avere un separatore delle
+migliaia. Di seguito sono riportati alcuni esempi che illustrano la differenza
+di comportamento, su un sistema GNU/Linux:
+
+@example
+$ @kbd{export POSIXLY_CORRECT=1} @ii{Forzare aderenza a standard POSIX}
+$ @kbd{gawk 'BEGIN @{ printf "%g\n", 3.1415927 @}'}
+@print{} 3.14159
+$ @kbd{LC_ALL=en_DK.utf-8 gawk 'BEGIN @{ printf "%g\n", 3.1415927 @}'}
+@print{} 3,14159
+$ @kbd{echo 4,321 | gawk '@{ print $1 + 1 @}'}
+@print{} 5
+$ @kbd{echo 4,321 | LC_ALL=en_DK.utf-8 gawk '@{ print $1 + 1 @}'}
+@print{} 5,321
+@end example
+
+@noindent
+La localizzazione @code{en_DK.utf-8} @`e per l'inglese in Danimarca, dove
+le virgole fungono da separatore decimale. Nella localizzazione @code{"C"}
+normale, @command{gawk} tratta @samp{4,321} come 4, mentre nella localizzazione
+danese @`e trattato come numero completo comprendente la parte frazionaria,
+4.321.
+
+Alcune delle prime versioni di @command{gawk} si conformavano completamente con
+quest'aspetto dello standard. Tuttavia, molti utenti di localizzazioni non
+inglesi si lamentavano di questo comportamento, perch@'e i loro dati usavano il
+punto come separatore decimale, per cui fu ripristinato il comportamento di
+default che usava il punto come carattere di separazione decimale. Si pu@`o
+usare l'opzione @option{--use-lc-numeric} (@pxref{Opzioni}) per forzare
+@command{gawk} a usare il carattere separatore decimale della localizzazione.
+(@command{gawk} usa il separatore decimale della localizzazione anche quando
+@`e in modalit@`a POSIX, o con l'opzione @option{--posix} o con la variabile
+d'ambiente @env{POSIXLY_CORRECT}, come appena visto.)
+
+@ref{table-locale-affects} descrive i casi in cui si usa il separatore decimale
+locale e quando si usa il punto. Alcune di queste funzionalit@`a non sono state
+ancora descritte.
+
+@float Tabella,table-locale-affects
+@caption{Separatore decimale locale o punto}
+@multitable @columnfractions .15 .25 .45
+@headitem Funzione @tab Default @tab @option{--posix} o @option{--use-lc-numeric}
+@item @code{%'g} @tab Usa la localizzazione @tab Usa la localizzazione
+@item @code{%g} @tab Usa il punto @tab Usa la localizzazione
+@item Input @tab Usa il punto @tab Usa la localizzazione
+@item @code{strtonum()} @tab Usa il punto @tab Usa la localizzazione
+@end multitable
+@end float
+
+Infine, gli standard ufficiali correnti e la rappresentazione dei numeri
+in virgola mobile dello standard IEEE possono avere un effetto insolito ma
+importante sul modo in cui @command{gawk} converte alcuni valori di stringa
+speciali in
+numeri. I dettagli sono illustrati in @ref{Problemi virgola mobile POSIX}.
+
+@node Tutti gli operatori
+@section Operatori: fare qualcosa coi valori
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} introduce gli @dfn{operatori} che fanno uso
+dei valori forniti da costanti e variabili.
+
+@menu
+* Operatori aritmetici:: Operazioni aritmetiche (@samp{+}, @samp{-},
+ etc.)
+* Concatenazione:: Concatenazione di stringhe.
+* Operatori di assegnamento:: Cambiare il valore di una variabile o di un
+ campo.
+* Operatori di incremento:: Incrementare il valore numerico di una
+ variabile.
+@end menu
+
+@node Operatori aritmetici
+@subsection Operatori aritmetici
+@cindex aritmetici, operatori
+@cindex operatori aritmetici
+@c @cindex addition
+@c @cindex subtraction
+@c @cindex multiplication
+@c @cindex division
+@c @cindex remainder
+@c @cindex quotient
+@c @cindex exponentiation
+
+Il linguaggio @command{awk} usa i comuni operatori aritmetici nella valutazione
+delle espressioni. Tutti questi operatori aritmetici seguono le normali regole
+di precedenza e funzionano come ci si aspetta.
+
+Il seguente esempio usa un file chiamato @file{grades}, che contiene
+una lista di nomi di studenti e anche i voti di tre verifiche per ogni studente
+(@`e una piccola classe):
+
+@example
+Pat 100 97 58
+Sandy 84 72 93
+Chris 72 92 89
+@end example
+
+@noindent
+Questo programma prende il file @file{grades} e stampa la media
+dei voti:
+
+@example
+$ @kbd{awk '@{ sum = $2 + $3 + $4 ; avg = sum / 3}
+> @kbd{print $1, avg @}' grades}
+@print{} Pat 85
+@print{} Sandy 83
+@print{} Chris 84.3333
+@end example
+
+La lista seguente elenca gli operatori aritmetici in @command{awk},
+in ordine di precedenza, da quella pi@`u alta a quella pi@`u bassa:
+
+@table @code
+@cindex estensioni comuni, operatore @code{**}
+@cindex POSIX @command{awk}, operatori aritmetici e
+@item @var{x} ^ @var{y}
+@itemx @var{x} ** @var{y}
+Elevamento a potenza; @var{x} elevato alla potenza @var{y}. @samp{2 ^ 3}
+ha il valore otto; la sequenza di caratteri @samp{**} @`e equivalente a
+@samp{^}. @value{COMMONEXT}
+
+@item - @var{x}
+Negazione.
+
+@item + @var{x}
+Pi@`u unario; l'espressione @`e convertita in un numero.
+
+@item @var{x} * @var{y}
+Moltiplicazione.
+
+@cindex risoluzione di problemi, divisione
+@cindex problemi, risoluzione di, divisione
+@cindex divisione
+@item @var{x} / @var{y}
+Divisione; poich@'e tutti i numeri in @command{awk} sono numeri in virgola
+mobile, il risultato @emph{non} @`e arrotondato all'intero---@samp{3 / 4} ha il
+valore di 0.75. (Un errore comune, specialmente tra i programmatori in C, @`e
+quello di dimenticare che @emph{tutti} i numeri in @command{awk} sono in virgola mobile,
+e che la divisione di costanti rappresentate da numeri interi produce un
+numero reale, non un numero intero.)
+
+@item @var{x} % @var{y}
+Resto della divisione; subito dopo questa lista, l'argomento viene
+ulteriormente dettagliato.
+
+@item @var{x} + @var{y}
+Addizione.
+
+@item @var{x} - @var{y}
+Sottrazione.
+@end table
+
+Il pi@`u e il meno unari hanno la stessa precedenza,
+gli operatori di moltiplicazione hanno tutti la stessa precedenza, e
+l'addizione e la sottrazione hanno la stessa precedenza.
+
+@cindex differenze tra @command{awk} e @command{gawk}, operazione di modulo-troncamento
+@cindex modulo-troncamento, operazione di
+Quando si calcola il resto di @samp{@var{x} % @var{y}},
+il quoziente @`e troncato all'intero e
+moltiplicato per @var{y}. Questo risultato @`e sottratto da @var{x};
+quest'operazione @`e nota anche come ``modulo''. La seguente
+relazione @`e sempre verificata:
+
+@example
+b * int(a / b) + (a % b) == a
+@end example
+
+Un possibile effetto indesiderato di questa definizione di resto @`e che
+@samp{@var{x} % @var{y}} sia negativo se @var{x} @`e negativo. Cos@`{@dotless{i}}:
+
+@example
+-17 % 8 = -1
+@end example
+
+In altre implementazioni di @command{awk} il segno del resto
+pu@`o essere dipendente dalla macchina.
+@c FIXME !!! what does posix say?
+
+@cindex portabilit@`a, operatore @code{**}
+@cindex @code{*} (asterisco), operatore @code{**}
+@cindex asterisco (@code{*}), operatore @code{**}
+@quotation NOTA
+Lo standard POSIX specifica solo l'uso di @samp{^}
+per l'elevamento a potenza.
+Per garantire la massima portabilit@`a @`e meglio non usare l'operatore @samp{**}.
+@end quotation
+
+@node Concatenazione
+@subsection Concatenazione di stringhe
+@cindex Kernighan, Brian
+@quotation
+@i{Allora ci era sembrata una buona idea.}
+@author Brian Kernighan
+@end quotation
+
+@cindex operatori di stringa
+@cindex stringa, operatori di
+@cindex concatenare
+C'@`e una sola operazione di stringa: la concatenazione. Non ha un operatore
+specifico per rappresentarla. Piuttosto, la concatenazione @`e effettuata
+scrivendo le espressioni l'una vicino all'altra, senza alcun operatore.
+Per esempio:
+
+@example
+$ @kbd{awk '@{ print "Campo numero uno: " $1 @}' mail-list}
+@print{} Campo numero uno: Amelia
+@print{} Campo numero uno: Anthony
+@dots{}
+@end example
+
+Senza lo spazio nella costante stringa dopo @samp{:}, la riga
+rimane unita. Per esempio:
+
+@example
+$ @kbd{awk '@{ print "Campo numero uno:" $1 @}' mail-list}
+@print{} Campo numero uno:Amelia
+@print{} Campo numero uno:Anthony
+@dots{}
+@end example
+
+@cindex risoluzione di problemi, concatenazione di stringhe
+@cindex problemi, risoluzione di, concatenazione di stringhe
+Poich@'e la concatenazione di stringhe non ha un operatore esplicito, @`e spesso
+necessario assicurarsi che venga effettuata al momento giusto usando le
+parentesi per racchiudere gli elementi da concatenare. Per esempio, ci si
+potrebbe aspettare che il
+seguente fammento di codice concateni @code{nome} e @code{file}:
+
+@example
+nome = "nome"
+file = "file"
+print "qualcosa di significativo" > nome file
+@end example
+
+@cindex Brian Kernighan, @command{awk} di
+@cindex @command{mawk}, programma di utilit@`a
+@cindex programma di utilit@`a @command{mawk}
+@noindent
+Questo produce un errore di sintassi in alcune versioni di
+@command{awk} per Unix.@footnote{Pu@`o capitare che BWK
+@command{awk}, @command{gawk} e @command{mawk} lo interpretino nel modo giusto,
+ma non ci si dovrebbe fare affidamento.}
+@`E necessario usare la seguente sintassi:
+
+@example
+print "qualcosa di significativo" > (nome file)
+@end example
+
+@cindex ordine di valutazione, concatenazione
+@cindex valutazione, ordine di, concatenazione
+@cindex effetti collaterali
+Si dovrebbero usare le parentesi attorno alle concatenazioni in tutti i
+contesti non comuni, come, per esempio, sul lato destro di @samp{=}.
+Bisogna stare attenti
+al tipo di espressioni usate nella concatenazione di stringhe. In particolare,
+l'ordine di valutazione di espressioni usate per la concatenazione non @`e
+definita nel linguaggio @command{awk}. Si consideri quest'esempio:
+
+@example
+BEGIN @{
+ a = "Non"
+ print (a " " (a = "v'allarmate"))
+@}
+@end example
+
+@noindent
+Non @`e definito se il secondo assegnamento ad @code{a} debba avvenire
+prima o dopo il recupero del valore di @code{a} per produrre il
+valore concatenato. Il risultato potrebbe essere sia @samp{Non v'allarmate},
+sia @samp{v'allarmate v'allarmate}.
+@c see test/nasty.awk for a worse example
+
+La precedenza della concatenazione, quando @`e in combinazione con altri
+operatori, @`e spesso controintuitiva. Si consideri questo esempio:
+
+@ignore
+> To: bug-gnu-utils@@gnu.org
+> CC: arnold@@gnu.org
+> Subject: gawk 3.0.4 bug with {print -12 " " -24}
+> From: Russell Schulz <Russell_Schulz@locutus.ofB.ORG>
+> Date: Tue, 8 Feb 2000 19:56:08 -0700
+>
+> gawk 3.0.4 on NT gives me:
+>
+> prompt> cat bad.awk
+> BEGIN { print -12 " " -24; }
+>
+> prompt> gawk -f bad.awk
+> -12-24
+>
+> when I would expect
+>
+> -12 -24
+>
+> I have not investigated the source, or other implementations. The
+> bug is there on my NT and DOS versions 2.15.6 .
+@end ignore
+
+@example
+$ @kbd{awk 'BEGIN @{ print -12 " " -24 @}'}
+@print{} -12-24
+@end example
+
+Quest'esempio, ``ovviamente'' concatena @minus{}12, uno spazio, e @minus{}24.
+Ma dov'@`e finito lo spazio?
+La risposta sta nella combinazione di precedenze di operatori e nelle regole di
+conversione automatica di @command{awk}. Per ottenere il risultato desiderato,
+si deve scrivere il programma in questo modo:
+
+@example
+$ @kbd{awk 'BEGIN @{ print -12 " " (-24) @}'}
+@print{} -12 -24
+@end example
+
+Questo forza il trattamento, da parte di @command{awk}, del @samp{-} del
+@samp{-24} come operatore unario. Altrimenti @`e analizzato in questo modo:
+
+@display
+ @minus{}12 (@code{"@ "} @minus{} 24)
+@result{} @minus{}12 (0 @minus{} 24)
+@result{} @minus{}12 (@minus{}24)
+@result{} @minus{}12@minus{}24
+@end display
+
+Come si @`e detto precedentemente,
+quando si usa la concatenazione insieme ad altri operatori, @`e necessario
+@emph{usare le parentesi}. Altrimenti, non si pu@`o essere mai completamente
+certi di quel che si ottiene.
+
+@node Operatori di assegnamento
+@subsection Espressioni di assegnamento
+@cindex operatori di assegnamento
+@cindex assegnamento, operatori di
+@cindex espressioni di assegnamento
+@cindex @code{=} (uguale), operatore @code{=}
+@cindex uguale (@code{=}), operatore @code{=}
+Un @dfn{assegnamento} @`e un'espressione che memorizza un valore (generalmente
+diverso da quello che la variabile aveva in precedenza) in una variabile.
+Per esempio, si assegni il valore uno alla variabile @code{z}:
+
+@example
+z = 1
+@end example
+
+Dopo l'esecuzione di quest'espressione, la variabile @code{z} ha il valore
+uno. Qualsiasi precedente valore di @code{z} prima dell'assegnamento
+viene dimenticato.
+
+Gli assegnamenti possono anche memorizzare valori di stringa. Il seguente
+esempio memorizza
+il valore @code{"questo cibo @`e buono"} nella variabile @code{messaggio}:
+
+@example
+cosa = "cibo"
+predicato = "buono"
+messaggio = "questo " cosa " @`e " predicato
+@end example
+
+@noindent
+@cindex effetti collaterali, espressioni di assegnamento
+Quest'esempio illustra anche la concatenazione di stringhe.
+Il segno @samp{=} @`e un @dfn{operatore di assegnamento}. @`E il pi@`u semplice
+fra gli operatori di assegnamento perch@'e il valore dell'operando di destra
+@`e memorizzato invariato.
+La maggior parte degli operatori (addizione, concatenazione e cos@`{@dotless{i}} via) non
+fanno altro che calcolare un valore. Se il valore non viene poi utilizzato non c'@`e alcun
+motivo per usare l'operatore. Un operatore di assegnamento @`e differente;
+produce un valore; anche se poi non lo si usa, l'assegnamento svolge ancora
+una funzione alterando la variabile. Chiamiamo questo
+un @dfn{effetto collaterale}.
+
+@cindex @dfn{lvalue/rvalue}
+@cindex @dfn{rvalue/lvalue}
+@cindex assegnamento, operatori di, @dfn{lvalue/rvalue}
+@cindex operatori di assegnamento
+L'operando di sinistra non dev'essere necessariamente una variabile
+(@pxref{Variabili}); pu@`o essere anche un campo
+(@pxref{Cambiare i campi}) o
+@iftex
+un elemento di un vettore (@pxrefil{Vettori}).
+@end iftex
+@ifnottex
+un elemento di un vettore (@pxref{Vettori}).
+@end ifnottex
+Questi operandi sono chiamati @dfn{lvalue}, il
+che significa che possono apparire sul lato sinistro di un operatore di
+assegnamento. L'operando sul lato destro pu@`o essere qualsiasi espressione;
+produce un nuovo valore che l'assegnamento memorizza nella variabile, nel campo
+o nell'elemento di vettore specificati. Tali valori sono chiamati
+@dfn{rvalue}.
+
+@cindex variabili, tipi di
+@`E importante notare che le variabili @emph{non} hanno dei tipi permanenti.
+Il tipo di una variabile @`e semplicemente quello di qualsiasi valore le sia stato
+assegnato per ultimo. Nel seguente frammento di programma, la variabile
+@code{pippo} ha dapprima un valore numerico, e in seguito un valore di stringa:
+
+@example
+pippo = 1
+print pippo
+pippo = "pluto"
+print pippo
+@end example
+
+@noindent
+Quando il secondo assegnamento d@`a a @code{pippo} un valore di stringa, il fatto
+che avesse precedentemente un valore numerico viene dimenticato.
+
+Ai valori di stringa che non iniziano con una cifra viene assegnato il valore
+numerico zero. Dopo l'esecuzione del seguente codice, il valore di @code{pippo} @`e
+cinque:
+
+@example
+pippo = "una stringa"
+pippo = pippo + 5
+@end example
+
+@quotation NOTA
+Usare una variabile sia come numero che come stringa pu@`o originare confusione
+e denota uno stile di programmazione scadente. I due esempi precedenti
+illustrano come funziona @command{awk}, @emph{non} come si dovrebbero scrivere
+i programmi!
+@end quotation
+
+Un assegnamento @`e un'espressione, per cui ha un valore: lo stesso valore che
+le @`e stato assegnato. Cos@`{@dotless{i}}, @samp{z = 1} @`e un'espressione col valore uno.
+Una conseguenza di ci@`o @`e che si possono scrivere pi@`u assegnamenti insieme,
+come:
+
+@example
+x = y = z = 5
+@end example
+
+@noindent
+Quest'esempio memorizza il valore cinque in tutte e tre le variabili,
+(@code{x}, @code{y} e @code{z}).
+Questo perch@'e il
+valore di @samp{z = 5}, che @`e cinque, @`e memorizzato in @code{y} e poi
+il valore di @samp{y = z = 5}, che @`e cinque, @`e memorizzato in @code{x}.
+
+Gli assegnamenti possono essere usati ovunque sia prevista un'espressione. Per
+esempio, @`e valido scrivere @samp{x != (y = 1)} per impostare @code{y} a
+uno, e poi verificare se @code{x} @`e uguale a uno. Per@`o questo stile rende i
+programmi difficili da leggere; una tale nidificazione di assegnamenti dovrebbe
+essere evitata, eccetto forse in un programma usa-e-getta.
+
+@cindex @code{+} (pi@`u), operatore @code{+=}
+@cindex pi@`u (@code{+}), operatore @code{+=}
+Accanto a @samp{=}, ci sono diversi altri operatori di assegnamento che
+eseguono calcoli col vecchio valore di una variabile. Per esempio,
+l'operatore @samp{+=} calcola un nuovo valore aggiungendo il valore sul lato
+destro al vecchio valore di una variabile. Cos@`{@dotless{i}}, il seguente assegnamento
+aggiunge cinque al valore di @code{pippo}:
+
+@example
+pippo += 5
+@end example
+
+@noindent
+Questo @`e equivalente a:
+
+@example
+pippo = pippo + 5
+@end example
+
+@noindent
+Si usi la notazione che rende pi@`u chiaro il significato del programma.
+
+Ci sono situazioni in cui usare @samp{+=} (o qualunque operatore di
+assegnamento) @emph{non} @`e la stessa cosa che ripetere semplicemente l'operando
+di sinistra nell'espressione di destra. Per esempio:
+
+@cindex Rankin, Pat
+@example
+# Grazie a Pat Rankin per quest'esempio
+BEGIN @{
+ pippo[rand()] += 5
+ for (x in pippo)
+ print x, pippo[x]
+
+ pluto[rand()] = pluto[rand()] + 5
+ for (x in pluto)
+ print x, pluto[x]
+@}
+@end example
+
+@cindex operatori di assegnamento, ordine di valutazione
+@cindex assegnamento, operatori di, ordine di valutazione
+@noindent
+@`E praticamente certo che gli indici di @code{pluto} siano differenti, perch@'e
+@code{rand()} restituisce valori differenti ogni volta che viene chiamata.
+(I vettori e la funzione @code{rand()} non sono ancora stati trattati.
+@iftex
+@xrefil{Vettori},
+@end iftex
+@ifnottex
+@xref{Vettori},
+@end ifnottex
+e
+@ifnotdocbook
+@pxref{Funzioni numeriche}
+@end ifnotdocbook
+@ifdocbook
+@ref{Funzioni numeriche}
+@end ifdocbook
+per maggiori informazioni.)
+Quest'esempio illustra un fatto importante riguardo agli operatori di
+assegnamento: l'espressione di sinistra viene valutata @emph{una volta sola}.
+
+Dipende dall'implementazione stabilire quale espressione valutare per
+prima, se quella di sinistra o quella di destra.
+Si consideri quest'esempio:
+
+@example
+i = 1
+a[i += 2] = i + 1
+@end example
+
+@noindent
+Il valore di @code{a[3]} potrebbe essere sia due sia quattro.
+
+La @ref{table-assign-ops} elenca gli operatori di assegnamento aritmetici. In
+ogni caso, l'operando di destra @`e un'espressione il cui valore @`e convertito in
+un numero.
+
+@cindex @code{-} (meno), operatore @code{-=}
+@cindex meno (@code{-}), operatore @code{-=}
+@cindex @code{*} (asterisco), operatore @code{*=}
+@cindex asterisco (@code{*}), operatore @code{*=}
+@cindex @code{/} (barra), operatore @code{/=}
+@cindex barra (@code{/}), operatore @code{/=}
+@cindex @code{%} (percento), operatore @code{%=}
+@cindex percento (@code{%}), operatore @code{%=}
+@cindex @code{^} (circonflesso), operatore @code{^=}
+@cindex circonflesso (@code{^}), operatore @code{^=}
+@cindex @code{*} (asterisco), operatore @code{**=}
+@cindex asterisco (@code{*}), operatore @code{**=}
+@float Tabella,table-assign-ops
+@caption{Operatori di assegnamento aritmetici}
+@multitable @columnfractions .30 .70
+@headitem Operatore @tab Effetto
+@item @var{lvalue} @code{+=} @var{incremento} @tab Aggiunge @var{incremento} al valore di @var{lvalue}.
+@item @var{lvalue} @code{-=} @var{decremento} @tab Sottrae @var{decremento} dal valore di @var{lvalue}.
+@item @var{lvalue} @code{*=} @var{coefficiente} @tab Moltiplica il valore di @var{lvalue} per @var{coefficiente}.
+@item @var{lvalue} @code{/=} @var{divisore} @tab Divide il valore di @var{lvalue} per @var{divisore}.
+@item @var{lvalue} @code{%=} @var{modulo} @tab Imposta @var{lvalue} al resto della sua divisione per @var{modulo}.
+@cindex estensioni comuni, operatore @code{**=}
+@cindex estensioni comuni@comma{} operatore @code{**=}
+@cindex @command{awk}, linguaggio, versione POSIX
+@cindex POSIX @command{awk}
+@item @var{lvalue} @code{^=} @var{esponente} @tab Eleva @var{lvalue} alla potenza @var{esponente}.
+@item @var{lvalue} @code{**=} @var{esponente} @tab Eleva @var{lvalue} alla potenza @var{esponente}. @value{COMMONEXT}
+@end multitable
+@end float
+
+@cindex POSIX @command{awk}, operatore @code{**=} e
+@cindex portabilit@`a, operatore @code{**=}
+@quotation NOTA
+Soltanto l'operatore @samp{^=} @`e definito da POSIX.
+Per avere la massima portabilit@`a, non usare l'operatore @samp{**=}.
+@end quotation
+
+@sidebar Ambiguit@`a sintattiche tra @samp{/=} e le espressioni regolari
+@cindex angolo buio, costanti @dfn{regexp}, operatore @code{/=} e
+@cindex @code{/} (barra), operatore @code{/=}, vs. costante @dfn{regexp} @code{/=@dots{}/}
+@cindex barra (@code{/}), operatore @code{/=}, vs. costante @dfn{regexp} @code{/=@dots{}/}
+@cindex @dfn{regexp}, costanti, @code{/=@dots{}/}, operatore @code{/=} e
+
+@c derived from email from "Nelson H. F. Beebe" <beebe@math.utah.edu>
+@c Date: Mon, 1 Sep 1997 13:38:35 -0600 (MDT)
+
+@cindex angolo buio, operatore @code{/=} vs. costante @dfn{regexp} @code{/=@dots{}/}
+@cindex ambiguit@`a sintattica: operatore @code{/=} vs. costante @dfn{regexp} @code{/=@dots{}/}
+@cindex sintattica, ambiguit@`a: operatore @code{/=} vs. costante @dfn{regexp} @code{/=@dots{}/}
+@cindex @code{/=}, operatore, vs. costante @dfn{regexp} @code{/=@dots{}/}
+C'@`e un'ambiguit@`a sintattica tra l'operatore di assegnamento @code{/=}
+e le costanti @dfn{regexp} il cui primo carattere sia @samp{=}.
+@value{DARKCORNER}
+Questo @`e pi@`u evidente in alcune versioni commerciali di @command{awk}.
+Per esempio:
+
+@example
+$ @kbd{awk /==/ /dev/null}
+@error{} awk: syntax error at source line 1
+@error{} context is
+@error{} >>> /= <<<
+@error{} awk: bailing out at source line 1
+@end example
+
+@noindent
+Un espediente @`e:
+
+@example
+awk '/[=]=/' /dev/null
+@end example
+
+@command{gawk} non ha questo problema, e neppure lo hanno BWK @command{awk}
+e @command{mawk}.
+@end sidebar
+
+@node Operatori di incremento
+@subsection Operatori di incremento e di decremento
+
+@cindex incremento, operatori di
+@cindex operatori di decremento/incremento
+Gli @dfn{operatori di incremento} e @dfn{decremento} incrementano o riducono il
+valore di una variabile di uno. Un operatore di assegnamento pu@`o fare la
+stessa cosa, per cui gli operatori di incremento non aggiungono funzionalit@`a
+al inguaggio @command{awk}; in ogni caso, sono delle convenienti abbreviazioni
+per operazioni molto comuni.
+
+@cindex effetti collaterali
+@cindex @code{+} (pi@`u), operatore @code{++}
+@cindex pi@`u (@code{+}), operatore @code{++}
+@cindex effetti collaterali, operatori di decremento/incremento
+L'operatore per aggiungere uno @`e @samp{++}. Pu@`o essere usato per incrementare
+una variabile prima o dopo aver stabilito il suo valore. Per @dfn{preincrementare}
+una variabile @code{v}, si scrive @samp{++v}. Questo aggiunge uno al valore di
+@code{v}; questo nuovo valore @`e anche il valore dell'espressione.
+(L'espressione di assegnamento @samp{v += 1} @`e totalmente equivalente.)
+Scrivendo @samp{++} dopo la variabile si specifica un @dfn{postincremento}.
+Questo incrementa il valore della variabile nello stesso modo; la differenza @`e
+che il valore dell'espressione d'incremento @`e il @emph{vecchio} valore della
+variabile. Cos@`{@dotless{i}}, se @code{pippo} ha il valore quattro, l'espressione
+@samp{pippo++} ha il valore quattro, ma cambia il valore di @code{pippo} in cinque.
+In altre parole, l'operatore restituisce il vecchio valore della variabile, ma
+con l'effetto collaterale di incrementarlo.
+
+Il postincremento @samp{pippo++} @`e quasi come scrivere @samp{(pippo += 1) - 1}.
+Non @`e perfettamente equivalente perch@'e tutti i numeri in @command{awk} sono in
+virgola mobile. In virgola mobile, @samp{pippo + 1 - 1} non @`e necessariamente
+uguale a @code{pippo}, ma la differenza @`e molto piccola finch@'e si ha a che
+fare con numeri relativamente piccoli (inferiori a
+@iftex
+@math{10^{12}}).
+@end iftex
+@ifinfo
+10e12).
+@end ifinfo
+@ifnottex
+@ifnotinfo
+10@sup{12}).
+@end ifnotinfo
+@end ifnottex
+
+@cindex @code{$} (dollaro), incrementare campi e vettori
+@cindex dollaro (@code{$}), incrementare campi e vettori
+I campi di un record e gli elementi di un vettore vengono incrementati
+proprio come le
+variabili. (Si deve usare @samp{$(i++)} quando si deve fare un riferimento a
+un campo e incrementare una variabile allo stesso tempo. Le parentesi sono
+necessarie a causa della precedenza dell'operatore di riferimento @samp{$}.)
+
+@cindex decremento, operatori di
+L'operatore di decremento @samp{--} funziona proprio come @samp{++}, solo che
+sottrae uno anzich@'e aggiungerlo. Come @samp{++}, si pu@`o usare prima di
+@dfn{lvalue}
+per predecrementare o dopo per postdecrementare.
+Quel che segue @`e un sommario delle espressioni di incremento e di
+decremento:
+
+@table @code
+@cindex @code{+} (pi@`u), operatore @code{++}
+@cindex pi@`u (@code{+}), operatore @code{++}
+@item ++@var{lvalue}
+Incrementa @var{lvalue}, restituendo il nuovo valore come
+valore dell'espressione.
+
+@item @var{lvalue}++
+Incrementa @var{lvalue}, restituendo il @emph{vecchio} valore di @var{lvalue}
+come valore dell'espressione.
+
+@cindex @code{-} (meno), operatore @code{--}
+@cindex meno (@code{-}), operatore @code{--}
+@item --@var{lvalue}
+Decrementa @var{lvalue}, restituendo il nuovo valore come
+valore dell'espressione.
+(Quest'espressione @`e come
+@samp{++@var{lvalue}}, ma invece di aggiungere, sottrae.)
+
+@item @var{lvalue}--
+Decrementa @var{lvalue}, restituendo il @emph{vecchio} valore di @var{lvalue}
+come valore dell'espressione.
+(Quest'espressione @`e come
+@samp{@var{lvalue}++}, ma invece di aggiungere, sottrae.)
+@end table
+
+@sidebar Ordine di valutazione degli operatori
+@cindex precedenza
+@cindex operatori, precedenza
+@cindex portabilit@`a, operatori
+@cindex valutazione, ordine di
+@cindex Marx, Groucho
+@quotation
+@i{Dottore, quando faccio cos@`{@dotless{i}} mi fa male!@*
+E allora non farlo!}
+@author Groucho Marx
+@end quotation
+
+@noindent
+Che cosa succede con qualcosa come questo?
+
+@example
+b = 6
+print b += b++
+@end example
+
+@noindent
+O con qualcosa di pi@`u strano ancora?
+
+@example
+b = 6
+b += ++b + b++
+print b
+@end example
+
+@cindex effetti collaterali
+In altre parole, quando hanno effetto i vari effetti collaterali previsti
+dagli operatori col suffisso (@samp{b++})? Quando gli effetti collaterali
+si verificano @`e @dfn{definito dall'implementazione}.
+Per dirla diversamente, questo @`e compito di ogni specifica versione di
+@command{awk}. Il risultato del primo esempio pu@`o essere 12 o 13, e del
+secondo pu@`o essere 22 o 23.
+
+In breve, @`e sconsigliato fare cose come questa e, in ogni caso,
+ogni cosa che possa incidere sulla portabilit@`a.
+Si dovrebbero evitare cose come queste nei programmi.
+@c You'll sleep better at night and be able to look at yourself
+@c in the mirror in the morning.
+@end sidebar
+
+@node Valori e condizioni di verit@`a
+@section Valori e condizioni di verit@`a
+
+In certi contesti, i valori delle espressioni servono anche come
+``valori di verit@`a''; cio@`e, determinano quale sar@`a la direzione che il
+programma prender@`a durante la sua esecuzione. Questa
+@value{SECTION} descrive come @command{awk} definisce ``vero'' e ``falso''
+e come questi valori sono confrontati.
+
+@menu
+* Valori di verit@`a:: Cos'@`e ``vero'' e cos'@`e ``falso''.
+* Tipi di variabile e confronti:: Come alle variabili si assegna il tipo e
+ l'effetto che questo ha sul confronto di
+ numeri e stringhe con @samp{<}, etc.
+* Operatori booleani:: Combinare espressioni di confronto usando
+ operatori booleani @samp{||} (``or''),
+ @samp{&&} (``and'') e @samp{!} (``not'').
+* Espressioni condizionali:: Le espressioni condizionali scelgono una fra
+ due sottoespressioni, a seconda del valore di
+ una terza sottoespressione.
+@end menu
+
+@node Valori di verit@`a
+@subsection Vero e falso in @command{awk}
+@cindex valori di verit@`a
+@cindex logico, valore, vero/falso
+@cindex falso, valore logico (zero o stringa nulla)
+@cindex vero, valore logico (diverso da zero e da stringa nulla)
+
+@cindex nulle, stringhe
+Molti linguaggi di programmazione hanno una particolare rappresentazione per i
+concetti di ``vero'' e ``falso.'' Questi linguaggi usano normalmente le
+costanti speciali @code{true} e @code{false}, o forse i loro equivalenti
+maiuscoli.
+Per@`o @command{awk} @`e differente.
+Prende in prestito un concetto molto semplice di vero e falso dal linguaggio
+C. In @command{awk}, ogni valore numerico diverso da zero @emph{oppure}
+ogni valore di stringa non vuota @`e vero. Ogni altro valore (zero o la stringa
+nulla, @code{""}) @`e falso. Il seguente programma stampa @samp{Uno strano
+valore di verit@`a} tre volte:
+
+@example
+BEGIN @{
+ if (3.1415927)
+ print "Uno strano valore di verit@`a"
+ if ("Ottanta e sette anni or sono")
+ print "Uno strano valore di verit@`a"
+ if (j = 57)
+ print "Uno strano valore di verit@`a"
+@}
+@end example
+
+@cindex angolo buio, @code{"0"} @`e effettivamente vero
+C'@`e una conseguenza sorprendente della regola ``non zero o non nullo'':
+la costante di stringa @code{"0"} sta effettivamente per vero, perch@'e
+@`e non nulla.
+@value{DARKCORNER}
+
+@node Tipi di variabile e confronti
+@subsection Tipi di variabile ed espressioni di confronto
+@quotation
+@i{La Guida galattica @`e infallibile. @`E la realt@`a, spesso, a essere inesatta.}
+@author Douglas Adams, @cite{Guida galattica per autostoppisti}
+@end quotation
+@c 2/2015: Antonio Colombo points out that this is really from
+@c The Restaurant at the End of the Universe. But I'm going to
+@c leave it alone.
+
+@cindex confronto, espressioni di
+@cindex espressioni di confronto
+@cindex espressioni, ricerca di corrispondenze, si veda espressioni di confronto
+@cindex individuazione, espressioni di, si veda espressioni di confronto
+@cindex relazionali, operatori, si veda espressioni di confronto
+@cindex operatori relazionali, si veda espressioni di confronto
+@cindex variabile, tipi di
+@cindex variabili, tipi di, espressioni di confronto e
+Diversamente che in altri linguaggi di programmazione, le variabili di
+@command{awk} non hanno un tipo fisso. Possono essere sia un numero che una
+stringa, a seconda del valore loro assegnato.
+Vediamo ora come viene assegnato il tipo a una variabile, e come @command{awk}
+le confronta.
+
+@menu
+* Tipi di variabile:: Tipo stringa rispetto a tipo numero.
+* Operatori di confronto:: Gli operatori di confronto.
+* Confronto POSIX di stringhe:: Confronto tra stringhe usando le
+ regole POSIX.
+@end menu
+
+@node Tipi di variabile
+@subsubsection Tipo stringa rispetto a tipo numero
+
+Per gli elementi scalari in @command{awk} (variabili, elementi di
+vettore e campi), il tipo degli stessi viene attribuito @emph{dinamicamente}.
+Ci@`o significa che il tipo di un elemento pu@`o cambiare nel corso
+dell'esecuzione di un programma, da @dfn{untyped} (non ancora tipizzata),
+valore assunto prima che la variabile sia utilizzata,@footnote{@command{gawk}
+chiama queste variabili @dfn{unassigned} (non ancora assegnate), come si
+vede dall'esempio che segue.} a stringa oppure a numero, e in seguito
+da stringa a numero o da numero a stringa, nel prosieguo del programma.
+(@command{gawk} prevede anche degli scalari di tipo @dfn{regexp}, ma
+per ora possiamo ignorarli;
+@pxref{Costanti @dfn{regexp} forti}.)
+
+Non si pu@`o fare molto riguardo alle variabili di tipo @dfn{untyped},
+oltre a constatare che ancora non @`e stato loro attribuito un tipo.
+Il seguente programma confronta la variabile @code{a} con i valori
+@code{""} e @code{0}; il confronto d@`a esito positivo se alla
+variabile @code{a} non @`e mai stato assegnato un valore.
+L'esempio usa la funzione predefinita @code{typeof()}
+(non ancora trattata; @pxref{Funzioni per i tipi}) per
+visualizzare il tipo della variabile @code{a}:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print (a == "" && a == 0 ?}
+> @kbd{"a non ha un tipo" : "a ha un tipo!") ; print typeof(a) @}'}
+@print{} a non ha un tipo
+@print{} unassigned
+@end example
+
+Una variabile scalare diviene di tipo numerico quando le viene assegnato un
+valore numerico, per mezzo di una costante numerica, o tramite un'altra
+variabile scalare di tipo numerico:
+
+@example
+$ @kbd{gawk 'BEGIN @{ a = 42 ; print typeof(a)}
+> @kbd{b = a ; print typeof(b) @}'}
+number
+number
+@end example
+
+Analogamente, una variabile scalare diviene di tipo stringa quando le
+viene assegnato come valore una stringa, per mezzo di una costante stringa,
+o tramite un'altra variabile scalare di tipo stringa:
+
+@example
+$ @kbd{gawk 'BEGIN @{ a = "quarantadue" ; print typeof(a)}
+> @kbd{b = a ; print typeof(b) @}'}
+string
+string
+@end example
+
+Fin qui, tutto semplice e chiaro. Cosa succede, per@`o, quando
+@command{awk} deve trattare dati forniti dall'utente?
+Il primo caso da considerare @`e quello dei campi di dati in input.
+Quale dovrebbe essere l'output del seguente programma?
+
+@example
+echo ciao | awk '@{ printf("%s %s < 42\n", $1,
+ ($1 < 42 ? "@`e" : "non @`e")) @}'
+@end example
+
+@noindent
+Poich@'e @samp{ciao} @`e un dato di tipo alfabetico, @command{awk} pu@`o solo
+effettuare un confronto di tipo stringa. Internamente, il numero @code{42}
+viene convertito in @code{"42"} e vengono confrontate le due stringhe di
+valore @code{"ciao"} e @code{"42"}. Questo @`e il risultato:
+
+@example
+$ @kbd{echo ciao | awk '@{ printf("%s %s < 42\n", $1,}
+> @kbd{ ($1 < 42 ? "@`e" : "non @`e")) @}'}
+@print{} ciao non @`e < 42
+@end example
+
+Tuttavia, cosa succede quando un dato utente @emph{assomiglia} a un
+numero?
+Da un lato, in realt@`a, il dato in input @`e formato da alcuni caratteri, non da
+valori numerici in formato binario. Ma, d'altro lato, il dato sembra
+numerico, e @command{awk} dovrebbe davvero trattarlo come tale. E in effetti
+questo @`e ci@`o che avviene:
+
+@example
+$ @kbd{echo 37 | awk '@{ printf("%s %s < 42\n", $1,}
+> @kbd{ ($1 < 42 ? "@`e" : "non @`e")) @}'}
+@print{} 37 is < 42
+@end example
+
+Queste sono le regole seguite per determinare quando @command{awk}
+tratta dei dati in input come numeri, e quando li considera stringhe.
+
+@cindex numeriche, stringhe
+@cindex stringhe, numeriche
+@cindex POSIX @command{awk}, stringhe numeriche e
+Lo standard POSIX usa il concetto di @dfn{stringa numerica}, per dei dati
+in input che appaiono essere numerici. Il @samp{37} nell'esempio precedente
+@`e una stringa numerica. Quindi, qual @`e il tipo di una stringa numerica?
+Risposta: numerico.
+
+Il tipo di una variabile @`e importante perch@'e il tipo di due variabili
+determina il modo con cui le stesse vengono confrontate.
+La determinazione del tipo di variabile segue queste regole:
+
+@itemize @value{BULLET}
+@item
+Una costante numerica o il risultato di un'operazione numerica ha l'attributo
+@dfn{numeric}.
+
+@item
+Una costante di stringa o il risultato di un'operazione di stringa ha
+l'attributo @dfn{string}.
+
+@item
+Campi, input tramite @code{getline}, @code{FILENAME}, elementi di
+@code{ARGV}, elementi di @code{ENVIRON}, e gli elementi di un vettore
+creato da @code{match()}, @code{split()} e @code{patsplit()} che sono
+stringhe numeriche hanno l'attributo @dfn{strnum}.@footnote{Quindi, una
+stringa numerica POSIX e una variabile tipo @dfn{strnum} di @command{gawk}
+sono equivalenti.}
+Altrimenti, hanno l'attributo @dfn{string}.
+Anche le variabili non inizializzate hanno l'attributo @var{strnum}.
+
+@item
+Gli attributi si trasmettono attraverso gli assegnamenti ma non vengono
+cambiati da nessun uso.
+@c (Although a use may cause the entity to acquire an additional
+@c value such that it has both a numeric and string value, this leaves the
+@c attribute unchanged.)
+@c This is important but not relevant
+@end itemize
+
+L'ultima regola @`e particolarmente importante. Nel seguente programma,
+@code{a} @`e di tipo numerico, anche se viene usata in un secondo momento in
+un'operazione di stringa:
+
+@example
+BEGIN @{
+ a = 12.345
+ b = a " @`e un numero carino"
+ print b
+@}
+@end example
+
+Quando si confrontano due operandi, pu@`o essere usata sia il confronto come
+stringa che il confronto numerico, a seconda degli attributi degli operandi,
+secondo questa matrice simmetrica:
+
+@c thanks to Karl Berry, kb@cs.umb.edu, for major help with TeX tables
+@tex
+\centerline{
+\vbox{\bigskip % space above the table (about 1 linespace)
+% Because we have vertical rules, we can't let TeX insert interline space
+% in its usual way.
+\offinterlineskip
+%
+% Define the table template. & separates columns, and \cr ends the
+% template (and each row). # is replaced by the text of that entry on
+% each row. The template for the first column breaks down like this:
+% \strut -- a way to make each line have the height and depth
+% of a normal line of type, since we turned off interline spacing.
+% \hfil -- infinite glue; has the effect of right-justifying in this case.
+% # -- replaced by the text (for instance, `STRNUM', in the last row).
+% \quad -- about the width of an `M'. Just separates the columns.
+%
+% The second column (\vrule#) is what generates the vertical rule that
+% spans table rows.
+%
+% The doubled && before the next entry means `repeat the following
+% template as many times as necessary on each line' -- in our case, twice.
+%
+% The template itself, \quad#\hfil, left-justifies with a little space before.
+%
+\halign{\strut\hfil#\quad&\vrule#&&\quad#\hfil\cr
+ &&STRING &NUMERIC &STRNUM\cr
+% The \omit tells TeX to skip inserting the template for this column on
+% this particular row. In this case, we only want a little extra space
+% to separate the heading row from the rule below it. the depth 2pt --
+% `\vrule depth 2pt' is that little space.
+\omit &depth 2pt\cr
+% This is the horizontal rule below the heading. Since it has nothing to
+% do with the columns of the table, we use \noalign to get it in there.
+\noalign{\hrule}
+% Like above, this time a little more space.
+\omit &depth 4pt\cr
+% The remaining rows have nothing special about them.
+STRING &&string &string &string\cr
+NUMERIC &&string &numeric &numeric\cr
+STRNUM &&string &numeric &numeric\cr
+}}}
+@end tex
+@ifnottex
+@ifnotdocbook
+@verbatim
+ +----------------------------------------------
+ | STRING NUMERIC STRNUM
+--------+----------------------------------------------
+ |
+STRING | string string string
+ |
+NUMERIC | string numeric numeric
+ |
+STRNUM | string numeric numeric
+--------+----------------------------------------------
+@end verbatim
+@end ifnotdocbook
+@end ifnottex
+@docbook
+<informaltable>
+<tgroup cols="4">
+<colspec colname="1" align="left"/>
+<colspec colname="2" align="left"/>
+<colspec colname="3" align="left"/>
+<colspec colname="4" align="left"/>
+<thead>
+<row>
+<entry/>
+<entry>STRING</entry>
+<entry>NUMERIC</entry>
+<entry>STRNUM</entry>
+</row>
+</thead>
+
+<tbody>
+<row>
+<entry><emphasis role="bold">STRING</emphasis></entry>
+<entry>string</entry>
+<entry>string</entry>
+<entry>string</entry>
+</row>
+
+<row>
+<entry><emphasis role="bold">NUMERIC</emphasis></entry>
+<entry>string</entry>
+<entry>numeric</entry>
+<entry>numeric</entry>
+</row>
+
+<row>
+<entry><emphasis role="bold">STRNUM</emphasis></entry>
+<entry>string</entry>
+<entry>numeric</entry>
+<entry>numeric</entry>
+</row>
+
+</tbody>
+</tgroup>
+</informaltable>
+
+@end docbook
+
+L'idea di base @`e che l'input dell'utente che appare come numerico---e
+@emph{solo} l'input dell'utente---dovrebbe essere trattato come numerico, anche
+se in realt@`a @`e un insieme di caratteri e quindi anche una stringa.
+Cos@`{@dotless{i}}, ad esempio, la costante di stringa @w{@code{" +3.14"}},
+quando appare nel codice sorgente di un programma,
+@`e una stringa---anche se sembra numerica---e non
+viene @emph{mai} trattato come numero
+ai fini di un confronto.
+
+In breve, quando un operando @`e una stringa ``pura'', come una costante di
+stringa, viene effettuato un confronto di stringa. In caso contrario viene
+effettuato un confronto numerico.
+(La differenza principale tra un numero e uno @dfn{strnum} @`e che per gli
+@dfn{strnum} @command{gawk} conserva anche il valore originale della stringa
+che la variabile scalare aveva al momento in cui @`e stata letta.
+
+Questo punto merita di essere ulteriormente ribadito:
+l'input che appare essere un numero @emph{@`e} numerico.
+Tutto il resto dell'input @`e considerato essere una stringa.
+
+Cos@`{@dotless{i}}, la stringa in input di sei caratteri @w{@samp{ +3.14}}
+riceve l'attributo @dfn{strnum}. Al contrario, la stringa di sei caratteri
+@w{@code{" +3.14"}} che compaia nel testo di un programma rimane una
+costante di stringa. I seguenti esempi stampano @samp{1} quando il confronto
+fra due diverse costanti @`e vero, altrimenti stampano @samp{0}:
+
+@c 22.9.2014: Tested with mawk and BWK awk, got same results.
+@example
+$ @kbd{echo ' +3.14' | awk '@{ print($0 == " +3.14") @}'} @ii{Vero}
+@print{} 1
+$ @kbd{echo ' +3.14' | awk '@{ print($0 == "+3.14") @}'} @ii{Falso}
+@print{} 0
+$ @kbd{echo ' +3.14' | awk '@{ print($0 == "3.14") @}'} @ii{Falso}
+@print{} 0
+$ @kbd{echo ' +3.14' | awk '@{ print($0 == 3.14) @}'} @ii{Vero}
+@print{} 1
+$ @kbd{echo ' +3.14' | awk '@{ print($1 == " +3.14") @}'} @ii{Falso}
+@print{} 0
+$ @kbd{echo ' +3.14' | awk '@{ print($1 == "+3.14") @}'} @ii{Vero}
+@print{} 1
+$ @kbd{echo ' +3.14' | awk '@{ print($1 == "3.14") @}'} @ii{Falso}
+@print{} 0
+$ @kbd{echo ' +3.14' | awk '@{ print($1 == 3.14) @}'} @ii{Vero}
+@print{} 1
+@end example
+
+Per controllare il tipo di un campo in input (o di altro input immesso
+dall'utente, si pu@`o usare @code{typeof()}:
+
+@example
+$ @kbd{echo salve 37 | gawk '@{ print typeof($1), typeof($2) @}'}
+@print{} string strnum
+@end example
+
+@node Operatori di confronto
+@subsubsection Operatori di confronto
+
+Le @dfn{espressioni di confronto} confrontano stringhe o numeri per metterli in
+relazione tra di loro, come ad esempio nella relazione di uguaglianza. Sono
+scritte usando @dfn{operatori di relazione}, che sono un superinsieme di quelli
+in C. Sono descritti nella @ref{table-relational-ops}.
+
+@cindex @code{<} (parentesi acuta sinistra), operatore @code{<}
+@cindex parentesi acuta sinistra (@code{<}), operatore @code{<}
+@cindex @code{<} (parentesi acuta sinistra), operatore @code{<=}
+@cindex parentesi acuta sinistra (@code{<}), operatore @code{<=}
+@cindex @code{>} (parentesi acuta destra), operatore @code{>=}
+@cindex parentesi acuta destra (@code{>}), operatore @code{>=}
+@cindex @code{>} (parentesi acuta destra), operatore @code{>}
+@cindex parentesi acuta destra (@code{>}), operatore @code{>}
+@cindex @code{=} (uguale), operatore @code{==}
+@cindex uguale (@code{=}), operatore @code{==}
+@cindex @code{!} (punto esclamativo), operatore @code{!=}
+@cindex punto esclamativo (@code{!}), operatore @code{!=}
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+@cindex @code{in}, operatore
+@float Tabella,table-relational-ops
+@caption{Operatori di relazione}
+@multitable @columnfractions .23 .77
+@headitem Espressione @tab Risultato
+@item @var{x} @code{<} @var{y} @tab Vero se @var{x} @`e minore di @var{y}
+@item @var{x} @code{<=} @var{y} @tab Vero se @var{x} @`e minore o uguale a @var{y}
+@item @var{x} @code{>} @var{y} @tab Vero se @var{x} @`e maggiore di @var{y}
+@item @var{x} @code{>=} @var{y} @tab Vero se @var{x} @`e maggiore o uguale a @var{y}
+@item @var{x} @code{==} @var{y} @tab Vero se @var{x} @`e uguale a @var{y}
+@item @var{x} @code{!=} @var{y} @tab Vero se @var{x} @`e diverso da @var{y}
+@item @var{x} @code{~} @var{y} @tab Vero se la stringa @var{x} corrisponde alla @dfn{regexp} rappresentata da @var{y}
+@item @var{x} @code{!~} @var{y} @tab Vero se la stringa @var{x} non corrisponde alla @dfn{regexp} rappresentata da @var{y}
+@item @var{indice} @code{in} @var{vettore} @tab Vero se il vettore @var{vettore} ha un elemento con indice @var{indice}
+@end multitable
+@end float
+
+Le espressioni di confronto valgono uno se sono vere e zero se false.
+Quando si confrontano operandi di tipi diversi, gli operandi numerici sono
+convertiti in stringhe usando il valore di @code{CONVFMT}
+(@pxref{Conversione}).
+
+Il confronto tra stringhe avviene
+confrontando il primo carattere di ciascuna stringa, poi il secondo carattere,
+e cos@`{@dotless{i}} via. Quindi, @code{"10"} @`e minore di @code{"9"}. Se vi sono due
+stringhe di cui una @`e il prefisso dell'altra, la stringa pi@`u corta @`e minore di
+quella pi@`u lunga. Cos@`{@dotless{i}}, @code{"abc"} @`e minore di @code{"abcd"}.
+
+@cindex risoluzione di problemi, operatore @code{==}
+@cindex problemi, risoluzione di, operatore @code{==}
+@`E molto facile sbagliarsi scrivendo l'operatore @samp{==} e
+omettendo uno dei due caratteri @samp{=}. Il risultato @`e sempre un codice
+@command{awk} valido, ma il programma non fa quel che si voleva:
+
+@example
+if (a = b) # oops! dovrebbe essere == b
+ @dots{}
+else
+ @dots{}
+@end example
+
+@noindent
+A meno che @code{b} non sia zero o la stringa nulla, la parte @code{if}
+del test ha sempre successo. Poich@'e gli operatori sono molto simili,
+questo tipo di errore @`e molto difficile da individuare
+rileggendo il codice sorgente.
+
+Il seguente elenco di espressioni illustra il tipo di confronti
+che @command{awk} effettua e il risultato di ciascun confronto:
+
+@table @code
+@item 1.5 <= 2.0
+Confronto numerico (vero)
+
+@item "abc" >= "xyz"
+Confronto tra stringhe (falso)
+
+@item 1.5 != " +2"
+Confronto tra stringhe (vero)
+
+@item "1e2" < "3"
+Confronto tra stringhe (vero)
+
+@item a = 2; b = "2"
+@itemx a == b
+Confronto tra stringhe (vero)
+
+@item a = 2; b = " +2"
+@itemx a == b
+Confronto tra stringhe (falso)
+@end table
+
+In quest'esempio:
+
+@example
+$ @kbd{echo 1e2 3 | awk '@{ print ($1 < $2) ? "vero" : "falso" @}'}
+@print{} falso
+@end example
+
+@cindex espressioni di confronto, stringa vs.@: @dfn{regexp}
+@c @cindex string comparison vs.@: regexp comparison
+@c @cindex regexp comparison vs.@: string comparison
+@noindent
+il risultato @`e @samp{falso} perch@'e sia @code{$1} che @code{$2}
+sono immessi dall'utente. Sono stringhe numeriche---quindi hanno entrambe
+l'attributo @dfn{strnum}, che richiede un confronto di tipo numerico.
+Lo scopo delle regole di confronto e dell'uso di stringhe numeriche @`e quello
+di cercare di produrre il comportamento "meno inaspettato possibile",
+pur "facendo la cosa giusta".
+
+I confronti di stringhe e i confronti di espressioni regolari sono molto
+diversi. Per esempio:
+
+@example
+x == "att"
+@end example
+
+@noindent
+ha il valore uno, ossia @`e vero, se la variabile @code{x}
+@`e precisamente @samp{att}. Al contrario:
+
+@example
+x ~ /att/
+@end example
+
+@noindent
+ha il valore uno se @code{x} contiene @samp{att}, come
+@code{"Oh, che matto che sono!"}.
+
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+L'operando di destra degli operatori @samp{~} e @samp{!~} pu@`o essere sia una
+costante @dfn{regexp} (@code{/}@dots{}@code{/}) che un'espressione ordinaria.
+In quest'ultimo caso, il valore dell'espressione come stringa @`e usato come una
+@dfn{regexp} dinamica (@pxref{Uso di @dfn{regexp}}; e
+@pxref{Espressioni regolari calcolate}).
+
+@cindex @command{awk}, costanti @dfn{regexp} e
+@cindex costanti @dfn{regexp}
+@cindex @dfn{regexp}, costanti
+Un'espressione regolare costante tra due barre @`e di per s@'e anche
+un'espressione. @code{/@var{regexp}/} @`e un'abbreviazione per la seguente
+espressione di confronto:
+
+@example
+$0 ~ /@var{regexp}/
+@end example
+
+Una particolare posizione dove @code{/pippo/} @emph{non} @`e un'abbreviazione di
+@samp{$0 ~ /pippo/} @`e quella in cui @`e l'operando di destra di @samp{~} o
+@samp{!~}.
+@xref{Usare le costanti @dfn{regexp}},
+dove questo punto @`e trattato in maggiore dettaglio.
+
+@node Confronto POSIX di stringhe
+@subsubsection Confronto tra stringhe usando l'ordine di collazione locale
+
+Lo standard POSIX diceva che il confronto di stringhe viene effettuato secondo
+l'@dfn{ordine di collazione} locale. Questo @`e l'ordine secondo il quale sono
+disposti i caratteri, come definito dalla localizzazione (per una trattazione
+pi@`u dettagliata, @pxref{Localizzazioni}). Quest'ordine normalmente @`e molto
+diverso dal risultato ottenuto quando si esegue un confronto rigorosamente
+"carattere per carattere".@footnote{Tecnicamente, il confronto di stringhe
+dovrebbe funzionare come se le stringhe fossero confrontate usando la
+funzione @code{strcoll()} di C.}
+
+Poich@'e questo comportamento differisce sensibilmente dalla pratica corrente,
+@command{gawk} lo implementava solo quando eseguito in modalit@`a POSIX
+(@pxref{Opzioni}).
+Quest'esempio ilustra la differenza, in una localizzazione
+@code{en_US.UTF-8}:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf("ABC < abc = %s\n",}
+> @kbd{("ABC" < "abc" ? "TRUE" : "FALSE")) @}'}
+@print{} ABC < abc = TRUE
+$ @kbd{gawk --posix 'BEGIN @{ printf("ABC < abc = %s\n",}
+> @kbd{("ABC" < "abc" ? "TRUE" : "FALSE")) @}'}
+@print{} ABC < abc = FALSE
+@end example
+Fortunatamente, dal mese di agosto 2016, un confronto basato sull'ordine
+di collazione locale non @`e pi@`u richiesto per gli operatori @code{==} e
+@code{!=}.@footnote{Si consulti il sito web
+@uref{http://austingroupbugs.net/view.php?id=1070,
+dell'Austin Group}.} Tuttavia, un confronto basato sull'ordine di
+collazione locale @`e ancora richiesto per gli operatori @code{<},
+@code{<=}, @code{>} e @code{>=}. POSIX, quindi, raccomanda quanto
+segue:
+
+@quotation
+Poich@'e l'operatore @code{==} controlla che se le stringhe sono identiche,
+e non se sono nell'ordine di collazione locale, le applicazioni che
+devono controllare se le stringhe sono nell'ordine di collazione locale
+possono usare:
+
+@example
+a <= b && a >= b
+@end example
+@end quotation
+
+A partire dalla @value{PVERSION} 4.2, @command{gawk} continua a usare
+l'ordine di collazione locale per @code{<}, @code{<=}, @code{>}
+e @code{>=} solo se eseguito nella modalit@`a POSIX.
+
+@node Operatori booleani
+@subsection Espressioni booleane
+@cindex @dfn{and}, operatore logico-booleano
+@cindex @dfn{or}, operatore logico-booleano
+@cindex @dfn{not}, operatore logico-booleano
+@cindex espressioni booleane
+@cindex booleane, espressioni
+@cindex operatori booleani, si veda espressioni booleane
+@cindex booleani, operatori, si veda espressioni booleane
+@cindex logici, operatori, si veda espressioni booleane
+@cindex operatori logici, si veda espressioni booleane
+
+Un'@dfn{espressione booleana} @`e una combinazione di espressioni di confronto o
+espressioni di ricerca, che usa gli operatori booleani "or"
+(@samp{||}), "and" (@samp{&&}), e "not" (@samp{!}), facendo uso di
+parentesi per controllare le nidificazioni. Il valore di verit@`a
+dell'espressione booleana @`e calcolato calcolando i valori di verit@`a delle
+espressioni componenti. Le espressioni booleane sono conosciute anche come
+@dfn{espressioni logiche}. I due termini sono equivalenti.
+
+Le espressioni booleane possono essere usate in tutti i casi in cui @`e possibile
+usare espressioni di confronto e di ricerca di corrispondenze. Si possono
+usare nelle istruzioni @code{if}, @code{while}, @code{do} e @code{for}
+(@pxref{Istruzioni}).
+Hanno valori numerici (uno se vero, zero se falso) che entrano in gioco
+se il risultato di un'espressione booleana @`e memorizzato in una variabile o
+se @`e usato nei calcoli.
+
+Inoltre, ogni espressione booleana @`e anche un modello di ricerca valido, cos@`{@dotless{i}}
+se ne pu@`o usare uno come modello di ricerca per controllare l'esecuzione di
+regole. Gli operatori booleani sono:
+
+@table @code
+@item @var{booleano1} && @var{booleano2}
+Vero se @var{booleano1} e @var{booleano2} sono entrambi veri. Per esempio,
+la seguente istruzione stampa il record in input corrente se contiene
+sia @samp{edu} che @samp{li}:
+
+@example
+if ($0 ~ /edu/ && $0 ~ /li/) print
+@end example
+
+@cindex effetti collaterali, operatori booleani
+La sottoespressione @var{booleano2} viene valutata solo se @var{booleano1}
+@`e vero. Questo pu@`o comportare una differenza laddove @var{booleano2} contenga
+espressioni che hanno effetti collaterali. Nel caso di @samp{$0 ~ /pippo/ &&
+($2 == pluto++)}, la variabile @code{pluto} non viene incrementata se non c'@`e
+nessuna sottostringa @samp{pippo} nel record.
+
+@item @var{booleano1} || @var{booleano2}
+Vero se almeno uno tra @var{booleano1} e @var{booleano2} @`e vero.
+Per esempio, la seguente istruzione stampa tutti i record dell'input che
+contengono @samp{edu} @emph{oppure}
+@samp{li}:
+
+@example
+if ($0 ~ /edu/ || $0 ~ /li/) print
+@end example
+
+La sottoespressione @var{booleano2} viene valutata solo se @var{booleano1}
+@`e falso. Questo pu@`o comportare una differenza quando @var{booleano2} contiene
+espressioni che hanno effetti collaterali.
+(Perci@`o, questo confronto non individua mai i record che contengono sia
+@samp{edu} che @samp{li}: non appena @samp{edu} viene trovato,
+l'intero confronto @`e concluso positivamente.)
+
+@item ! @var{booleano}
+Vero se @var{booleano} @`e falso. Per esempio,
+il seguente programma stampa @samp{nessuna home!} nel
+caso insolito che la variabile d'ambiente @env{HOME}
+non sia stata definita:
+
+@example
+BEGIN @{ if (! ("HOME" in ENVIRON))
+ print "nessuna home!" @}
+@end example
+
+(L'operatore @code{in} @`e descritto in
+@ref{Visitare elementi}.)
+@end table
+
+@cindex cortocircuito, operatori
+@cindex operatori di cortocircuito
+@cindex @code{&} (e commerciale), operatore @code{&&}
+@cindex e commerciale (@code{&}), operatore @code{&&}
+@cindex @code{|} (barra verticale), operatore @code{||}
+@cindex barra verticale (@code{|}), operatore @code{||}
+Gli operatori @samp{&&} e @samp{||} sono chiamati operatori di
+@dfn{cortocircuito} per il modo in cui funzionano. La valutazione dell'intera
+espressione @`e "cortocircuitata" se il risultato pu@`o gi@`a essere determinato
+prima di aver completato interamente la valutazione.
+
+@cindex continuazione di riga
+Le istruzioni che finiscono con @samp{&&} o @samp{||} si possono continuare
+semplicemente mettendo un ritorno a capo dopo di esse. Per@`o non si pu@`o mettere
+un ritorno a capo @emph{prima} di questi operatori senza usare la
+continuazione tramite la barra inversa (@pxref{Istruzioni/Righe}).
+
+@cindex @code{!} (punto esclamativo), operatore @code{!}
+@cindex punto esclamativo (@code{!}), operatore @code{!}
+@cindex ritorno a capo
+@cindex variabili di tipo indicatore [@dfn{flag}]
+@cindex @dfn{flag} [indicatore], variabili
+Il valore reale di un'espressione che usa l'operatore @samp{!} @`e uno
+o zero, a seconda del valore di verit@`a dell'espressione a cui
+@`e applicato.
+L'operatore @samp{!} spesso @`e utile per cambiare il senso di una variabile
+indicatore [@dfn{flag}] da falso a vero e viceversa. Per esempio, il seguente
+programma @`e un modo per stampare righe poste tra due speciali righe
+delimitatrici:
+
+@example
+$1 == "START" @{ pertinente = ! pertinente; next @}
+pertinente @{ print @}
+$1 == "END" @{ pertinente = ! pertinente; next @}
+@end example
+
+@noindent
+La variabile @code{pertinente}, cos@`{@dotless{i}} come tutte le variabili di @command{awk},
+@`e inizializzata a zero, che vale anche "falso". Quando viene trovata
+una riga il cui primo campo @`e @samp{START}, il valore di @code{pertinente}
+viene commutato a vero, usando @samp{!}. La regola nella riga seguente stampa righe finch@'e
+@code{pertinente} resta vero. Quando viene trovata una riga il cui primo
+campo @`e @samp{END}, @code{pertinente} viene nuovamente commutata a
+falso.@footnote{Questo programma ha un bug; stampa righe che iniziano con
+@samp{END}. Come si pu@`o risolvere?}
+
+@ignore
+Scott Deifik points out that this program isn't robust against
+bogus input data, but the point is to illustrate the use of `!',
+so we'll leave well enough alone.
+@end ignore
+
+Pi@`u comunemente, l'operatore @samp{!} viene usato nelle condizioni delle
+istruzioni @code{if} e @code{while}, dove ha pi@`u senso formulare espressioni
+logiche in negativo:
+
+@example
+if (! @var{qualche condizione} || @var{qualche altra condizione}) @{
+ @var{@dots{} fai un'operazione a piacere @dots{}}
+@}
+@end example
+
+@cindex @code{next}, istruzione
+@quotation NOTA
+L'istruzione @code{next} viene trattata in
+@ref{Istruzione next}.
+@code{next} dice ad @command{awk} di tralasciare il resto delle regole,
+leggere il record successivo, e iniziare a elaborare le regole partendo
+nuovamente dalla prima.
+Il motivo @`e quello di evitare di stampare le righe delimitatrici
+@samp{START} e @samp{END}.
+@end quotation
+
+@node Espressioni condizionali
+@subsection Espressioni condizionali
+@cindex condizionali, espressioni
+@cindex espressioni condizionali
+@cindex espressioni, selezionare
+
+Un'@dfn{espressione condizionale} @`e un tipo particolare di espressione che ha
+tre operandi. Consente di usare il primo valore dell'espressione per
+scegliere una o l'altra delle due ulteriori espressioni.
+L'espressione condizionale in @command{awk} @`e la stessa di quella del
+linguaggio C, ovvero:
+
+@example
+@var{selettore} ? @var{espr-se-vero} : @var{espr-se-falso}
+@end example
+
+@noindent
+Ci sono tre sottoespressioni. La prima, @var{selettore}, viene sempre
+calcolata per prima. Se @`e "vera" (non zero o non nulla), viene poi calcolata
+@var{espr-se-vero} e il suo valore diventa il valore dell'intera espressione.
+Altrimenti, la seconda espressione che viene calcolata @`e @var{espr-se-falso}
+e il suo valore diventa il valore dell'intera espressione.
+Per esempio, la seguente espressione produce il valore assoluto di @code{x}:
+
+@example
+x >= 0 ? x : -x
+@end example
+
+@cindex effetti collaterali, espressioni condizionali
+Ogni volta che viene calcolata un'espressione condizionale, solo una delle
+espressioni @var{espr-se-vero} e @var{espr-se-falso} viene usata; l'altra
+@`e ignorata. Questo @`e importante quando le espressioni hanno effetti
+collaterali. Per esempio, quest'espressione condizionale esamina l'elemento
+@code{i} del vettore @code{a} o del vettore @code{b}, e incrementa @code{i}:
+
+@example
+x == y ? a[i++] : b[i++]
+@end example
+
+@noindent
+Questa istruzione garantisce che @code{i} sia incrementato una volta sola
+per ogni esecuzione dell'istruzione stessa, perch@'e ogni volta viene eseguita
+solo una delle due espressioni di incremento, mentre l'altra viene
+ignorata.
+@iftex
+@xrefil{Vettori},
+@end iftex
+@ifnottex
+@xref{Vettori},
+@end ifnottex
+per maggiori informazioni sui vettori.
+
+@cindex differenze tra @command{awk} e @command{gawk}, continuazione di riga
+@cindex continuazione di riga, @command{gawk}
+@cindex @command{gawk}, continuazione di riga in
+Come estensione minore di @command{gawk},
+un'istruzione che usa @samp{?:} si pu@`o continuare mettendo
+semplicemente un ritorno a capo dopo i due caratteri.
+Tuttavia, se si mette un ritorno a capo @emph{prima} dei due
+caratteri, la continuazione non funziona, se non si aggiunge anche la barra inversa
+(@pxref{Istruzioni/Righe}).
+Se viene specificata l'opzione @option{--posix}
+(@pxref{Opzioni}), quest'estensione @`e disabilitata.
+
+@node Chiamate di funzione
+@section Chiamate di funzione
+@cindex chiamata di funzione
+
+Una @dfn{funzione} @`e un nome per richiedere un particolare calcolo.
+Il nome permette di richiamare
+la funzione da qualsiasi punto del programma.
+Per esempio, la funzione @code{sqrt()} calcola la radice quadrata di un numero.
+
+@cindex funzioni predefinite
+Un certo numero di funzioni sono @dfn{predefinite}, ossia sono
+disponibili in ogni programma @command{awk}. La funzione @code{sqrt()} @`e una
+di queste. @xref{Funzioni predefinite} per un elenco di funzioni
+predefinite e per le loro rispettive descrizioni. In aggiunta, l'utente pu@`o
+definire delle funzioni da usare nel proprio programma.
+@xref{Funzioni definite dall'utente}
+per istruzioni su come farlo.
+Infine, @command{gawk} permette di scrivere funzioni in C o in C++ che possono
+essere chiamate dal proprio programma (@pxref{Estensioni dinamiche}).
+
+@cindex argomenti, nelle chiamate di funzione
+Una funzione viene utilizzata invocandola tramite un'espressione di
+@dfn{chiamata di funzione}, che consiste nel nome della funzione seguito
+immediatamente da una lista di @dfn{argomenti} tra parentesi. Gli argomenti
+sono espressioni che forniscono i materiali grezzi su cui opera la funzione.
+Quando ci sono pi@`u argomenti, questi sono separati da virgole. Se
+non ci sono argomenti, basta scrivere @samp{()} dopo il nome della funzione.
+Gli esempi che seguono mostrano chiamate di funzione con e senza argomenti:
+
+@example
+sqrt(x^2 + y^2) @ii{un argomento}
+atan2(y, x) @ii{due argomenti}
+rand() @ii{nessun argomento}
+@end example
+
+@cindex risoluzione di problemi, sintassi della chiamata di funzione
+@cindex problemi, risoluzione di, sintassi della chiamata di funzione
+@quotation ATTENZIONE
+Non ci dev'essere nessuno spazio tra il nome della funzione e la parentesi
+aperta! Un nome di funzione definita dall'utente pu@`o essere scambiata per
+il nome di una
+variabile: uno spazio renderebbe l'espressione simile alla concatenazione di
+una variabile con un'espressione racchiusa tra parentesi.
+Per le funzioni predefinite, lo spazio prima delle parentesi non crea problemi,
+ma @`e meglio non prendere l'abitudine di usare spazi per evitare errori con le
+funzioni definite dall'utente.
+@end quotation
+
+Ogni funzione richiede uno specifico numero di argomenti.
+Per esempio, la funzione @code{sqrt()} dev'essere chiamata con
+un solo argomento, il numero del quale si vuole estrarre la radice quadrata:
+
+@example
+sqrt(@var{argomento})
+@end example
+
+Alcune delle funzioni predefinite hanno uno o pi@`u argomenti opzionali.
+Se questi argomenti non vengono forniti, le funzioni
+usano un valore di default appropriato.
+@xref{Funzioni predefinite} per tutti i dettagli. Se sono omessi argomenti
+in chiamate a funzioni definite dall'utente, tali argomenti sono considerati
+essere variabili locali. Il valore di tali variabili locali
+@`e la stringa nulla se usate in un contesto che richiede una stringa
+di caratteri, e lo zero se @`e richiesto
+un valore numerico
+(@pxref{Funzioni definite dall'utente}).
+
+Come funzionalit@`a avanzata, @command{gawk} prevede la possibilit@`a di
+effettuare chiamate di funzione
+indirette, il che permette di scegliere la funzione da chiamare al momento
+dell'esecuzione, invece che nel momento in cui si scrive il codice sorgente
+del programma.
+Si rimanda la trattazione di questa funzionalit@`a
+a un secondo momento; si veda @ref{Chiamate indirette}.
+
+@cindex effetti collaterali, chiamate di funzione
+Come ogni altra espressione, la chiamata di funzione ha un valore, chiamato
+spesso @dfn{valore di ritorno}, che @`e calcolato dalla funzione
+in base agli argomenti dati. In quest'esempio, il valore di ritorno
+di @samp{sqrt(@var{argomento})} @`e la radice quadrata di @var{argomento}.
+Il seguente programma legge numeri, un numero per riga, e stampa
+la radice quadrata di ciascuno:
+
+@example
+$ @kbd{awk '@{ print "La radice quadrata di", $1, "@`e", sqrt($1) @}'}
+@kbd{1}
+@print{} La radice quadrata di 1 @`e 1
+@kbd{3}
+@print{} La radice quadrata di 3 @`e 1.73205
+@kbd{5}
+@print{} La radice quadrata di 5 @`e 2.23607
+@kbd{Ctrl-d}
+@end example
+
+Una funzione pu@`o avere anche effetti collaterali, come assegnare
+valori a certe variabili o effettuare operazioni di I/O.
+Questo programma mostra come la funzione @code{match()}
+(@pxref{Funzioni per stringhe})
+cambia le variabili @code{RSTART} e @code{RLENGTH}:
+
+@example
+@{
+ if (match($1, $2))
+ print RSTART, RLENGTH
+ else
+ print "non uguali"
+@}
+@end example
+
+@noindent
+Qui vediamo un'esecuzione di esempio:
+
+@example
+$ @kbd{awk -f matchit.awk}
+@kbd{aaccdd c+}
+@print{} 3 2
+@kbd{pippo pluto}
+@print{} non uguali
+@kbd{abcdefg e}
+@print{} 5 1
+@end example
+
+@node Precedenza
+@section Precedenza degli operatori (Come si nidificano gli operatori)
+@cindex precedenza
+@cindex operatori, precedenza
+
+La @dfn{precedenza degli operatori} determina come gli operatori vengono
+raggruppati quando diversi operatori appaiono uno vicino all'altro in
+un'espressione.
+Per esempio, @samp{*} ha una precedenza pi@`u alta di @samp{+}; cos@`{@dotless{i}},
+@samp{a + b * c} moltiplica @code{b} e @code{c}, e poi aggiunge @code{a} al
+prodotto (ovvero esegue @samp{a + (b * c)}).
+
+La normale precedenza degli operatori pu@`o essere cambiata usando delle
+parentesi. Si possono vedere le regole di precedenza come un modo per
+indicare dove si sarebbero dovute mettere delle parentesi. Di fatto,
+@`e cosa saggia usare sempre le parentesi
+in presenza di una combinazione di operatori insolita, perch@'e altre persone
+che leggono il programma potrebbero non ricordare quale sia la precedenza
+in quel particolare caso.
+Anche dei programmatori esperti a volte dimenticano le regole esatte,
+il che porta a commettere errori.
+Usare esplicitamente le parentesi previene qualunque errore
+di questo tipo.
+
+Quando vengono usati insieme operatori con uguale precedenza, quello pi@`u a
+sinistra viene raggruppato per primo, ad eccezione degli operatori di
+assegnamento, condizionali e di elevamento a potenza, che vengono raggruppati
+nell'ordine opposto.
+Quindi, @samp{a - b + c} raggruppa come @samp{(a - b) + c} e
+@samp{a = b = c} raggruppa come @samp{a = (b = c)}.
+
+Normalmente la precedenza degli operatori unari di prefisso non ha importanza,
+perch@'e c'@`e un solo modo di interpretarli: prima il pi@`u interno. Quindi,
+@samp{$++i} significa @samp{$(++i)} e
+@samp{++$x} significa @samp{++($x)}. Tuttavia, quando un altro operatore segue
+l'operando, la precedenza degli operatori unari pu@`o avere importanza.
+@samp{$x^2} significa @samp{($x)^2}, ma @samp{-x^2} significa
+@samp{-(x^2)}, perch@'e @samp{-} ha precedenza pi@`u bassa rispetto a @samp{^},
+mentre @samp{$} ha precedenza pi@`u alta.
+Inoltre, gli operatori non possono essere combinati in modo tale da violare le
+regole di precedenza; per esempio, @samp{$$0++--} non @`e un'espressione valida
+perch@'e il primo @samp{$} ha precedenza pi@`u alta di
+@samp{++}; per evitare il problema l'espressione pu@`o essere scritta come
+@samp{$($0++)--}.
+
+Questa lista illustra gli operatori di @command{awk}, in ordine di precedenza
+dalla pi@`u alta alla pi@`u bassa:
+
+@c @asis for docbook to come out right
+@table @asis
+@item @code{(}@dots{}@code{)}
+Raggruppamento.
+
+@cindex @code{$} (dollaro), operatore di campo @code{$}
+@cindex dollaro (@code{$}), operatore di campo @code{$}
+@item @code{$}
+Riferimento a un campo.
+
+@cindex @code{+} (pi@`u), operatore @code{++}
+@cindex pi@`u (@code{+}), operatore @code{++}
+@cindex @code{-} (meno), operatore @code{--}
+@cindex meno (@code{-}), operatore @code{--}
+@item @code{++ --}
+Incremento, decremento.
+
+@cindex @code{^} (circonflesso), operatore @code{^}
+@cindex circonflesso (@code{^}), operatore @code{^}
+@cindex @code{*} (asterisco), operatore @code{**}
+@cindex asterisco (@code{*}), operatore @code{**}
+@item @code{^ **}
+Elevamento a potenza. Questi operatori sono raggruppati da destra verso
+sinistra.
+
+@cindex @code{+} (pi@`u), operatore @code{+}
+@cindex pi@`u (@code{+}), operatore @code{+}
+@cindex @code{-} (meno), operatore @code{-}
+@cindex meno (@code{-}), operatore @code{-}
+@cindex @code{!} (punto esclamativo), operatore @code{!}
+@cindex punto esclamativo (@code{!}), operatore @code{!}
+@item @code{+ - !}
+Pi@`u, meno, ``not'' logico, unari.
+
+@cindex @code{*} (asterisco), operatore @code{*}, come operatore di moltiplicazione
+@cindex asterisco (@code{*}), operatore @code{*}, come operatore di moltiplicazione
+@cindex @code{/} (barra), operatore @code{/}
+@cindex barra (@code{/}), operatore @code{/}
+@cindex @code{%} (percento), operatore @code{%}
+@cindex percento (@code{%}), operatore @code{%}
+@item @code{* / %}
+Moltiplicazione, divisione, resto di una divisione.
+
+@cindex @code{+} (pi@`u), operatore @code{+}
+@cindex pi@`u (@code{+}), operatore @code{+}
+@cindex @code{-} (meno), operatore @code{-}
+@cindex meno (@code{-}), operatore @code{-}
+@item @code{+ -}
+Addizione, sottrazione.
+
+@item Concatenazione di stringhe
+Non c'@`e un simbolo speciale per la concatenazione.
+Gli operandi sono semplicemente scritti uno accanto all'altro.
+(@pxref{Concatenazione}).
+
+@cindex @code{<} (parentesi acuta sinistra), operatore @code{<}
+@cindex parentesi acuta sinistra (@code{<}), operatore @code{<}
+@cindex @code{<} (parentesi acuta sinistra), operatore @code{<=}
+@cindex parentesi acuta sinistra (@code{<}), operatore @code{<=}
+@cindex @code{>} (parentesi acuta destra), operatore @code{>=}
+@cindex parentesi acuta destra (@code{>}), operatore @code{>=}
+@cindex @code{>} (parentesi acuta destra), operatore @code{>}
+@cindex parentesi acuta destra (@code{>}), operatore @code{>}
+@cindex @code{=} (uguale), operatore @code{==}
+@cindex uguale (@code{=}), operatore @code{==}
+@cindex @code{!} (punto esclamativo), operatore @code{!=}
+@cindex punto esclamativo (@code{!}), operatore @code{!=}
+@cindex @code{>} (parentesi acuta destra), operatore @code{>>} (I/O)
+@cindex parentesi acuta destra (@code{>}), operatore @code{>>} (I/O)
+@cindex operatori, input/output
+@cindex @code{|} (barra verticale), operatore @code{|} (I/O)
+@cindex barra verticale (@code{|}), operatore @code{|} (I/O)
+@cindex operatori, input/output
+@cindex @code{|} (barra verticale), operatore @code{|&} (I/O)
+@cindex barra verticale (@code{|}), operatore @code{|&} (I/O)
+@cindex operatori, input/output
+@item @code{< <= == != > >= >> | |&}
+Operatori relazionali e ridirezione.
+Gli operatori relazionali e le ridirezioni hanno lo stesso livello di
+precedenza. I caratteri come @samp{>} servono sia come operatori relazionali
+che come ridirezioni; la distinzione tra i due significati dipende dal
+contesto.
+
+@cindex istruzione @code{print}, operatori I/O nell'
+@cindex istruzione @code{printf}, operatori I/O nell'
+Si noti che gli operatori di ridirezione I/O nelle istruzioni @code{print} e
+@code{printf} appartengono al livello dell'istruzione, non alle espressioni.
+La ridirezione non produce un'espressione che potrebbe essere l'operando di un
+altro operatore. Di conseguenza, non ha senso usare un operatore di
+ridirezione vicino a un altro operatore con precedenza pi@`u bassa senza
+parentesi. Tali combinazioni generano errori di sintassi
+(p.es., @samp{print pippo > a ? b : c}).
+Il modo corretto di scrivere quest'istruzione @`e @samp{print pippo > (a ? b : c)}.
+
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+@item @code{~ !~}
+Corrispondenza, non corrispondenza.
+
+@cindex @code{in}, operatore
+@item @code{in}
+Appartenenza a un vettore.
+
+@cindex @code{&} (e commerciale), operatore @code{&&}
+@cindex e commerciale (@code{&}), operatore @code{&&}
+@item @code{&&}
+``and'' logico.
+
+@cindex @code{|} (barra verticale), operatore @code{||}
+@cindex barra verticale (@code{|}), operatore @code{||}
+@item @code{||}
+``or'' logico.
+
+@cindex @code{?} (punto interrogativo), operatore @code{?:}
+@cindex punto interrogativo (@code{?}), operatore @code{?:}
+@item @code{?:}
+Operatore condizionale. Questo operatore raggruppa da destra verso sinistra.
+
+@cindex @code{+} (pi@`u), operatore @code{+=}
+@cindex pi@`u (@code{+}), operatore @code{+=}
+@cindex @code{-} (meno), operatore @code{-=}
+@cindex meno (@code{-}), operatore @code{-=}
+@cindex @code{*} (asterisco), operatore @code{*=}
+@cindex asterisco (@code{*}), operatore @code{*=}
+@cindex @code{*} (asterisco), operatore @code{**=}
+@cindex asterisco (@code{*}), operatore @code{**=}
+@cindex @code{/} (barra), operatore @code{/=}
+@cindex barra (@code{/}), operatore @code{/=}
+@cindex @code{%} (percento), operatore @code{%=}
+@cindex percento (@code{%}), operatore @code{%=}
+@cindex @code{^} (circonflesso), operatore @code{^=}
+@cindex circonflesso (@code{^}), operatore @code{^=}
+@item @code{= += -= *= /= %= ^= **=}
+Assegnamento. Questi operatori raggruppano da destra verso sinistra.
+@end table
+
+@cindex POSIX @command{awk}, @code{**} e
+@cindex portabilit@`a, operatori, non in POSIX @command{awk}
+@quotation NOTA
+Gli operatori @samp{|&}, @samp{**} e @samp{**=} non sono definiti da POSIX.
+Per la massima portabilit@`a, @`e meglio non usarli.
+@end quotation
+
+@node Localizzazioni
+@section Il luogo fa la differenza
+@cindex localizzazione, definizione di
+
+I moderni sistemi prevedono la nozione di @dfn{localizzazione}: un modo per
+informare il sistema sulla serie di caratteri e sulla lingua locali.
+Lo standard ISO C definisce una localizzazione di default @code{"C"}, che @`e
+l'ambiente tipico a cui molti programmatori in C sono abituati.
+
+Un tempo, le impostazioni della localizzazione avevano influenza sulla
+ricerca di corrispondenze tramite @dfn{regexp}, ma ora non @`e pi@`u cos@`{@dotless{i}}
+(@pxref{Intervalli e localizzazione}).
+
+La localizzazione pu@`o influire sulla separazione dei record. Per il caso
+normale di @samp{RS = "\n"}, la localizzazione @`e generalmente irrilevante.
+Per altri separatori di record di un solo carattere, impostare
+la variabile d'ambiente @samp{LC_ALL=C}
+garantisce una migliore efficienza nella lettura dei record. Altrimenti,
+@command{gawk} dovrebbe fare diverse chiamate di funzione, @emph{per ogni
+carattere in input}, per determinare la fine del record.
+
+La localizzazione pu@`o influire sulla formattazione delle date e delle ore
+(@pxref{Funzioni di tempo}). Per esempio, un modo comune per abbreviare la
+data 4 settembre 2015, negli Stati Uniti @`e ``9/4/15.'' In molti paesi
+dell'Europa, invece, l'abbreviazione @`e "4.9.15". Quindi, la specifica di
+formato
+@code{%x} in una localizzazione @code{"US"} potrebbe produrre @samp{9/4/15},
+mentre in una localizzazione @code{"EUROPA"}, potrebbe produrre @samp{4.9.15}.
+
+Secondo POSIX, anche il confronto tra stringhe @`e influenzato dalla
+localizzazione (come nelle espressioni regolari). I dettagli sono descritti in
+@ref{Confronto POSIX di stringhe}.
+
+Infine, la localizzazione influenza il valore del separatore decimale
+usato quando @command{gawk} analizza i dati in input. Questo @`e stato
+trattato nel dettaglio in @ref{Conversione}.
+
+@node Sommario delle espressioni
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+Le espressioni sono gli elementi base dei calcoli eseguiti nei programmi.
+Sono costruite a partire da costanti, variabili, chiamate di funzione e dalla
+combinazione di vari tipi di valori tramite operatori.
+
+@item
+@command{awk} fornisce tre tipi di costanti: numerica, di stringa e
+di @dfn{regexp}. Le costanti numeriche in @command{gawk} si possono
+specificare nei sistemi ottale ed esadecimale (con base 8 e 16), e anche nel
+sistema decimale (base 10). In alcuni contesti, una costante @dfn{regexp}
+isolata come @code{/pippo/} ha lo stesso significato di @samp{$0 ~ /pippo/}.
+
+@item
+Le variabili contengono valori che possono essere usati diverse volte nei
+calcoli. Un certo numero di variabili predefinite forniscono informazioni al
+programma @command{awk}, mentre altre permettono il controllo del comportamento
+di @command{awk}.
+
+@item
+I numeri sono automaticamente convertiti in stringhe, e le stringhe in numeri,
+a seconda delle necessit@`a di @command{awk}. I valori numerici sono convertiti
+come se fossero formattati con @code{sprintf()} usando il formato contenuto in
+@code{CONVFMT}. La localizzazione pu@`o influire sulle conversioni.
+
+@item
+In @command{awk} ci sono gli operatori aritmetici di uso comune (addizione,
+sottrazione, moltiplicazione, divisione, modulo), e il pi@`u e il meno unari.
+Ci sono anche operatori di confronto, operatori booleani, una verifica
+dell'esistenza di una chiave in
+un vettore, e operatori per la ricerca di corrispondenze con espressioni
+regolari. La concatenazione di stringhe @`e effettuata mettendo due espressioni
+una vicino all'altra; non c'@`e nessun operatore esplicito.
+L'operatore con tre operandi @samp{?:} fornisce una verifica ``if-else''
+all'interno delle espressioni.
+
+@item
+Gli operatori di assegnamento forniscono delle comode forme brevi per le comuni
+operazioni aritmetiche.
+
+@item
+In @command{awk}, un valore @`e considerato vero se @`e diverso da zero
+@emph{oppure} non nullo. Altrimenti, il valore @`e falso.
+
+@item
+Il tipo di una variabile viene impostata a ogni assegnamento e pu@`o cambiare
+durante il suo ciclo di vita. Il tipo determina il comportamento della
+variabile nei confronti (di tipo stringa o numerici).
+
+@item
+Le chiamate di funzione restituiscono un valore che pu@`o essere usato come parte
+di un'espressione pi@`u lunga. Le espressioni usate per passare valori di
+parametro vengono valutate completamente prima di chiamare la funzione.
+@command{awk} fornisce funzioni predefinite e prevede quelle definite
+dall'utente; questo @`e descritto in
+@ref{Funzioni}.
+
+@item
+La precedenza degli operatori specifica l'ordine secondo il quale vengono
+effettuate le operazioni, a meno che quest'ordine non sia esplicitamente
+alterato
+tramite parentesi. Le regole di precedenza degli operatori di @command{awk}
+sono compatibili con quelle del linguaggio C.
+
+@item
+La localizzazione pu@`o influire sul formato dei dati in uscita da un programma
+@command{awk}, e occasionalmente sul formato dei dati letti in input.
+
+@end itemize
+
+@node Criteri di ricerca e azioni
+@chapter Criteri di ricerca, azioni e variabili
+@cindex criteri di ricerca
+@cindex @dfn{pattern}, si veda criteri di ricerca
+@cindex espressione di ricerca
+
+Come gi@`a visto, ogni istruzione @command{awk} consiste di un criterio di
+ricerca [@dfn{pattern}] a cui @`e associata un'azione. Questo @value{CHAPTER}
+descrive come specificare criteri e azioni, cosa @`e possibile
+fare tramite le azioni e quali sono le variabili predefinite in
+@command{awk}.
+
+Le regole @dfn{criterio di ricerca--azione} e le istruzioni che si possono
+dare all'interno delle azioni formano il nucleo centrale dei programmi
+scritti in @command{awk}.
+In un certo senso, tutto quanto si @`e visto finora costituisce le fondamenta
+sulle quali sono costruiti i programmi. @`E giunto il momento di iniziare a
+costruire qualcosa di utile.
+
+@menu
+* Panoramica sui criteri di ricerca:: Come scrivere un criterio di ricerca.
+* Usare variabili di shell:: come usare variabili della shell in
+ @command{awk}.
+* Panoramica sulle azioni:: Come scrivere un'azione.
+* Istruzioni:: Descrizione dettagliata delle varie
+ istruzioni di controllo.
+* Variabili predefinite:: Sommario delle variabili predefinite.
+* Sommario criteri e azioni:: Sommario di criteri di ricerca e azioni.
+@end menu
+
+@node Panoramica sui criteri di ricerca
+@section Elementi di un criterio di ricerca
+
+@menu
+* @dfn{regexp} come criteri di ricerca:: Usare espressioni regolari come
+ criteri di ricerca.
+* Espressioni come criteri di ricerca:: Qualsiasi espressione pu@`o servire da
+ criterio di ricerca.
+* Intervalli:: Coppie di espressioni regolari per
+ delimitare una ricerca.
+* BEGIN/END:: Specificare regole di inizio e fine programma.
+* BEGINFILE/ENDFILE:: Due condizioni speciali per controlli avanzati.
+* Vuoto:: Il criterio di ricerca vuoto, che
+ corrisponde a ogni record.
+@end menu
+
+@cindex criteri di ricerca, tipi di
+I criteri di ricerca in @command{awk} controllano l'esecuzione di
+azioni: un'azione viene eseguita
+quando il criterio di ricerca associato ad essa @`e soddisfatto dal
+record in input corrente.
+La tabella seguente @`e un sommario dei tipi di criteri di ricerca in
+@command{awk}:
+
+@table @code
+@item /@var{espressione regolare}/
+Un'espressione regolare. @`E verificata quando il testo di un
+record in input corrisponde all'espressione regolare.
+@iftex
+(@xrefIl{Espressioni regolari}.)
+@end iftex
+@ifnottex
+(@xref{Espressioni regolari}.)
+@end ifnottex
+
+@item @var{espressione}
+Una singola espressione. @`E verificata quando il suo valore @`e
+diverso da zero (se di tipo numerico) o non nullo (se @`e una stringa).
+(@xref{Espressioni come criteri di ricerca}.)
+
+@item @var{inizio_interv}, @var{fine_interv}
+Una coppia di criteri di ricerca separati da una virgola, che specificano un
+@dfn{intervallo} di record.
+L'intervallo comprende sia il record iniziale che corrisponde a @var{inizio_interv}
+sia il record finale che corrisponde a @var{fine_interv}.
+(@xref{Intervalli}.)
+
+@item BEGIN
+@itemx END
+Criteri di ricerca speciali che consentono azioni di inizializzazione o
+di pulizia in un programma @command{awk}.
+(@xref{BEGIN/END}.)
+
+@item BEGINFILE
+@itemx ENDFILE
+Criteri di ricerca speciali che consentono azioni di inizializzazione o di
+pulizia da eseguire all'inizio o alla fine di ogni file in input.
+(@xref{BEGINFILE/ENDFILE}.)
+
+@item @var{vuoto}
+Il criterio di ricerca vuoto corrisponde a ciascun record in input.
+(@xref{Vuoto}.)
+@end table
+
+@node @dfn{regexp} come criteri di ricerca
+@subsection Espressioni regolari come criteri di ricerca
+@cindex criteri di ricerca, espressioni come
+@cindex espressioni regolari, come criteri di ricerca
+
+Le espressioni regolari sono uno dei primi tipi di criteri di ricerca
+presentati in questo @value{DOCUMENT}.
+Questo tipo di criterio di ricerca @`e semplicemente una costante @dfn{regexp}
+posta nella parte @dfn{criterio di ricerca} di una regola. Equivale a
+scrivere @samp{$0 ~ /@var{criterio di ricerca}/}.
+Il criterio di ricerca @`e verificato quando il record in input corrisponde
+alla @dfn{regexp}.
+Per esempio:
+
+@example
+/pippo|pluto|paperino/ @{ personaggi_Disney++ @}
+END @{ print personaggi_Disney, "Personaggi Disney visti" @}
+@end example
+
+@node Espressioni come criteri di ricerca
+@subsection Espressioni come criteri di ricerca
+@cindex espressioni regolari, come criteri di ricerca
+
+Qualsiasi espressione @command{awk} pu@`o essere usata come un criterio di
+ricerca @command{awk}.
+Il criterio di ricerca @`e verificato se il valore dell'espressione @`e diverso
+da zero (se @`e un numero), o non nullo (se @`e una stringa).
+L'espressione @`e ricalcolata ogni volta che la regola viene applicata a un
+nuovo record in input. Se l'espressione usa campi come @code{$1}, il suo
+valore dipende direttamente dal contenuto del record in input appena letto;
+altrimenti, dipende solo da quel che @`e accaduto fino a quel momento durante
+l'esecuzione del programma @command{awk}.
+
+@cindex espressioni di confronto, come criteri di ricerca
+@cindex criteri di ricerca, espressioni di confronto come
+Le espressioni di confronto, che usano gli operatori di confronto descritti in
+@ref{Tipi di variabile e confronti},
+sono un tipo di criterio di ricerca usato frequentemente.
+Anche le @dfn{regexp}, verificate o non verificate, sono tipi di espressioni molto frequenti.
+L'operando a sinistra degli operatori @samp{~} e @samp{!~} @`e una stringa.
+L'operando di destra @`e un'espressione regolare costante delimitata da
+barre (@code{/@var{@dfn{regexp}}/}) o qualsiasi espressione il cui valore come
+stringa @`e usato come un'espressione regolare dinamica
+(@pxref{Espressioni regolari calcolate}).
+L'esempio seguente stampa il secondo campo di ogni record in input
+il cui primo campo sia esattamente @samp{li}:
+
+@cindex @code{/} (barra), criteri di ricerca e
+@cindex barra (@code{/}), criteri di ricerca e
+@cindex @code{~} (tilde), operatore @code{~}
+@cindex tilde (@code{~}), operatore @code{~}
+@cindex @code{!} (punto esclamativo), operatore @code{!~}
+@cindex punto esclamativo (@code{!}), operatore @code{!~}
+@example
+$ @kbd{awk '$1 == "li" @{ print $2 @}' mail-list}
+@end example
+
+@noindent
+(Il programma non stampa alcun output, perch@'e nessuna persona ha come nome esattamente @samp{li}.)
+Si veda la differenza con il seguente confronto di espressione regolare, che
+individua invece qualsiasi record il cui primo campo @emph{contenga} @samp{li}:
+
+@example
+$ @kbd{awk '$1 ~ /li/ @{ print $2 @}' mail-list}
+@print{} 555-5553
+@print{} 555-6699
+@end example
+
+@cindex @dfn{regexp}, costanti, come criteri di ricerca
+@cindex criteri di ricerca, costanti @dfn{regexp} come
+Una costante @dfn{regexp} usata come criterio di ricerca @`e anche un
+caso speciale di criterio di ricerca costituito da un'espressione.
+All'espressione @code{/li/} viene assegnato il valore uno se @samp{li}
+viene trovato nel record in input corrente. Quindi, come criterio di ricerca,
+@code{/li/} individua tutti i record che contengono la stringa @samp{li}.
+
+@cindex espressioni booleane, come criteri di ricerca
+Anche le espressioni booleane sono frequentemente usate come criteri di
+ricerca. Se un criterio di ricerca
+individua o no un record in input dipende dalla verifica delle
+sottoespressioni da cui @`e composto.
+Per esempio, il seguente comando stampa tutti i record in
+@file{mail-list} che contengono sia @samp{edu} che @samp{li}:
+
+@example
+$ @kbd{awk '/edu/ && /li/' mail-list}
+@print{} Samuel 555-3430 samuel.lanceolis@@shu.edu A
+@end example
+
+Il seguente comando stampa tutti i record in
+@file{mail-list} che contengono @samp{edu} @emph{oppure} @samp{li}
+(o entrambi, naturalmente):
+
+@example
+$ @kbd{awk '/edu/ || /li/' mail-list}
+@print{} Amelia 555-5553 amelia.zodiacusque@@gmail.com F
+@print{} Broderick 555-0542 broderick.aliquotiens@@yahoo.com R
+@print{} Fabius 555-1234 fabius.undevicesimus@@ucb.edu F
+@print{} Julie 555-6699 julie.perscrutabor@@skeeve.com F
+@print{} Samuel 555-3430 samuel.lanceolis@@shu.edu A
+@print{} Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R
+@end example
+
+Il seguente comando stampa tutti i record in
+@file{mail-list} che @emph{non} contengono la stringa @samp{li}:
+
+@example
+$ @kbd{awk '! /li/' mail-list}
+@print{} Anthony 555-3412 anthony.asserturo@@hotmail.com A
+@print{} Becky 555-7685 becky.algebrarum@@gmail.com A
+@print{} Bill 555-1675 bill.drowning@@hotmail.com A
+@print{} Camilla 555-2912 camilla.infusarum@@skynet.be R
+@print{} Fabius 555-1234 fabius.undevicesimus@@ucb.edu F
+@print{} Martin 555-6480 martin.codicibus@@hotmail.com A
+@print{} Jean-Paul 555-2127 jeanpaul.campanorum@@nyu.edu R
+@end example
+
+@cindex @code{BEGIN}, criterio di ricerca, criteri di ricerca booleani e
+@cindex @code{END}, criterio di ricerca, criteri di ricerca booleani e
+@cindex @code{BEGINFILE}, criterio di ricerca, criteri di ricerca booleani e
+@cindex @code{ENDFILE}, criterio di ricerca, criteri di ricerca booleani e
+Le sottoespressioni di un'operatore booleano in un criterio di ricerca possono
+essere espressioni regolari costanti, confronti, o qualsiasi altra espressione
+di @command{awk}. Gli intervalli di ricerca
+non sono espressioni, e quindi non possono apparire all'interno di
+criteri di ricerca booleani. Analogamente, i criteri di ricerca speciali
+@code{BEGIN}, @code{END}, @code{BEGINFILE} ed @code{ENDFILE},
+che non corrispondono ad alcun record in input, non sono espressioni e non
+possono essere usati all'interno di criteri di ricerca booleani.
+
+L'ordine di precedenza dei differenti operatori che possono essere usati nei
+criteri di ricerca @`e descritto in @ref{Precedenza}.
+
+@node Intervalli
+@subsection Specificare intervalli di record con i criteri di ricerca
+
+@cindex intervalli di ricerca
+@cindex criteri di ricerca, intervalli nei
+@cindex righe, individuare intervalli di
+@cindex @code{,} (virgola), negli intervalli di ricerca
+@cindex virgola (@code{,}), negli intervalli di ricerca
+Un @dfn{intervallo di ricerca} @`e composto da due criteri di ricerca
+separati da una virgola, nella forma
+@samp{@var{inizio_intervallo}, @var{fine_intervallo}}. @`E usato per
+individuare
+una serie di record consecutivi nei file in input. Il primo criterio di
+ricerca, @var{inizio_intervallo}, controlla dove inizia la serie di record,
+mentre @var{fine_intervallo} controlla dove finisce la serie stessa.
+L'esempio seguente:
+
+@example
+awk '$1 == "on", $1 == "off"' miofile
+@end example
+
+@noindent
+stampa ogni record in @file{miofile} incluso tra i due record che iniziano con
+@samp{on}/@samp{off}, estremi compresi.
+
+Un intervallo di ricerca inizia con la valutazione di
+@var{inizio_intervallo} per ogni record in input. Quando un record soddisfa
+la condizione @var{inizio_intervallo}, l'intervallo di ricerca @`e
+@dfn{attivato} e l'intervallo di ricerca include anche quel
+record. Finch@'e l'intervallo di ricerca rimane attivo,
+automaticamente vengono trovate corrispondenze in ogni record in input letto.
+L'intervallo di ricerca verifica anche @var{fine_intervallo} per ogni
+record in input; quando la verifica ha successo, il
+criterio di ricerca viene @dfn{disattivato} a partire dal record seguente.
+Quindi il criterio di ricerca torna a controllare
+@var{inizio_intervallo} per ogni nuovo record.
+
+@cindex @code{if}, istruzione, azioni@comma{} modificabili
+Il record che segnala l'inizio dell'intervallo
+di ricerca e quello che segnala la fine di quell'intervallo soddisfano
+@emph{entrambi} il criterio di ricerca. Se non si vuole agire su tali record
+si possono scrivere istruzioni @code{if} nella parte @dfn{azione} della regola
+per distinguerli dai record che il programma @`e interessato a trattare.
+
+@`E possibile che un criterio di ricerca sia attivato e disattivato dallo
+stesso record. Se il record soddisfa entrambe le condizioni, l'azione @`e
+eseguita solo su quel record.
+Per esempio, si supponga che ci sia un testo tra due separatori identici
+(p.es., il simbolo @samp{%}), ognuno dei quali sia su una riga a parte, che
+dovrebbero essere ignorati. Un primo tentativo potrebbe essere quello di
+combinare un intervallo di ricerca che descrive il
+testo delimitato con l'istruzione
+@code{next}
+(non ancora introdotta, @pxref{Istruzione next}).
+Con quest'istruzione @command{awk} non effettua alcuna azione sul record
+corrente e inizia di nuovo a elaborare il successivo record in input.
+Un tale programma @`e simile a questo:
+
+@example
+/^%$/,/^%$/ @{ next @}
+ @{ print @}
+@end example
+
+@noindent
+@cindex righe, saltare tra delimitatori
+@c @cindex @dfn{flag} variables
+Questo programma non funziona, perch@'e l'intervallo di ricerca @`e sia attivato
+che disattivato dalla prima riga incontrata, quella costituita da un @samp{%}.
+Per ottenere l'effetto desiderato, si scriva il programma nella maniera che
+segue, utilizzando un @dfn{flag}:
+
+@cindex @code{!} (punto esclamativo), operatore @code{!}
+@cindex punto esclamativo (@code{!}), operatore @code{!}
+@example
+/^%$/ @{ ignora = ! ignora; next @}
+ignora == 1 @{ next @} # ignora righe quando `ignora' @`e impostato a 1
+@end example
+
+In un intervallo di ricerca, la virgola (@samp{,}) ha la
+precedenza pi@`u bassa tra tutti gli operatori (cio@`e, @`e l'ultima a essere
+valutata). Il programma seguente tenta di combinare un intervallo di
+ricerca con un altro controllo, pi@`u semplice:
+
+@example
+echo Yes | awk '/1/,/2/ || /Yes/'
+@end example
+
+L'intenzione in questo programma @`e quello di esprimere le condizioni
+@samp{(/1/,/2/) || /Yes/}.
+Tuttavia, @command{awk} lo interpreta come se fosse
+@samp{/1/, (/2/ || /Yes/)}.
+Questo comportamento non pu@`o essere cambiato o evitato; gli intervalli di
+ricerca non si possono combinare con altri criteri di ricerca:
+
+@example
+$ @kbd{echo Yes | gawk '(/1/,/2/) || /Yes/'}
+@error{} gawk: riga com.:1: (/1/,/2/) || /Yes/
+@error{} gawk: riga com.:1: ^ syntax error
+@end example
+
+@cindex intervalli di ricerca, continuazione di riga e
+Come punto di secondaria importanza, nonostante sia stilisticamente poco elegante,
+lo standard POSIX consente di andare a capo dopo la virgola
+in un intervallo di ricerca. @value{DARKCORNER}
+@node BEGIN/END
+@subsection I criteri di ricerca speciali @code{BEGIN} ed @code{END}
+
+@cindex @code{BEGIN}, criterio di ricerca
+@cindex @code{END}, criterio di ricerca
+@cindex criterio di ricerca @code{END}
+Tutti i criteri di ricerca fin qui descritti servono a individuare dei record
+in input.
+I criteri di ricerca speciali @code{BEGIN} ed @code{END} non hanno questo scopo.
+Servono invece per effettuare azioni di inizializzazione o di pulizia nei
+programmi @command{awk}.
+Le regole @code{BEGIN} ed @code{END} devono prevedere azioni; non c'@`e
+un'azione di default per queste regole, perch@'e non c'@`e un record corrente
+quando sono invocate.
+Le regole @code{BEGIN} ed @code{END} sono spesso chiamate
+``blocchi @code{BEGIN} ed @code{END}'' da programmatori che usano @command{awk}
+da molto tempo.
+
+@menu
+* Usare BEGIN/END:: Come e perch@'e usare regole BEGIN/END.
+* I/O e BEGIN/END:: Problemi di I/O nelle regole BEGIN/END.
+@end menu
+
+@node Usare BEGIN/END
+@subsubsection Azioni di inizializzazione e pulizia
+
+@cindex @code{BEGIN}, criterio di ricerca
+@cindex criterio di ricerca @code{BEGIN}
+@cindex @code{END}, criterio di ricerca
+@cindex criterio di ricerca @code{END}
+Una regola @code{BEGIN} @`e eseguita solo una volta, prima che sia letto il
+primo record in input. Analogamente, una regola @code{END} @`e eseguita
+solo una volta, dopo che tutto l'input @`e gi@`a stato letto. Per esempio:
+
+@example
+$ @kbd{awk '}
+> @kbd{BEGIN @{ print "Analisi di \"li\"" @}}
+> @kbd{/li/ @{ ++n @}}
+> @kbd{END @{ print "\"li\" @`e presente in", n, "record." @}' mail-list}
+@print{} Analisi di "li"
+@print{} "li" @`e presente in 4 record.
+@end example
+
+@cindex @code{BEGIN}, criterio di ricerca, operatori e
+@cindex @code{END}, criterio di ricerca, operatori e
+@cindex criterio di ricerca @code{END}, operatori e
+Questo programma trova il numero di record nel file in input
+@file{mail-list} che contengono la stringa @samp{li}. La regola @code{BEGIN}
+stampa un titolo per il rapporto. Non c'@`e bisogno di usare la regola
+@code{BEGIN} per inizializzare il contatore @code{n} a zero, poich@'e
+@command{awk} lo fa
+automaticamente (@pxref{Variabili}).
+La seconda regola incrementa la variabile @code{n} ogni volta che si legge
+un record che soddisfa il criterio di ricerca @samp{li}. La regola @code{END}
+stampa il valore di @code{n} alla fine del programma.
+
+I criteri di ricerca speciali @code{BEGIN} ed @code{END} non possono essere
+usati negli intervalli,
+o con operatori booleani (in effetti, non possono essere combinati con nessun
+altro operatore).
+Un programma @command{awk} pu@`o avere molte regole @code{BEGIN} e/o @code{END}.
+Queste sono eseguite nell'ordine in cui compaiono nel programma: tutte le
+regole @code{BEGIN} a inizio programma e tutte le regole @code{END}
+a fine programma.
+Le regole @code{BEGIN} ed @code{END} possono apparire in qualsiasi
+posizione all'interno del programma.
+Questa funzionalit@`a @`e stata aggiunta nella versione 1987 di @command{awk} ed
+@`e inclusa nello standard POSIX.
+La versione originale (1978) di @command{awk} richiedeva che la regola
+@code{BEGIN} fosse posta all'inizio del programma, e la regola
+@code{END} alla fine del programma, e solo una regola per tipo era ammessa.
+Ci@`o non @`e pi@`u obbligatorio, ma @`e una buona idea continuare a seguire questo
+modello per migliorare l'organizzazione e la leggibilit@`a del programma.
+
+Regole multiple @code{BEGIN} ed @code{END} sono utili per scrivere funzioni
+di libreria, poich@'e ogni file di libreria pu@`o avere la sua propria regola
+@code{BEGIN} e/o @code{END} per fare la propria inizializzazione e/o pulizia.
+L'ordine in cui le funzioni di libreria sono menzionate nella riga dei comandi
+determina l'ordine in cui le rispettive regole @code{BEGIN} ed @code{END} sono
+eseguite. Per questo motivi, occorre prestare attenzione nello scrivere tali
+regole nei file di libreria, in modo che non sia importante
+l'ordine in cui tali regole vengono eseguite.
+@xref{Opzioni} per maggiori informazioni sull'uso di funzioni di libreria.
+@iftex
+@xrefil{Funzioni di libreria},
+@end iftex
+@ifnottex
+@xref{Funzioni di libreria},
+@end ifnottex
+per parecchie utili funzioni di libreria.
+
+Se un programma @command{awk} ha solo regole @code{BEGIN} e nessun'altra
+regola, il programma esce dopo aver eseguito le regole
+@code{BEGIN}.@footnote{La versione originale di @command{awk} continuava a
+leggere e ignorare i record in input fino alla fine del file.} Tuttavia, se
+una regola @code{END} esiste, l'intero input @`e letto, anche se non sono
+presenti altre regole nel programma. Ci@`o viene fatto necessariamente
+per permettere che
+la regola @code{END} faccia uso delle variabili @code{FNR} e @code{NR}.
+
+@node I/O e BEGIN/END
+@subsubsection Input/Output dalle regole @code{BEGIN} ed @code{END}
+
+@cindex input/output, dalle regole @code{BEGIN} ed @code{END}
+Ci sono parecchi punti (talora insidiosi) da tener presente se si fa dell'I/O
+all'interno di una regola @code{BEGIN} o @code{END}.
+Il primo ha a che fare con il valore di @code{$0} in una regola @code{BEGIN}.
+Poich@'e le regole @code{BEGIN} sono eseguite prima delle lettura di qualsiasi
+input, non c'@`e assolutamente alcun record in input, e quindi nessun campo,
+quando si eseguono delle regole @code{BEGIN}. I riferimento a @code{$0} e ai
+campi restituiscono una stringa nulla o zero, a seconda del contesto.
+Un modo per assegnare un valore effettivo a @code{$0} @`e di eseguire un
+comando @code{getline} senza indicare una variabile (@pxref{Getline}).
+Un altro modo @`e semplicemente quello di assegnare un valore a @code{$0}.
+
+@cindex Brian Kernighan, @command{awk} di
+@cindex differenze tra @command{awk} e @command{gawk}, criteri di ricerca @code{BEGIN}/@code{END}
+@cindex POSIX @command{awk}, criteri di ricerca @code{BEGIN}/@code{END}
+@cindex @code{print}, istruzione, criteri di ricerca @code{BEGIN}/@code{END} e
+@cindex @code{BEGIN}, criterio di ricerca, istruzione @code{print} e
+@cindex @code{END}, criterio di ricerca, istruzione @code{print} e
+Il secondo punto @`e simile al primo, ma in direzione opposta.
+Tradizionalmente, pi@`u che altro per problemi di implementazione, @code{$0}
+e @code{NF} erano @emph{indefiniti} all'interno di una regola @code{END}.
+Lo standard POSIX prescrive che @code{NF} sia disponibile all'interno di una
+regola @code{END}. Contiene il numero di campi dell'ultimo record in input.
+Probabilmente per una svista, lo standard non specifica che @`e reso
+disponibile anche @code{$0}, sebbene possa apparire logico che sia cos@`{@dotless{i}}.
+In effetti, BWK @command{awk}, @command{mawk} e @command{gawk} mantengono il
+valore di @code{$0} in modo che sia possibile usarlo all'interno delle regole
+@code{END}. Occorre peraltro tener presente che alcune altre implementazioni
+e parecchie tra le versioni pi@`u vecchie di Unix @command{awk} non si
+comportano cos@`{@dotless{i}}.
+
+Il terzo punto @`e una conseguenza dei primi due. Il significato di
+@samp{print}
+all'interno di una regola @code{BEGIN} o @code{END} @`e quello di sempre:
+@samp{print $0}. Se @code{$0} @`e la stringa nulla, stampa una riga vuota.
+Molti programmatori di lungo corso di @command{awk} usano un semplice
+@samp{print} all'interno delle regole @code{BEGIN} ed @code{END},
+intendendo @samp{@w{print ""}}, contando sul fatto che @code{$0} sia una
+stringa nulla. Sebbene questo funzioni solitamente con le regole
+@code{BEGIN}, @`e una pessima idea nelle regole @code{END},
+almeno in @command{gawk}. @`E anche stilisticamente inelegante, perch@'e se
+serve una riga vuota in output, il programma dovrebbe stamparne
+una esplicitamente.
+
+@cindex @code{next}, istruzione, criteri di ricerca @code{BEGIN}/@code{END} e
+@cindex @code{nextfile}, istruzione, criteri di ricerca @code{BEGIN}/@code{END} e
+@cindex @code{BEGIN}, criterio di ricerca, istruzioni @code{next}/@code{nextfile} e
+@cindex @code{END}, criterio di ricerca, istruzioni @code{next}/@code{nextfile} e
+Per finire, le istruzioni @code{next} e @code{nextfile} non sono consentite
+all'interno di una regola @code{BEGIN}, perch@'e il ciclo implicito
+leggi-un-record-e-confrontalo-con-le-regole non @`e ancora iniziato.
+Analogamente, tali istruzioni non sono valide all'interno di una regola
+@code{END}, perch@'e tutto l'input @`e gi@`a stato letto.
+(@xref{Istruzione next} e
+@ifnotdocbook
+@pxref{Istruzione nextfile}.)
+@end ifnotdocbook
+@ifdocbook
+@ref{Istruzione nextfile}.)
+@end ifdocbook
+
+@node BEGINFILE/ENDFILE
+@subsection I criteri di ricerca speciali @code{BEGINFILE} ed @code{ENDFILE}
+@cindex @code{BEGINFILE}, criterio di ricerca
+@cindex @code{ENDFILE}, criterio di ricerca
+@cindex differenze tra @command{awk} e @command{gawk}, criteri di ricerca @code{BEGINFILE}/@code{ENDFILE}
+
+Questa @value{SECTION} descrive una funzionalit@`a specifica di @command{gawk}.
+
+Due tipi speciali di criterio di ricerca, @code{BEGINFILE} ed @code{ENDFILE},
+forniscono
+degli ``agganci'' per intervenire durante il ciclo di elaborazione dei file
+specificati sulla riga di comando di @command{gawk}.
+Come con le regole @code{BEGIN} ed @code{END}
+@ifnottex
+@ifnotdocbook
+(@pxref{BEGIN/END}),
+@end ifnotdocbook
+@end ifnottex
+@iftex
+(si veda la @value{SECTION} precedente),
+@end iftex
+@ifdocbook
+(si veda la @value{SECTION} precedente),
+@end ifdocbook
+tutte le regole @code{BEGINFILE} in un programma sono riunite, mantenendole
+nell'ordine in cui sono lette da @command{gawk} e lo stesso viene fatto
+per tutte le regole @code{ENDFILE}.
+
+Il corpo delle regole @code{BEGINFILE} @`e eseguito subito prima che
+@command{gawk} legga il primo record da un file. La variabile @code{FILENAME}
+@`e impostata al nome del file corrente e @code{FNR} @`e impostata a zero.
+
+La regola @code{BEGINFILE} d@`a la possibilit@`a di eseguire due compiti
+che sarebbe difficile o impossibile effettuare altrimenti:
+
+@itemize @value{BULLET}
+@item
+Si pu@`o verificare che il file sia leggibile. Di solito, se un file presente
+nella riga dei comandi non pu@`o essere aperto in lettura, il programma
+@command{gawk} viene terminato. Comunque, questo si pu@`o evitare, per poi
+passare a elaborare il file successivo specificato sulla riga dei comandi.
+
+@cindex @command{gawk}, variabile @code{ERRNO} in
+@cindex @code{ERRNO}, variabile, con criterio di ricerca @code{BEGINFILE}
+@cindex @code{nextfile}, istruzione, criteri di ricerca @code{BEGINFILE}/@code{ENDFILE} e
+Questo controllo @`e fattibile controllando se la variabile @code{ERRNO} @`e
+diversa dalla stringa nulla; se @`e questo il caso, @command{gawk} non @`e
+riuscito ad aprire il file. In questo caso il programma pu@`o eseguire
+un'istruzione @code{nextfile}
+(@pxref{Istruzione nextfile}). In questo modo @command{gawk} salta
+completamente l'elaborazione di quel file.
+In caso contrario, @command{gawk} termina come al solito con un
+errore fatale.
+
+@item
+Se sono state scritte estensioni che modificano la gestione del record
+(tramite l'inserzione di un ``analizzatore di input'';
+@pxref{Analizzatori di input}), @`e possibile richiamarle
+a questo punto, prima che @command{gawk} inizi a elaborare il file.
+(Questa @`e una funzionalit@`a @emph{molto} avanzata, usata al momento solo dal
+@uref{http://sourceforge.net/projects/gawkextlib, progetto @code{gawkextlib}}.)
+@end itemize
+
+La regola @code{ENDFILE} @`e chiamata quando @command{gawk} ha finito di
+elaborare l'ultimo record di un file in input. Per l'ultimo file in input,
+@`e chiamata prima di ogni regola @code{END}.
+La regola @code{ENDFILE} @`e eseguita anche per file in input vuoti.
+
+Normalmente, se si verifica un errore di lettura durante il normale
+ciclo di elaborazione dell'input,
+questo @`e considerato fatale (il programma termina). Tuttavia, se @`e presente
+una regola @code{ENDFILE}, l'errore non @`e considerato fatale, ma viene
+impostato @code{ERRNO}. Ci@`o permette di intercettare ed elaborare errori
+di I/O a livello di programma @command{awk}.
+
+@cindex @code{next}, istruzione, criteri di ricerca @code{BEGINFILE}/@code{ENDFILE} e
+L'istruzione @code{next} (@pxref{Istruzione next}) non @`e permessa all'interno
+di una regola @code{BEGINFILE} o @code{ENDFILE}. L'istruzione @code{nextfile}
+@`e consentita solo all'interno di una regola @code{BEGINFILE}, non all'interno
+di una regola @code{ENDFILE}.
+
+@cindex @code{getline}, comando, criteri di ricerca @code{BEGINFILE}/@code{ENDFILE} e
+L'istruzione @code{getline} (@pxref{Getline}) @`e limitata all'interno sia di
+@code{BEGINFILE} che di @code{ENDFILE}: solo le forme ridirette di
+di @code{getline} sono permesse.
+
+@code{BEGINFILE} ed @code{ENDFILE} sono estensioni @command{gawk}.
+In molte altre implementazioni di @command{awk} o se @command{gawk} @`e in
+modalit@`a compatibile (@pxref{Opzioni}), non sono regole speciali.
+
+@c FIXME: For 4.2 maybe deal with this?
+@ignore
+Date: Tue, 17 May 2011 02:06:10 PDT
+From: rankin@pactechdata.com (Pat Rankin)
+Message-Id: <110517015127.20240f4a@pactechdata.com>
+Subject: BEGINFILE
+To: arnold@skeeve.com
+
+ The documentation for BEGINFILE states that FNR is 0, which seems
+pretty obvious. It doesn't mention what the value of $0 is, and that's
+not obvious. I think setting it to null before starting the BEGINFILE
+action would be preferable to leaving whatever was there in the last
+record of the previous file.
+
+ ENDFILE can retain the last record in $0. I guess it has to if
+the END rule's actions see that value too. But the beginning of a new
+file doesn't just mean that the old one has been closed; the old file
+is being superseded, so leaving the old data around feels wrong to me.
+[If the user wants to keep it on hand, he or she can use an ENDFILE
+rule to grab it before moving on to the next file.]
+@end ignore
+
+@node Vuoto
+@subsection Il criterio di ricerca vuoto
+
+@cindex vuoto, criterio di ricerca
+@cindex criteri di ricerca vuoti
+Un criterio di ricerca vuoto (cio@`e omesso) corrisponde a
+@emph{ogni} record in input. Per esempio, il programma:
+
+@example
+awk '@{ print $1 @}' mail-list
+@end example
+
+@noindent
+stampa il primo campo di ogni record.
+
+@node Usare variabili di shell
+@section Usare variabili di shell in programmi
+@cindex shell, variabili di
+@cindex programmi @command{awk}, variabili di shell in
+@c @cindex shell and @command{awk} interaction
+
+I programmi @command{awk} sono spesso usati come componenti di programmi pi@`u
+ampi, scritti in un linguaggio di shell.
+Per esempio, @`e molto comune usare una variabile di shell per
+specificare un criterio di ricerca che il programma @command{awk} deve poi
+individuare.
+Ci sono due modi per rendere disponibile il valore di una variabile di shell
+all'interno di un programma @command{awk}.
+
+@cindex shell, uso di doppio apice
+Un modo comune @`e quello di usare i doppi apici per sostituire il valore della
+variabile nel progamma @command{awk} contenuto nello @dfn{script}:
+
+Per esempio, si consideri il programma seguente:
+
+@example
+printf "Immettere il criterio di ricerca: "
+read criterio_di_ricerca
+awk "/$criterio_di_ricerca/ "'@{ num_trov++ @}
+ END @{ print num_trov, "occorrenze trovate" @}' /nome/file/dati
+@end example
+
+@noindent
+Il programma @command{awk} consiste di due pezzi di testo tra apici
+che, concatenati insieme, formano il programma.
+La prima parte @`e tra doppi apici, per consentire la sostituzione della
+variabile di shell @code{criterio_di_ricerca} contenuta al loro interno.
+La seconda parte @`e racchiusa tra apici singoli.
+
+La sostituzione di variabile attraverso gli apici funziona, ma pu@`o
+facilmente generare difficolt@`a. Richiede una buona comprensione delle
+regole per l'uso degli apici nella shell
+(@pxref{Protezione}),
+e spesso @`e difficile accoppiare i vari apici quando si legge il programma.
+
+Un metodo migliore @`e quello di usare la funzionalit@`a di assegnamento delle
+variabili di @command{awk}
+(@pxref{Opzioni di assegnamento})
+per assegnare il valore di una variabile di shell a una variabile
+di @command{awk}.
+Poi si possono usare @dfn{regexp} dinamiche come criterio di ricerca
+(@pxref{Espressioni regolari calcolate}).
+Quanto segue mostra come sarebbe l'esempio precedente usando questa tecnica:
+
+@example
+printf "Immettere il criterio di ricerca: "
+read criterio_di_ricerca
+awk -v crit="$criterio_di_ricerca" '$0 ~ crit @{ num_trov++ @}
+ END @{ print num_trov, "occorrenze trovate" @}' /nome/file/dati
+@end example
+
+@noindent
+Adesso il programma @command{awk} @`e solo una stringa tra apici semplici.
+L'assegnamento @samp{-v crit="$criterio_di_ricerca"} richiede ancora doppi
+apici, per il caso in cui uno spazio vuoto sia presente nel valore di
+@code{$criterio_di_ricerca}.
+La variabile @command{awk} @code{crit} potrebbe avere come nome anche
+@code{criterio_di_ricerca}, ma ci@`o potrebbe essere causa di confusione.
+Usare una variabile permette una maggiore flessibilit@`a, poich@'e la variabile
+pu@`o essere usata in ogni parte del
+programma---per stamparla, per indicizzare un vettore, o per qualsiasi altro
+scopo---senza che sia necessario l'artificio di doverla inserire usando gli
+apici.
+
+@node Panoramica sulle azioni
+@section Azioni
+@c @cindex action, definition of
+@c @cindex curly braces
+@c @cindex action, curly braces
+@c @cindex action, separating statements
+@cindex azioni
+
+Un programma o script @command{awk} consiste in una serie di
+regole e definizioni di funzione frammiste tra loro. (Le funzioni sono
+descritte pi@`u avanti. @xref{Funzioni definite dall'utente}.)
+Una regola contiene un criterio di ricerca e un'azione; l'uno o l'altra
+(ma non tutt'e due) possono essere omessi. Lo scopo di una @dfn{azione} @`e
+di specificare cosa deve fare @command{awk} quando si trova una corrispondenza
+con il criterio di ricerca. Quindi, schematicamente, un programma
+@command{awk} @`e normalmente simile a questo:
+
+@display
+[@var{criterio di ricerca}] @code{@{ @var{azione} @}}
+ @var{criterio di ricerca} [@code{@{ @var{azione} @}}]
+@dots{}
+@code{function @var{nome}(@var{argomenti}) @{ @dots{} @}}
+@dots{}
+@end display
+
+@cindex @code{@{@}} (parentesi graffe), azioni e
+@cindex parentesi graffe (@code{@{@}}), azioni e
+@cindex separatori, per istruzioni in azioni
+@cindex a capo, separatore di istruzioni nelle azioni
+@cindex @code{;} (punto e virgola), separare istruzioni nelle azioni
+@cindex punto e virgola (@code{;}), separare istruzioni nelle azioni
+Un'azione consiste di una o pi@`u @dfn{istruzioni} @command{awk}, racchiuse
+fra parentesi graffe (@samp{@{@r{@dots{}}@}}). Ogni istruzione specifica
+una cosa da fare. Le istruzioni sono separate tra loro da dei ritorni a capo o
+da dei punti e virgola.
+Le parentesi graffe attorno a un'azione vanno usate anche se l'azione
+contiene una sola istruzione o se non contiene alcuna istruzione.
+Comunque, se si omette completamente l'azione, si possono omettere anche le
+parentesi graffe. Un'azione omessa @`e equivalente a specificare
+@samp{@{ print $0 @}}:
+
+@example
+/pippo/ @{ @} @ii{se si trova @code{pippo}, non fare nulla --- azione vuota}
+/pippo/ @ii{se si trova @code{pippo}, stampa il record --- azione omessa}
+@end example
+
+I seguenti tipi di istruzione sono disponibili in @command{awk}:
+
+@table @asis
+@cindex effetti collaterali delle istruzioni
+@cindex istruzioni, effetti collaterali delle
+@item Espressioni
+Servono per chiamare funzioni o assegnare valori a variabili
+@iftex
+(@pxrefil{Espressioni}). L'esecuzione
+@end iftex
+@ifnottex
+(@pxref{Espressioni}). L'esecuzione
+@end ifnottex
+di questo tipo di istruzione calcola semplicemente il valore dell'espressione.
+Ci@`o @`e utile quando l'espressione ha effetti collaterali
+(@pxref{Operatori di assegnamento}).
+
+@item Istruzioni di controllo
+Specificano il flusso di controllo dei programmi @command{awk}.
+Il linguaggio @command{awk} utilizza dei costrutti simili a quelli del C,
+(@code{if}, @code{for}, @code{while} e @code{do}), e anche alcune altre
+di tipo speciale (@pxref{Istruzioni}).
+
+@item Istruzioni composte
+Sono una o pi@`u istruzioni racchiuse tra parentesi graffe. Un'istruzione
+composta
+@`e usata per riunire un gruppo di istruzioni all'interno di
+un'istruzione @code{if}, @code{while}, @code{do} o @code{for}.
+
+@item Istruzioni di input
+Usano il comando @code{getline}
+(@pxref{Getline}).
+In @command{awk} sono anche disponibili le istruzioni @code{next}
+(@pxref{Istruzione next})
+e @code{nextfile}
+(@pxref{Istruzione nextfile}).
+
+@item Istruzioni di output
+Come @code{print} e @code{printf}.
+@iftex
+@xrefIl{Stampare}.
+@end iftex
+@ifnottex
+@xref{Stampare}.
+@end ifnottex
+
+@item Istruzioni di cancellazione
+Per eliminare elementi di vettori.
+@xref{Cancellazione}.
+@end table
+
+@node Istruzioni
+@section Istruzioni di controllo nelle azioni
+@cindex istruzioni di controllo
+@cindex controllo, tramite istruzioni, in azioni
+@cindex azioni, istruzioni di controllo in
+
+Le @dfn{istruzioni di controllo}, come @code{if}, @code{while} e cos@`{@dotless{i}} via,
+regolano il flusso di esecuzione nei programmi @command{awk}. Molte tra
+le istruzioni di controllo di @command{awk} sono modellate sulle
+corrispondenti istruzioni in C.
+@cindex istruzioni composte@comma{} istruzioni di controllo e
+@cindex composte, istruzioni@comma{} istruzioni di controllo e
+@cindex corpo, nelle azioni
+@cindex @code{@{@}} (parentesi graffe), istruzioni, raggruppare
+@cindex parentesi graffe (@code{@{@}}), istruzioni, raggruppare
+@cindex a capo, separatore di istruzioni nelle azioni
+@cindex @code{;} (punto e virgola), separare istruzioni nelle azioni
+@cindex punto e virgola (@code{;}), separare istruzioni nelle azioni
+Tutte le istruzioni di controllo iniziano con parole chiave speciali, come
+@code{if} e @code{while}, per distinguerle dalle semplici espressioni.
+Molte istruzioni di controllo contengono altre istruzioni. Per esempio,
+l'istruzione @code{if} contiene un'altra istruzione che pu@`o essere eseguita
+oppure no. Le istruzioni contenute sono chiamate @dfn{corpo}.
+Per includere pi@`u di un'istruzione nel corpo, queste vanno raggruppate
+in una sola @dfn{istruzione composta} tra parentesi graffe, e separate tra
+loro con dei ritorni a capo o dei punti e virgola.
+
+@menu
+* Istruzione if:: Eseguire in maniera condizionale
+ istruzioni @command{awk}.
+* Istruzione while:: Eseguire il ciclo finch@'e @`e
+ verificata una condizione.
+* Istruzione do:: Eseguire l'azione specificata, continuare
+ a eseguire il ciclo
+ finch@'e @`e verificata una condizione.
+* Istruzione for:: Un'altra istruzione iterativa, che
+ permette di specificare clausole
+ iniziali e di incremento.
+* Istruzione switch :: Valutazione di quale insieme di
+ istruzioni eseguire, a seconda del
+ valore assunto da una variabile.
+* Istruzione break:: Uscire subito dal ciclo pi@`u interno
+ in cui ci si trova.
+* Istruzione continue:: Andare alla fine del ciclo pi@`u interno
+ in cui ci si trova.
+* Istruzione next:: Smettere di elaborare il record corrente.
+* Istruzione nextfile:: Smettere di elaborare il file corrente.
+* Istruzione exit:: Interrompere l'esecuzione di @command{awk}.
+@end menu
+
+@node Istruzione if
+@subsection L'istruzione @code{if}-@code{else}
+
+@cindex istruzione @code{if}
+@cindex @code{if}, istruzione
+L'istruzione @code{if}-@code{else} @`e quella che serve in @command{awk}
+per prendere decisioni. @`E simile
+a questa:
+
+@display
+@code{if (@var{condizione}) @var{se-vera-fai}} [@code{else @var{se-falsa-fai}}]
+@end display
+
+@noindent
+La @var{condizione} @`e un'espressione che controlla quel che fa il resto
+dell'istruzione. Se la @var{condizione} @`e vera, viene eseguita la
+parte @var{se-vera-fai}; altrimenti viene
+eseguita la parte @var{se-falsa-fai}.
+La parte @code{else} dell'istruzione @`e
+facoltativa. La condizione @`e considerata falsa se il suo valore @`e zero o
+la stringa nulla; altrimenti, la condizione @`e vera.
+Si consideri quanto segue:
+
+@example
+if (x % 2 == 0)
+ print "x @`e pari"
+else
+ print "x @`e dispari"
+@end example
+
+In questo esempio, se l'espressione @samp{x % 2 == 0} @`e vera (cio@`e,
+se il valore di @code{x} @`e esattamente divisibile per due), allora viene
+eseguita la prima istruzione
+@code{print}; altrimenti, viene eseguita la seconda istruzione @code{print}.
+Se la parola chiave @code{else} sta sulla stessa riga di @var{se-vera-fai}
+e se @var{se-vera-fai} non @`e un'istruzione composta (cio@`e, non @`e racchiusa
+tra parentesi graffe), allora un punto e virgola deve separare
+@var{se-vera-fai} dalla parola chiave @code{else}.
+Per chiarire questo, l'esempio precedente si pu@`o riscrivere come:
+
+@example
+if (x % 2 == 0) print "x @`e pari"; else
+ print "x @`e dispari"
+@end example
+
+@noindent
+Se il @samp{;} @`e omesso, @command{awk} non pu@`o interpretare l'istruzione e
+segnala un errore di sintassi. Non si dovrebbero scrivere programmi in
+questo modo, perch@'e a chi li legge potrebbe sfuggire la parola chiave
+@code{else} se non @`e la prima parola della riga.
+
+@node Istruzione while
+@subsection L'istruzione @code{while}
+@cindex @code{while}, istruzione
+@cindex istruzione @code{while}
+@cindex cicli
+@cindex cicli, @code{while}
+@cindex cicli, si veda anche @code{while}, istruzione
+
+Nella programmazione, un @dfn{ciclo} @`e una parte di un programma che pu@`o
+essere eseguita due o pi@`u volte consecutivamente.
+L'istruzione @code{while} @`e la pi@`u semplice istruzione iterativa in
+@command{awk}. Esegue ripetutamente un'istruzione finch@'e una data
+condizione @`e vera. Per esempio:
+
+@example
+while (@var{condizione})
+ @var{corpo-del-ciclo}
+@end example
+
+@cindex corpo, nei cicli
+@noindent
+@var{corpo-del-ciclo} @`e un'istruzione detta @dfn{corpo} del ciclo,
+e @var{condizione} @`e un'espressione che controlla per quante volte il ciclo
+deve continuare a essere ripetuto.
+La prima cosa che l'istruzione @code{while} fa @`e un controllo della
+@var{condizione}.
+Se la @var{condizione} @`e vera, viene eseguita l'istruzione
+@var{corpo-del-ciclo}.
+@ifinfo
+(La @var{condizione} @`e vera quando il suo valore
+@`e diverso da zero e non @`e la stringa nulla.)
+@end ifinfo
+Dopo che le istruzioni in @var{corpo-del-ciclo} sono state eseguite,
+@var{condizione} @`e controllata nuovamente, e se @`e ancora vera,
+@var{corpo-del-ciclo} viene eseguito ancora. Questo processo @`e ripetuto
+finch@'e @var{condizione} rimane vera. Se la @var{condizione} @`e falsa fin
+dall'inizio, il corpo del ciclo
+non viene eseguito per nulla, e @command{awk} continua con l'istruzione
+che viene dopo il ciclo.
+Questo esempio stampa i primi tre campi di ogni record in input, uno per
+riga:
+
+@example
+awk '
+@{
+ i = 1
+ while (i <= 3) @{
+ print $i
+ i++
+ @}
+@}' inventory-shipped
+@end example
+
+@noindent
+Il corpo di questo ciclo @`e un'istruzione composta racchiusa tra parentesi graffe,
+che contiene due istruzioni.
+Il ciclo funziona in questo modo: all'inizio, il valore di @code{i} @`e
+impostato a 1.
+Poi, l'istruzione @code{while} controlla se @code{i} @`e minore o uguale a
+tre. Ci@`o @`e vero quando @code{i} @`e uguale a 1, quindi il campo
+@code{i}-esimo viene stampato. Quindi l'istruzione @samp{i++} incrementa il
+valore di @code{i}
+e il ciclo viene ripetuto. Il ciclo termina quando @code{i} assume il
+valore quattro.
+
+Un ritorno a capo non @`e richiesto tra la condizione e il corpo del ciclo;
+tuttavia, se lo si mette, il programma @`e di pi@`u facile comprensione,
+a meno che il corpo del ciclo non sia un'istruzione composta, oppure se @`e
+qualcosa di molto semplice. Neppure il ritorno a capo dopo la parentesi graffa
+aperta che inizia l'istruzione composta @`e necessario, ma il
+programma @`e di lettura pi@`u difficile se lo si omette.
+
+@node Istruzione do
+@subsection L'istruzione @code{do}-@code{while}
+@cindex @code{do}-@code{while}
+@cindex cicli, @code{do}-@code{while}
+
+Il ciclo @code{do} @`e una variazione dell'istruzione di ciclo @code{while}.
+Il ciclo @code{do} esegue il @var{corpo-del-ciclo} una volta e poi ripete il
+@var{corpo-del-ciclo} finch@'e la @var{condizione} rimane vera. @`E simile a questo:
+@example
+do
+ @var{corpo-del-ciclo}
+while (@var{condizione})
+@end example
+
+Anche se la @var{condizione} @`e falsa fin dall'inizio, il @var{corpo-del-ciclo}
+viene eseguito almeno una volta (e solo una volta, a meno che
+l'esecuzione di @var{corpo-del-ciclo}
+non renda vera la @var{condizione}). Si confronti con il corrispondente
+@code{while}:
+
+@example
+while (@var{condizione})
+ @var{corpo-del-ciclo}
+@end example
+
+@noindent
+Quest'istruzione non esegue il @var{corpo-del-ciclo} neppure una volta, se
+la @var{condizione} @`e falsa fin dall'inizio. Il seguente @`e un esempio di
+@code{do}:
+
+@example
+@{
+ i = 1
+ do @{
+ print $0
+ i++
+ @} while (i <= 10)
+@}
+@end example
+
+@noindent
+Questo programma stampa ogni record in input per 10 volte. Non si tratta,
+peraltro, di un esempio molto realistico, perch@'e in questo caso un semplice
+@code{while} sarebbe sufficiente. Questa osservazione riflette un'esperienza
+reale; solo occasionalmente @`e davvero necessario usare un @code{do}.
+
+@node Istruzione for
+@subsection L'istruzione @code{for}
+@cindex istruzione @code{for}
+@cindex @code{for}, istruzione
+@cindex cicli, @code{for}, iterativi
+
+L'istruzione @code{for} rende pi@`u agevole contare le iterazioni di un ciclo.
+La forma generale dell'istruzione @code{for} @`e simile a questa:
+
+@example
+for (@var{inizializzazione}; @var{condizione}; @var{incremento})
+ @var{corpo-del-ciclo}
+@end example
+
+@noindent
+La parti @var{inizializzazione}, @var{condizione} e @var{incremento} sono
+espressioni @command{awk} a piacere, e @var{corpo-del-ciclo} indica qualsiasi
+istruzione @command{awk}.
+
+L'istruzione @code{for} comincia con l'esecuzione di @var{inizializzazione}.
+Poi, finch@'e
+la @var{condizione} @`e vera, esegue ripetutamente @var{corpo-del-ciclo},
+e quindi @var{incremento}. Tipicamente, @var{inizializzazione} imposta una
+variabile a zero o a uno, @var{incremento} aggiunge uno alla stessa e
+@var{condizione} ne confronta il valore rispetto al numero desiderato di
+iterazioni.
+Per esempio:
+
+@example
+awk '
+@{
+ for (i = 1; i <= 3; i++)
+ print $i
+@}' inventory-shipped
+@end example
+
+@noindent
+Questo programma stampa i primi tre campi di ogni record in input, mettendo
+un campo su ogni riga.
+
+Non @`e possibile impostare
+pi@`u di una variabile nella parte di
+@var{inizializzazione} senza usare un'istruzione di assegnamento multiplo,
+come @samp{x = y = 0}. Ci@`o ha senso solo se tutti i valori iniziali
+sono uguali. (Ma @`e possibile inizializzare ulteriori variabili scrivendo
+i relativi assegnamenti come istruzioni separate @emph{prima} del ciclo
+@code{for}.)
+
+@c @cindex comma operator, not supported
+Lo stesso vale per la parte @var{incremento}. Se serve incrementare ulteriori
+variabili, questo va fatto con istruzioni separate alla fine del ciclo.
+L'espressione composta del linguaggio C, che usa l'operatore virgola [,]
+del C, sarebbe
+utile in questo contesto, ma non @`e
+prevista in @command{awk}.
+
+Molto spesso, @var{incremento} @`e un'espressione di incremento, come
+nell'esempio precedente. Ma questo non @`e obbligatorio; pu@`o trattarsi di
+un'espressione qualsiasi. Per esempio,
+la seguente istruzione stampa tutte le potenze di due comprese
+tra 1 e 100:
+
+@example
+for (i = 1; i <= 100; i *= 2)
+ print i
+@end example
+
+Se non @`e necessaria, ognuna delle tre espressioni fra
+parentesi che segue la parola chiave @code{for} pu@`o essere omessa. Quindi,
+@w{@samp{for (; x > 0;)}} @`e equivalente a @w{@samp{while (x > 0)}}. Se la
+@var{condizione} @`e omessa del tutto, @`e ritenuta sempre vera, producendo
+un @dfn{ciclo infinito} (cio@`e, un ciclo che non finisce mai).
+
+Molto spesso, un ciclo @code{for} @`e un'abbreviazione per un ciclo @code{while},
+come si pu@`o vedere qui:
+
+@example
+@var{inizializzazione}
+while (@var{condizione}) @{
+ @var{corpo-del-ciclo}
+ @var{incremento}
+@}
+@end example
+
+@cindex cicli, istruzione @code{continue} e
+@noindent
+La sola eccezione @`e quando l'istruzione @code{continue}
+(@pxref{Istruzione continue}) @`e usata
+all'interno del ciclo. Se si modifica un'istruzione @code{for}
+sostituendola con un'istruzione @code{while}
+ci@`o pu@`o cambiare l'effetto dell'istruzione @code{continue} posta all'interno
+del ciclo.
+
+Il linguaggio @command{awk} ha un'istruzione @code{for} oltre all'istruzione
+@code{while} perch@'e un ciclo @code{for} @`e spesso pi@`u semplice da scrivere,
+e viene in mente pi@`u naturalmente.
+Contare il numero di iterazioni @`e
+molto frequente nei cicli. Pu@`o essere pi@`u facile pensare a questo conto come
+parte del ciclo, piuttosto che come qualcosa da fare all'interno del ciclo.
+
+@cindex @code{in}, operatore
+@cindex operatore @code{in}
+Esiste una versione alternativa al ciclo @code{for}, per esaminare tutti
+gli indici di un vettore:
+
+@example
+for (i in vettore)
+ @var{fai qualcosa con} vettore[i]
+@end example
+
+@noindent
+@xref{Visitare un intero vettore}
+per maggiori informazioni su questa versione del ciclo @code{for}.
+
+@node Istruzione switch
+@subsection L'istruzione @code{switch}
+@cindex @code{switch}, istruzione
+@cindex @code{case}, parola chiave
+@cindex parola chiave @code{case}
+@cindex @code{default}, parola chiave
+@cindex parola chiave @code{default}
+
+Questa @value{SECTION} descrive una funzionalit@`a disponibile solo in
+@command{gawk}.
+Se @command{gawk} @`e in modalit@`a compatibile (@pxref{Opzioni}),
+la funzionalit@`a non @`e disponibile.
+
+L'istruzione @code{switch} consente di valutare un'espressione e di
+eseguire istruzioni se il valore trovato corrisponde a uno dei @code{case} [casi] previsti.
+Le istruzioni @code{case} sono esaminate per cercare una corrispondenza
+nell'ordine in cui i casi sono definiti nel programma. Se nessuno dei @code{case}
+corrisponde al valore dell'espressione, viene eseguita la sezione
+@code{default}, se @`e stata specificata.
+
+Ogni @code{case} contiene una singola costante, che pu@`o essere un numero,
+una stringa, o
+una @dfn{regexp}. Viene valutata l'espressione @code{switch}, e poi la
+costante di ogni @code{case} viene confrontata
+di volta in volta con il valore risultante.
+Il tipo di costante determina quale sar@`a il confronto: per i tipi numerici o
+stringa si seguono le regole abituali. Per una costante @dfn{regexp} viene
+effettuato un confronto tra l'espressione e il valore di tipo stringa
+dell'espressione originale.
+Il formato generale dell'istruzione @code{switch} @`e simile a questo:
+
+@example
+switch (@var{espressione}) @{
+case @var{valore o espressione regolare}:
+ @var{corpo-del-caso}
+default:
+ @var{corpo-del-default}
+@}
+@end example
+
+Il flusso di controllo
+dell'istruzione @code{switch} funziona come per il linguaggio C. Una volta
+stabilita una corrispondenza con un dato caso, le istruzione che formano il
+corpo del caso sono eseguite, fino a che non venga trovata un'istruzione
+@code{break},
+@code{continue}, @code{next}, @code{nextfile} o @code{exit},
+o fino alla fine dell'istruzione @code{switch} medesima. Per esempio:
+
+@example
+while ((c = getopt(ARGC, ARGV, "aksx")) != -1) @{
+ switch (c) @{
+ case "a":
+ # stampa la dimensione di tutti i file
+ all_files = TRUE;
+ break
+ case "k":
+ BLOCK_SIZE = 1024 # in blocchi da 1 Kbyte
+ break
+ case "s":
+ # fa solo le somme
+ sum_only = TRUE
+ break
+ case "x":
+ # non esce dal filesystem
+ fts_flags = or(fts_flags, FTS_XDEV)
+ break
+ case "?":
+ default:
+ uso()
+ break
+ @}
+@}
+@end example
+
+Si noti che se nessuna delle istruzioni specificate qui arresta l'esecuzione
+di un'istruzione @code{case} per la quale @`e stata trovata una corrispondenza;
+l'esecuzione continua fino al successivo @code{case} finch@'e
+non viene interrotta. In questo esempio, il
+@code{case} per @code{"?"} esegue quello di @code{default}, che consiste nel
+chiamare una funzione di nome @code{uso()}.
+(La funzione @code{getopt()} qui chiamata @`e descritta in
+@ref{Funzione getopt}.)
+
+@node Istruzione break
+@subsection L'istruzione @code{break}
+@cindex @code{break}, istruzione
+@cindex istruzione @code{break}
+@cindex cicli, uscita
+@cindex cicli, istruzione @code{break} e
+
+L'istruzione @code{break} esce dal ciclo pi@`u interno @code{for},
+@code{while} o @code{do} dentro al quale si trova. L'esempio seguente
+trova, se esiste, il divisore pi@`u piccolo di un dato numero intero, oppure
+dichiara che si tratta di un numero primo:
+
+@example
+# trova il divisore pi@`u piccolo di num
+@{
+ num = $1
+ for (divisore = 2; divisore * divisore <= num; divisore++) @{
+ if (num % divisore == 0)
+ break
+ @}
+ if (num % divisore == 0)
+ printf "Il pi@`u piccolo divisore di %d @`e %d\n", num, divisore
+ else
+ printf "%d @`e un numero primo\n", num
+@}
+@end example
+
+Quando il resto della divisione @`e zero nella prima istruzione @code{if},
+@command{awk} immediatamente esce, a causa del @dfn{break}, dal ciclo
+@code{for} in cui @`e contenuto. Ci@`o vuol dire
+che @command{awk} prosegue immediatamente fino all'istruzione che viene dopo
+il ciclo, e continua l'elaborazione. (L'istruzione @code{break} @`e molto
+differente dall'istruzione @code{exit},
+la quale termina l'intero programma @command{awk}.
+@xref{Istruzione exit}.)
+
+Il seguente programma mostra come la @var{condizione} di un'istruzione
+@code{for} o @code{while} potrebbe essere sostituita da un'istruzione
+@code{break} all'interno di un @code{if}:
+
+@example
+# trova il divisore pi@`u piccolo di num
+@{
+ num = $1
+ for (divisore = 2; ; divisore++) @{
+ if (num % divisore == 0) @{
+ printf "Il pi@`u piccolo divisore di %d @`e %d\n", num, divisore
+ break
+ @}
+ if (divisore * divisore > num) @{
+ printf "%d @`e un numero primo\n", num
+ break
+ @}
+ @}
+@}
+@end example
+
+L'istruzione @code{break} @`e usata anche per terminare l'esecuzione di
+un'istruzione @code{switch}.
+Questo argomento @`e trattato in @ref{Istruzione switch}.
+
+@c @cindex @code{break}, outside of loops
+@c @cindex historical features
+@c @cindex @command{awk} language, POSIX version
+@cindex POSIX @command{awk}, @code{break} e
+@cindex angolo buio, istruzione @code{break}
+@cindex @command{gawk}, istruzione @code{break} in
+@cindex Brian Kernighan, @command{awk} di
+L'istruzione @code{break} non ha significato se
+usata fuori dal corpo di un ciclo o di un'istruzione @code{switch}.
+Tuttavia, anche se la cosa non @`e mai stata documentata,
+le prime implementazioni di @command{awk} consideravano l'istruzione @code{break}
+esterna a un ciclo come un'istruzione @code{next}
+(@pxref{Istruzione next}).
+@value{DARKCORNER}
+Versioni recenti di BWK @command{awk} non consentono pi@`u un tale uso,
+e lo stesso fa @command{gawk}.
+
+@node Istruzione continue
+@subsection L'istruzione @code{continue}
+
+@cindex @code{continue}, istruzione
+@cindex istruzione @code{continue}
+Analogamente a @code{break}, l'istruzione @code{continue} @`e usata solo
+all'interno di cicli @code{for}, @code{while} e @code{do}. L'istruzione
+ignora il resto del corpo del ciclo, facendo s@`{@dotless{i}} che la successiva iterazione
+del ciclo inizi immediatamente. Questo comportamento @`e differente da quello
+di @code{break}, che esce completamente dal ciclo.
+
+L'istruzione @code{continue} in un ciclo @code{for} fa s@`{@dotless{i}} che @command{awk}
+ignori il resto del corpo del ciclo e prosegua l'esecuzione con l'espressione
+@var{incremento} dell'istruzione @code{for}. Il seguente programma
+@`e un esempio di ci@`o:
+
+@example
+BEGIN @{
+ for (x = 0; x <= 20; x++) @{
+ if (x == 5)
+ continue
+ printf "%d ", x
+ @}
+ print ""
+@}
+@end example
+
+@noindent
+Questo programma stampa tutti i numeri da 0 a 20---tranne il 5, in cui
+l'istruzione @code{printf} @`e saltata. Siccome l'incremento @samp{x++}
+non viene saltato, @code{x} non rimane fermo al valore 5. Si confronti il ciclo
+@code{for} dell'esempio precedente con il seguente ciclo @code{while}:
+
+@example
+BEGIN @{
+ x = 0
+ while (x <= 20) @{
+ if (x == 5)
+ continue
+ printf "%d ", x
+ x++
+ @}
+ print ""
+@}
+@end example
+
+@noindent
+Questo programma inizia un ciclo infinito dopo che @code{x} ha assunto il
+valore 5, poich@'e l'istruzione di incremento (@samp{x++}) non @`e mai raggiunta.
+
+@c @cindex @code{continue}, fuori da un ciclo
+@c @cindex funzionalit@`a del passato
+@c @cindex linguaggio @command{awk}, versione POSIX
+@cindex POSIX @command{awk}, istruzione @code{continue} e
+@cindex angolo buio, istruzione @code{continue}
+@cindex @command{gawk}, istruzione @code{continue} in
+@cindex Brian Kernighan, @command{awk} di
+L'istruzione @code{continue} non ha un significato speciale se appare in
+un'istruzione @code{switch}, e non ha alcun significato se usata fuori dal
+corpo di un ciclo. Le prime versioni di @command{awk} trattavano le
+istruzioni @code{continue} che erano fuori da un ciclo allo stesso modo con
+cui trattavano l'istruzione @code{break}
+fuori da un ciclo: come se fosse un'istruzione @code{next}
+@ifset FOR_PRINT
+(trattata nella @value{SECTION} seguente).
+@end ifset
+@ifclear FOR_PRINT
+(@pxref{Istruzione next}).
+@end ifclear
+@value{DARKCORNER}
+Versioni recenti di BWK @command{awk} non consentono pi@`u un tale uso,
+e lo stesso vale per @command{gawk}.
+
+@node Istruzione next
+@subsection L'istruzione @code{next}
+@cindex @code{next}, istruzione
+@cindex istruzione @code{next}
+
+L'istruzione @code{next} fa s@`{@dotless{i}} che @command{awk} termini immediatamente
+l'elaborazione del record corrente e proceda a elaborare il record successivo.
+Ci@`o vuol dire che nessuna delle eventuali regole successive viene eseguita
+per il record corrente e che il resto delle azioni presenti nella
+regola correntemente in esecuzione non viene eseguito.
+
+Si confronti quanto sopra con quel che fa la funzione @code{getline}
+(@pxref{Getline}). Anch'essa fa s@`{@dotless{i}} che @command{awk} legga il record
+successivo immediatamente, ma non altera il flusso del controllo in alcun
+modo (cio@`e, il resto dell'azione in esecuzione prosegue con il nuovo record
+in input).
+
+@cindex @command{awk}, programmi, eseguire
+Al livello pi@`u alto, l'esecuzione di un programma @command{awk} @`e un ciclo
+che legge un record in input e quindi confronta il criterio di ricerca di
+ciascuna regola con il record stesso. Se si vede questo ciclo come un
+@code{for} il cui corpo contiene le regole, l'istruzione @code{next} @`e analoga
+a un'istruzione @code{continue}. Salta, cio@`e, alla fine del corpo di questo
+ciclo implicito
+ed esegue l'incremento (ovvero legge un altro record).
+
+Per esempio, si supponga che un programma @command{awk} agisca solo su record
+che hanno quattro campi, e che non dovrebbe terminare con un errore se trova
+dei record in input non validi. Per evitare di complicare il resto del
+programma, si pu@`o scrivere una regola ``filtro'' a inizio programma, come
+mostrato in questo esempio:
+
+@example
+NF != 4 @{
+ printf("%s:%d: salto: NF != 4\n", FILENAME, FNR) > "/dev/stderr"
+ next
+@}
+@end example
+
+@noindent
+Siccome @`e presente un @code{next},
+le regole successive del programma non elaboreranno i record non validi.
+Il messaggio @`e ridiretto al flusso in output
+@dfn{standard error}, sul quale vanno scritti i messaggi di errore.
+Per maggiori dettagli, si veda
+@ref{File speciali}.
+
+Se l'istruzione @code{next} provoca il raggiungimento della fine del file
+in input, vengono eseguite le eventuali regole @code{END} presenti.
+@xref{BEGIN/END}.
+
+L'istruzione @code{next} non @`e consentita all'interno delle regole
+@code{BEGINFILE} ed @code{ENDFILE}.
+@xref{BEGINFILE/ENDFILE}.
+
+@c @cindex @command{awk} language, POSIX version
+@c @cindex @code{next}, inside a user-defined function
+@cindex @code{BEGIN}, criterio di ricerca, istruzioni @code{next}/@code{nextfile} e
+@cindex @code{END}, criterio di ricerca, istruzioni @code{next}/@code{nextfile} e
+@cindex POSIX @command{awk}, istruzioni @code{next}/@code{nextfile} e
+@cindex @code{next}, istruzione, in funzioni definite dall'utente
+@cindex funzioni definite dall'utente, istruzioni @code{next}/@code{nextfile} e
+Secondo lo standard POSIX, il comportamento di @command{awk} @`e indefinito
+se @code{next} @`e usato in una regola @code{BEGIN} o @code{END}.
+@command{gawk} considera questo come un errore di sintassi. Sebbene POSIX
+non proibisca di usarlo,
+molte altre implementazioni di @command{awk} non consentono che l'istruzione
+@code{next} sia usata all'interno del corpo di funzioni.
+(@pxref{Funzioni definite dall'utente}).
+Come tutte le altre istruzioni @code{next}, un'istruzione @code{next} all'interno del
+corpo di una funzione legge il record successivo e inizia a elaborarlo
+a partire dalla prima regola del programma.
+
+@node Istruzione nextfile
+@subsection L'istruzione @code{nextfile}
+@cindex @code{nextfile}, istruzione
+@cindex istruzione @code{nextfile}
+
+L'istruzione @code{nextfile}
+@`e simile all'istruzione @code{next}.
+Tuttavia, invece di terminare l'elaborazione del record corrente, l'istruzione
+@code{nextfile} richiede ad @command{awk} di terminare di elaborare il
+@value{DF} corrente.
+
+Alla fine dell'esecuzione dell'istruzione @code{nextfile},
+@code{FILENAME} @`e
+aggiornato per contenere il nome del successivo @value{DF} elencato sulla riga
+di comando, @code{FNR} @`e reimpostato a uno, e l'elaborazione riparte con
+la prima regola del programma.
+Se l'istruzione @code{nextfile} raggiunge la fine dei file in input,
+vengono eseguite le eventuali regole @code{END} presenti.
+Un'eccezione a questo si ha se @code{nextfile} @`e invocata durante
+l'esecuzione di qualche istruzione all'interno di una regola @code{END};
+in questo caso, il programma viene terminato immediatamente.
+@xref{BEGIN/END}.
+
+L'istruzione @code{nextfile} @`e utile quando ci sono parecchi @value{DF} da
+elaborare, ma non @`e necessario elaborare ogni record in ogni file.
+Senza @code{nextfile},
+per passare al successivo @value{DF}, un programma
+dovrebbe continuare a leggere i record che non gli servono. L'istruzione
+@code{nextfile} @`e una maniera molto pi@`u efficiente per ottenere lo stesso
+risultato.
+
+In @command{gawk}, l'esecuzione di @code{nextfile} produce ulteriori effetti:
+le eventuali regole @code{ENDFILE}
+sono eseguite se @command{gawk} non
+si trova correntemente all'interno di una regola @code{END} o
+@code{BEGINFILE}; @code{ARGIND} @`e
+incrementato e le eventuali regole @code{BEGINFILE} sono eseguite.
+(@code{ARGIND} non @`e stato ancora trattato.
+@xref{Variabili predefinite}.)
+
+In @command{gawk}, @code{nextfile} @`e utile all'interno di una regola
+@code{BEGINFILE} per evitare di elaborare un file che altrimenti causerebbe
+un errore fatale in @command{gawk}.
+In questo caso, le regole @code{ENDFILE} non vengono eseguite.
+@xref{BEGINFILE/ENDFILE}.
+
+Sebbene possa sembrare che @samp{close(FILENAME)} ottenga lo stesso
+risultato di @code{nextfile}, non @`e cos@`{@dotless{i}}. @code{close()}
+pu@`o essere usato solo per chiudere file, @dfn{pipe} e coprocessi che siano
+stati aperti tramite ridirezioni. Non ha niente a che vedere con
+l'elaborazione principale che
+@command{awk} fa dei file elencati in @code{ARGV}.
+
+@quotation NOTA
+Per molti anni, @code{nextfile} @`e stata
+un'estensione comune. A settembre 2012 si @`e deciso di
+includerla nello standard POSIX.
+Si veda @uref{http://austingroupbugs.net/view.php?id=607, il sito web dell'Austin Group}.
+@end quotation
+
+@cindex funzioni definite dall'utente, istruzioni @code{next}/@code{nextfile} e
+@cindex @code{nextfile}, in funzioni definite dall'utente
+@cindex Brian Kernighan, @command{awk} di
+@cindex @command{mawk}, programma di utilit@`a
+@cindex programma di utilit@`a @command{mawk}
+Le versioni correnti di BWK @command{awk} e @command{mawk}
+entrambe prevedono @code{nextfile}. Tuttavia, non sono consentite istruzioni
+@code{nextfile} all'interno del corpo delle funzioni
+(@pxref{Funzioni definite dall'utente}).
+@command{gawk} lo permette; una @code{nextfile} all'interno del corpo di una
+funzione legge il primo record del file
+successivo e inizia l'elaborazione dello stesso
+a partire dalla prima regola del programma, esattamente come farebbe
+qualsiasi altra istruzione @code{nextfile}.
+
+@node Istruzione exit
+@subsection L'istruzione @code{exit}
+
+@cindex @code{exit}, istruzione
+@cindex istruzione @code{exit}
+L'istruzione @code{exit} fa s@`{@dotless{i}} che @command{awk} termini immediatamente
+l'esecuzione della regola corrente e che termini di elaborare l'input;
+qualsiasi input ancora da elaborare @`e ignorato. L'istruzione @code{exit} @`e
+scritta come segue:
+
+@display
+@code{exit} [@var{codice di ritorno}]
+@end display
+
+@cindex @code{BEGIN}, criterio di ricerca, istruzione @code{exit} e
+@cindex criterio di ricerca @code{BEGIN}, istruzione @code{exit} e
+@cindex @code{END}, criterio di ricerca, istruzione @code{exit} e
+@cindex criterio di ricerca @code{END}, istruzione @code{exit} e
+Quando un'istruzione @code{exit} @`e eseguita all'interno di una regola @code{BEGIN},
+il programma termina completamente l'elaborazione. Nessun record in input
+viene letto. Tuttavia, se una regola @code{END} @`e presente, come parte
+dell'esecuzione dell'istruzione @code{exit},
+la regola @code{END} viene eseguita
+(@pxref{BEGIN/END}).
+Se @code{exit} @`e usata nel corpo di una regola @code{END},
+il programma termina immediatamente.
+
+Un'istruzione @code{exit} che non fa parte di una regola @code{BEGIN} o @code{END}
+termina l'esecuzione di qualsiasi ulteriore regola applicabile al record
+corrente, salta la lettura di qualsiasi record in input, ed esegue
+le eventuali regole @code{END}. @command{gawk} salta anche le eventuali regole
+@code{ENDFILE}, che non vengono eseguite.
+
+In questo caso,
+se non si desidera che la regola @code{END} venga eseguita, si deve impostare
+una variabile a un valore diverso da zero, prima di invocare l'istruzione
+@code{exit} e controllarne il valore nella regola @code{END}.
+@xref{Funzione assert}
+per un esempio di questo tipo.
+
+@cindex angolo buio, istruzione @code{exit}
+Se si specifica un argomento all'istruzione @code{exit}, il suo valore @`e
+usato come codice di ritorno finale dell'elaborazione @command{awk}. Se non
+viene specificato alcun argomento,
+@code{exit} fa terminare @command{awk} con un codice di ritorno di
+``successo''.
+Nel caso in cui un argomento
+sia specificato in una prima istruzione @code{exit} e poi @code{exit} sia
+chiamato una seconda volta all'interno di una regola @code{END} senza alcun
+argomento, @command{awk} usa il valore di ritorno specificato in precedenza.
+@value{DARKCORNER}
+@xref{Codice di ritorno} per maggiori informazioni.
+
+@cindex convenzioni di programmazione, istruzione @code{exit}
+Per esempio, si supponga che si sia verificata una condizione di errore
+difficile o impossibile da gestire. Convenzionalmente, i programmi la
+segnalano terminando con un codice di ritorno diverso da zero. Un programma
+@command{awk} pu@`o farlo usando un'istruzione @code{exit} con un argomento
+diverso da zero, come mostrato nell'esempio seguente:
+
+@example
+BEGIN @{
+ if (("date" | getline data_corrente) <= 0) @{
+ print "Non riesco a ottenere la data dal sistema" > "/dev/stderr"
+ exit 1
+ @}
+ print "la data corrente @`e", data_corrente
+ close("date")
+@}
+@end example
+
+@quotation NOTA
+Per una completa portabilit@`a, i codici di ritorno dovrebbero essere compresi
+tra zero e 126, estremi compresi.
+Valori negativi e valori maggiori o uguali a 127, possono non generare
+risultati coerenti tra loro in sistemi operativi diversi.
+@end quotation
+
+
+@node Variabili predefinite
+@section Variabili predefinite
+@cindex predefinite, variabili
+@cindex variabili predefinite
+
+La maggior parte delle variabili @command{awk} sono disponibili per essere
+usate dall'utente secondo le proprie esigenze;
+queste variabili non cambiano mai di valore a meno che il
+programma non assegni loro dei valori, e non hanno alcuna influenza sul
+programma a meno che non si decida di utilizzarle nel programma.
+Tuttavia, alcune variabili in @command{awk} hanno dei significati speciali
+predefiniti.
+@command{awk} tiene conto di alcune di queste automaticamente, in modo da
+rendere possibile la richiesta ad @command{awk} di fare certe cose nella
+maniera desiderata. Altre variabili sono impostate automaticamente da
+@command{awk}, in modo da poter comunicare al programma in esecuzione
+informazioni sul modo di procedere interno di @command{awk}.
+
+@cindex @command{gawk}, variabili predefinite e
+Questa @value{SECTION} documenta tutte le variabili predefinite di
+@command{gawk}; molte di queste variabili sono anche documentate nei
+@value{CHAPTER} che descrivono le loro aree di influenza.
+
+@menu
+* Variabili modificabili dall'utente:: Variabili predefinite modificabili per
+ controllare @command{awk}.
+* Variabili auto-assegnate:: Variabili predefinite con cui
+ @command{awk} fornisce informazioni.
+* ARGC e ARGV:: Modi di usare @code{ARGC} e @code{ARGV}.
+@end menu
+
+@node Variabili modificabili dall'utente
+@subsection Variabili predefinite modificabili per controllare @command{awk}
+@cindex variabili predefinite, modificabili dall'utente
+@cindex modificabili dall'utente, variabili
+
+La seguente @`e una lista alfabetica di variabili che @`e possibile modificare per
+controllare come @command{awk} gestisce alcuni compiti.
+
+Le variabili che sono specifiche di @command{gawk} sono contrassegnate da un
+cancelletto (@samp{#}). Queste variabili sono estensioni @command{gawk}.
+In altre implementazioni di @command{awk}, o se @command{gawk} @`e eseguito in
+modalit@`a compatibile
+(@pxref{Opzioni}), non hanno un significato speciale. (Eventuali eccezioni
+sono menzionate nella descrizione di ogni variabile.)
+
+@table @code
+@cindex @code{BINMODE}, variabile
+@cindex variabile @code{BINMODE}
+@cindex binario, input/output
+@cindex input/output binario
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{BINMODE}
+@item BINMODE #
+Su sistemi non-POSIX, questa variabile specifica l'uso della modalit@`a binaria
+per tutto l'I/O. I valori numerici di uno, due o tre specificano che i file
+in input, i file di output o tutti i file, rispettivamente, devono usare I/O
+binario.
+Un valore numerico inferiore a zero @`e trattato come zero e un valore
+numerico maggiore di tre @`e trattato
+come tre. Alternativamente, le stringhe @code{"r"} o @code{"w"} specificano
+che i file in input e i file in output,
+rispettivamente, devono usare
+I/O binario. Una stringa @code{"rw"} o @code{"wr"} indica che tutti i file
+devono usare I/O binario. Ogni altro valore di stringa @`e trattato come
+@code{"rw"}, ma @command{gawk} genera un messaggio di avvertimento.
+@code{BINMODE} @`e descritto in maggior
+dettaglio in @ref{Uso su PC}. @command{mawk} (@pxref{Altre versioni})
+prevede questa variabile, ma consente solo valori numerici.
+
+@cindex @code{CONVFMT}, variabile
+@cindex variabile @code{CONVFMT}
+@cindex POSIX @command{awk}, variabile @code{CONVFMT} e
+@cindex numeri, conversione in stringhe
+@cindex stringhe, conversione in numeri
+@item @code{CONVFMT}
+Una stringa che controlla la conversione di numeri in
+stringhe (@pxref{Conversione}).
+In effetti @`e la stringa passata come primo argomento alla funzione
+@code{sprintf()}
+(@pxref{Funzioni per stringhe}).
+Il suo valore di default @`e @code{"%.6g"}.
+@code{CONVFMT} @`e stata introdotta dallo standard POSIX.
+
+@cindex @command{gawk}, variabile @code{FIELDWIDTHS} in
+@cindex @code{FIELDWIDTHS}, variabile
+@cindex variabile @code{FIELDWIDTHS}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{FIELDWIDTHS}
+@cindex separatori di campo, variabile @code{FIELDWIDTHS} e
+@cindex campo, separatori di, variabile @code{FIELDWIDTHS} e
+@item FIELDWIDTHS #
+Una lista di posizioni di colonna, separate da spazi, per dire a
+@command{gawk}
+come dividere campi in input posti su colonne fisse.
+Assegnando un valore a @code{FIELDWIDTHS}, le variabili @code{FS} e
+@code{FPAT}
+@emph{non} vengono usate per effettuare la divisione in campi.
+@xref{Dimensione costante} per maggiori informazioni.
+
+@cindex @command{gawk}, variabile @code{FPAT} in
+@cindex @code{FPAT}, variabile
+@cindex variabile @code{FPAT}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{FPAT}
+@cindex separatori di campo, variabile @code{FPAT} e
+@cindex campo, separatori di, variabile @code{FPAT} e
+@item FPAT #
+Un'espressione regolare (di tipo stringa) per dire a @command{gawk}
+di creare i campi utilizzando come delimitatore il testo che corrisponde
+all'espressione regolare.
+Assegnando un valore a @code{FPAT}
+le variabili @code{FS} e @code{FIELDWIDTHS}
+@emph{non} vengono usate per effettuare la divisione in campi.
+@xref{Separazione in base al contenuto} per maggiori informazioni.
+
+@cindex @code{FS}, variabile
+@cindex variabile @code{FS}
+@cindex campo, separatori di
+@cindex separatori di campo
+@item FS
+Il separatore dei campi in input (@pxref{Separatori di campo}).
+Il valore pu@`o essere una stringa di un solo carattere o un'espressione
+regolare composta da pi@`u caratteri che individua il separatore tra i campi
+dei record in input. Se il suo valore
+@`e la stringa nulla (@code{""}),
+ogni singolo carattere del record costituisce un campo.
+(Questo comportamente @`e un'estensione @command{gawk}. POSIX @command{awk} non
+specifica il comportamento quando @code{FS} @`e la stringa nulla.
+Nonostante questo, alcune altre versioni di @command{awk} trattano @code{""}
+in modo speciale.)
+
+@cindex POSIX @command{awk}, variabile @code{FS} e
+Il valore di default @`e @w{@code{" "}}, una stringa consistente in un singolo
+spazio. In via eccezionale, questo valore significa che qualsiasi sequenza
+di spazi, TAB, e/o ritorni a capo costituisce
+un solo separatore.
+Inoltre eventuali spazi, TAB e ritorni a capo all'inizio e alla fine
+del record in input vengono ignorati.
+
+Si pu@`o impostare il valore di @code{FS} sulla riga dei comandi usando
+l'opzione @option{-F}:
+
+@example
+awk -F, '@var{programma}' @var{file-in-input}
+@end example
+
+@cindex @command{gawk}, separatori di campo e
+Se @command{gawk} sta usando @code{FIELDWIDTHS} o @code{FPAT}
+per separare i campi,
+assegnare un valore a @code{FS} fa s@`{@dotless{i}} che @command{gawk} torni alla
+separazione dei campi normale, fatta utilizzando la variabile @code{FS}.
+Un modo semplice per fare questo
+@`e semplicemente quello di scrivere l'istruzione
+@samp{FS = FS}, aggiungendo magari un commento esplicativo.
+
+@cindex @command{gawk}, variabile @code{IGNORECASE} in
+@cindex @code{IGNORECASE}, variabile
+@cindex variabile @code{IGNORECASE}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{IGNORECASE}
+@cindex maiuscolo/minuscolo e confronti tra stringhe
+@cindex maiuscolo/minuscolo e @dfn{regexp}
+@cindex espressioni regolari, maiuscolo/minuscolo
+@item IGNORECASE #
+Se la variabile @code{IGNORECASE} @`e diversa da zero o dalla stringa nulla,
+tutti i confronti tra stringhe
+e tutti i confronti tra espressioni regolari sono insensibili
+alle differenze maiuscolo/minuscolo.
+Questo vale per il confronto tra @dfn{regexp}
+usando @samp{~} e @samp{!~}, per le funzioni @code{gensub()},
+@code{gsub()}, @code{index()}, @code{match()}, @code{patsplit()},
+@code{split()} e @code{sub()},
+per la determinazione della fine record con @code{RS} e per la divisione
+in campi con @code{FS} e @code{FPAT}.
+Tuttavia, il valore di @code{IGNORECASE} @emph{non} influenza gli indici
+dei vettori
+e non influenza la separazione dei campi qualora si usi un separatore di campo
+costituito da un unico carattere.
+@xref{Maiuscolo-Minuscolo}.
+
+@cindex @command{gawk}, variabile @code{LINT} in
+@cindex @code{LINT}, variabile
+@cindex variabile @code{LINT}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{LINT}
+@cindex @dfn{lint}, controlli
+@cindex controlli @dfn{lint}
+@item LINT #
+Quando questa variabile @`e vera (non uguale a zero e non uguale alla stringa
+nulla), @command{gawk} si comporta come se fosse stata specificata sulla
+riga di comando l'opzione @option{--lint}
+(@pxref{Opzioni}).
+Con un valore di @code{"fatal"}, gli avvertimenti di @dfn{lint} generano un errore
+fatale.
+Con un valore di @code{"invalid"}, sono inviati solo gli avvertimenti
+per cose che sono effettivamente non valide. (Questa parte non funziona
+ancora perfettamente.)
+Ogni altro valore @dfn{vero} stampa avvertimenti non fatali.
+Se @code{LINT} ha per valore @dfn{falso} nessun avvertimento @dfn{lint} viene
+stampato.
+
+Questa variabile @`e un'estensione @command{gawk}. Non ha un valore speciale
+per altre implementazioni di @command{awk}. A differenza di altre variabili
+speciali, modificare il valore di @code{LINT} altera la produzione di
+avvertimenti @dfn{lint} anche se @command{gawk} @`e in modalit@`a compatibile.
+Analogamente a come le opzioni
+@option{--lint} e @option{--traditional} controllano in maniera indipendente
+diversi aspetti del comportamente di @command{gawk}, il controllo
+degli avvertimenti di @dfn{lint} durante l'esecuzione del programma @`e indipendente
+dall'implementazione @command{awk} in esecuzione.
+
+@cindex @code{OFMT}, variabile
+@cindex variabile @code{OFMT}
+@cindex numeri, conversione in stringhe
+@cindex stringhe, conversione in numeri
+@item OFMT
+@`E questa la stringa che controlla la conversione di numeri in
+stringhe (@pxref{Conversione}) quando li
+si stampa con l'istruzione
+@code{print}. Funziona passandola
+ come primo argomento alla funzione @code{sprintf()}
+(@pxref{Funzioni per stringhe}).
+Il suo valore di default @`e @code{"%.6g"}. Le prime versioni di @command{awk}
+usavano @code{OFMT} per specificare il formato da usare per convertire
+numeri in stringhe in espressioni generali; questo compito @`e ora svolto
+da @code{CONVFMT}.
+
+@cindex @code{sprintf()}, funzione, variabile @code{OFMT} e
+@cindex funzione @code{sprintf()}, variabile @code{OFMT} e
+@cindex @code{print}, istruzione, variabile @code{OFMT} e
+@cindex istruzione @code{print}, variabile @code{OFMT} e
+@cindex variabile @code{OFS}
+@cindex @code{OFS}, variabile
+@cindex campo, separatori di
+@cindex separatori di campo
+@item OFS
+@`E il separatore dei campi in output (@pxref{Separatori di output}). @`E ci@`o
+che viene stampato in output per separare i campi stampati da un'istruzione @code{print}.
+Il suo valore di default @`e @w{@code{" "}}, una stringa costituita da un solo
+spazio.
+
+@cindex @code{ORS}, variabile
+@cindex variabile @code{ORS}
+@item ORS
+Il separatore dei record in output. Viene stampato alla fine di ogni
+istruzione @code{print}. Il suo valore di default @`e @code{"\n"},
+il carattere di ritorno a capo.
+(@xref{Separatori di output}.)
+
+@cindex @code{PREC}, variabile
+@cindex variabile @code{PREC}
+@item PREC #
+La precisione disponibile nei numeri a virgola mobile a precisione arbitraria,
+per default 53 bit (@pxref{Impostare la precisione}).
+
+@cindex @code{ROUNDMODE}, variabile
+@cindex variabile @code{ROUNDMODE}
+@item ROUNDMODE #
+La modalit@`a di arrotondamento da usare per operazioni aritmetiche a precisione
+arbitraria svolte sui numeri, per default @code{"N"}
+(@code{roundTiesToEven} nello standard
+IEEE 754; @pxref{Impostare modi di arrotondare}).
+
+@cindex @code{RS}, variabile
+@cindex variabile @code{RS}
+@cindex separatori di record
+@cindex record, separatori di
+@item @code{RS}
+Il separatore tra record in input. Il suo valore di default @`e una stringa
+contenente il solo carattere di ritorno a capo, il che significa che un record in input
+consiste di una sola riga di testo.
+Il suo valore pu@`o essere anche la stringa nulla, nel qual caso i record sono
+separati da una o pi@`u righe vuote.
+Se invece @`e una @dfn{regexp}, i record sono separati da
+corrispondenze alla @dfn{regexp} nel testo in input.
+(@xref{Record}.)
+
+La possibilit@`a che @code{RS} sia un'espressione regolare
+@`e un'estensione @command{gawk}.
+In molte altre implementazioni @command{awk}, oppure
+se @command{gawk} @`e in modalit@`a compatibile
+(@pxref{Opzioni}),
+@`e usato solo il primo carattere del valore di @code{RS}.
+
+@cindex @code{SUBSEP}, variabile
+@cindex variabile @code{SUBSEP}
+@cindex separatori di indici
+@cindex indici, separatori di
+@item @code{SUBSEP}
+Il separatore di indici. Ha il valore di default di
+@code{"\034"} ed @`e usato per separare le parti di cui sono composti gli indici
+di un vettore multidimensionale. Quindi, l'espressione
+@samp{@w{pippo["A", "B"]}}
+in realt@`a accede a @code{pippo["A\034B"]}
+(@pxref{Vettori multidimensionali}).
+
+@cindex @command{gawk}, variabile @code{TEXTDOMAIN} in
+@cindex @code{TEXTDOMAIN}, variabile
+@cindex variabile @code{TEXTDOMAIN}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{TEXTDOMAIN}
+@cindex internazionalizzazione, localizzazione
+@item TEXTDOMAIN #
+Usata per l'internazionalizzazione di programmi a livello di
+@command{awk}. Imposta il dominio di testo (@dfn{text domain}) di default per costanti stringa
+marcate in maniera speciale nel codice sorgente, e anche per le funzioni
+@code{dcgettext()}, @code{dcngettext()} e @code{bindtextdomain()}
+@iftex
+(@pxrefil{Internazionalizzazione}).
+@end iftex
+@ifnottex
+(@pxref{Internazionalizzazione}).
+@end ifnottex
+Il valore di default di @code{TEXTDOMAIN} @`e @code{"messages"}.
+@end table
+
+@node Variabili auto-assegnate
+@subsection Variabili predefinite con cui @command{awk} fornisce informazioni
+
+@cindex predefinite, variabili, che forniscono informazioni
+@cindex variabili predefinite, che forniscono informazioni
+Quella che segue @`e una lista in ordine alfabetico di variabili che
+@command{awk} imposta automaticamente in determinate situazioni per
+fornire informazioni a un programma.
+
+Le variabili specifiche di @command{gawk} sono contrassegnate da un
+cancelletto (@samp{#}). Queste variabili sono estensioni @command{gawk}.
+In altre implementazioni di @command{awk} o se @command{gawk} @`e in
+modalit@`a compatibile (@pxref{Opzioni}), non hanno un significato speciale:
+
+@c @asis for docbook
+@table @asis
+@cindex @code{ARGC}/@code{ARGV}, variabili
+@cindex argomenti, riga di comando
+@cindex riga di comando, argomenti
+@item @code{ARGC}, @code{ARGV}
+Gli argomenti della riga di comando disponibili ai programmi @command{awk}
+sono memorizzati in un vettore di nome
+@code{ARGV}. @code{ARGC} @`e il numero di argomenti presenti sulla
+riga di comando.
+@xref{Altri argomenti}.
+A differenza di quasi tutti i vettori di @command{awk},
+@code{ARGV} @`e indicizzato da 0 a @code{ARGC} @minus{} 1.
+Lo si pu@`o vedere nell'esempio seguente:
+
+@example
+$ @kbd{awk 'BEGIN @{}
+> @kbd{for (i = 0; i < ARGC; i++)}
+> @kbd{print ARGV[i]}
+> @kbd{@}' inventory-shipped mail-list}
+@print{} awk
+@print{} inventory-shipped
+@print{} mail-list
+@end example
+
+@noindent
+@code{ARGV[0]} contiene @samp{awk}, @code{ARGV[1]}
+contiene @samp{inventory-shipped} e @code{ARGV[2]} contiene
+@samp{mail-list}. Il valore di @code{ARGC} @`e tre, ossia uno in pi@`u
+dell'indice dell'ultimo elemento di @code{ARGV}, perch@'e gli elementi sono
+numerati a partire da zero.
+
+@cindex convenzioni di programmazione, variabili @code{ARGC}/@code{ARGV}
+I nomi @code{ARGC} e @code{ARGV}, come pure la convenzione di indicizzare
+il vettore da 0 a @code{ARGC} @minus{} 1, derivano dal modo in cui il
+linguaggio C accede agli argomenti presenti sulla riga di comando.
+
+@cindex angolo buio, valore di @code{ARGV[0]}
+Il valore di @code{ARGV[0]} pu@`o variare da sistema a sistema.
+Va anche notato che il programma @emph{non}
+@`e incluso in @code{ARGV}, e non sono incluse neppure le eventuali opzioni di
+@command{awk} specificate sulla riga di comando.
+@xref{ARGC e ARGV} per informazioni
+su come @command{awk} usa queste variabili.
+@value{DARKCORNER}
+
+@cindex @code{ARGIND}, variabile
+@cindex variabile @code{ARGIND}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{ARGIND}
+@item @code{ARGIND #}
+L'indice in @code{ARGV} del file correntemente in elaborazione.
+Ogni volta che @command{gawk} apre un nuovo @value{DF} per elaborarlo, imposta
+@code{ARGIND} all'indice in @code{ARGV} del @value{FN}.
+Quando @command{gawk} sta elaborando i file in input, il confronto
+@samp{FILENAME == ARGV[ARGIND]} @`e sempre verificato.
+
+@cindex file, elaborazione@comma{} variabile @code{ARGIND} e
+Questa variabile @`e utile nell'elaborazione dei file; consente di stabilire
+a che punto ci si trova nella lista
+di @value{DF}, e anche di distinguere tra successive occorrenze dello stesso
+@value{FN} sulla riga dei comandi.
+
+@cindex nomi di file, distinguere
+Anche se @`e possibile modificare il valore di @code{ARGIND} all'interno del
+programma @command{awk}, @command{gawk} automaticamente lo imposta a un nuovo
+valore quando viene aperto il file successivo.
+
+@cindex @code{ENVIRON}, vettore
+@cindex vettore @code{ENVIRON}
+@cindex variabili d'ambiente, nel vettore @code{ENVIRON}
+@item @code{ENVIRON}
+Un vettore associativo contenente i valori delle variabili d'ambiente.
+Gli indici del vettore sono i nomi delle variabili d'ambiente; gli elementi
+sono i valori della specifica variabile d'ambiente. Per esempio,
+@code{ENVIRON["HOME"]} potrebbe valere @code{/home/arnold}.
+
+Per POSIX @command{awk}, le modifiche a questo vettore non cambiano
+le variabili d'ambiente passate a qualsivoglia programma che @command{awk}
+pu@`o richiamare tramite una ridirezione
+o usando la funzione @code{system()}.
+
+Tuttavia, a partire dalla @value{PVERSION} 4.2, se non si @`e in
+modalit@`a compatibile POSIX, @command{gawk} aggiorna le proprie variabili
+d'ambiente, quando si modifica @code{ENVIRON}, e in questo modo sono
+modificate anche le variabili d'ambiente disponibili ai programmi richiamati.
+Un'attenzione speciale dovrebbe essere prestata alla modifica di
+@code{ENVIRON["PATH"]}, che @`e il percorso di ricerca usato per trovare
+i programmi eseguibili.
+
+Queste modifiche possono anche influire sul programma @command{gawk}, poich@'e
+alcune funzioni predefinite possono tener conto di certe
+variabili d'ambiente.
+L'esempio pi@`u notevole di una tale situazione @`e @code{mktime()}
+(@pxref{Funzioni di tempo})
+che, in molti sistemi, tiene conto del valore della
+variabile d'ambiente @env{TZ}.
+
+Alcuni sistemi operativi possono non avere variabili d'ambiente.
+In tali sistemi, il vettore @code{ENVIRON} @`e vuoto (tranne che per
+le variabili
+@w{@code{ENVIRON["AWKPATH"]}} e
+@w{@code{ENVIRON["AWKLIBPATH"]}} eventualmente presenti;
+@pxref{AWKPATH (Variabile)} e
+@ifdocbook
+@ref{AWKLIBPATH (Variabile)}).
+@end ifdocbook
+@ifnotdocbook
+@pxref{AWKLIBPATH (Variabile)}).
+@end ifnotdocbook
+
+@cindex @command{gawk}, variabile @code{ERRNO} in
+@cindex @code{ERRNO}, variabile
+@cindex variabile @code{ERRNO}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{ERRNO}
+@cindex gestione errori, variabile @code{ERRNO} e
+@item @code{ERRNO #}
+Se si verifica un errore di sistema durante una ridirezione per @code{getline},
+durante una lettura per @code{getline} o durante un'operazione di
+@code{close()}, la variabile
+@code{ERRNO} contiene una stringa che descrive l'errore.
+
+Inoltre, @command{gawk} annulla @code{ERRNO} prima di aprire ogni
+file in input presente sulla riga di comando. Questo consente di controllare
+se il file @`e accessibile
+all'interno di un criterio di ricerca @code{BEGINFILE}
+(@pxref{BEGINFILE/ENDFILE}).
+
+Per il resto, @code{ERRNO} si comporta analogamente alla variabile C
+@code{errno}.
+Tranne nel caso sopra accennato, @command{gawk} non annulla @emph{mai}
+@code{ERRNO} (lo imposta a zero o a @code{""}). Quindi, ci si deve
+aspettare che il suo valore sia significativo solo quando un'operazione
+di I/O restituisce un valore che indica il fallimento dell'operazione, come
+per esempio quando @code{getline} restituisce @minus{}1. Si @`e, naturalmente,
+liberi di annullarla prima di effettuare un'operazione di I/O.
+
+Se il valore di @code{ERRNO} corrisponde a un errore di sistema della
+variabile C @code{errno}, @code{PROCINFO["errno"]} sar@`a impostato al valore
+di @code{errno}. Per errori non di sistema, @code{PROCINFO["errno"]} sar@`a
+impostata al valore zero.
+
+@cindex @code{FILENAME}, variabile
+@cindex variabile @code{FILENAME}
+@cindex angolo buio, variabile @code{FILENAME}
+@item @code{FILENAME}
+Il nome del file in input corrente. Quando non ci sono @value{DF}
+sulla riga dei comandi, @command{awk} legge dallo standard input e
+@code{FILENAME} @`e impostato a @code{"-"}. @code{FILENAME} cambia ogni
+volta che si legge un nuovo file
+@iftex
+(@pxrefil{Leggere file}).
+@end iftex
+@ifnottex
+(@pxref{Leggere file}).
+@end ifnottex
+All'interno di una
+regola @code{BEGIN}, il valore di @code{FILENAME} @`e @code{""}, perch@'e non si
+sta elaborando alcun file in input.@footnote{Alcune tra le prime implementazioni di Unix
+@command{awk} inizializzavano @code{FILENAME} a @code{"-"}, anche se
+vi erano @value{DF} da elaborare. Un tale comportamento era incorretto e
+non ci si dovrebbe poter contare nei programmi.}
+@value{DARKCORNER} Si noti, tuttavia,
+che l'uso di @code{getline} (@pxref{Getline}) all'interno di una regola
+@code{BEGIN} pu@`o implicare l'assegnamento di un valore a @code{FILENAME}.
+
+@cindex @code{FNR}, variabile
+@cindex variabile @code{FNR}
+@item @code{FNR}
+Il numero del record corrente nel file corrente. @command{awk} incrementa
+@code{FNR} ogni volta che legge un nuovo record (@pxref{Record}).
+@command{awk} imposta nuovamente a zero @code{FNR} ogni volta che inizia a
+leggere un nuovo file in input.
+
+@cindex @code{NF}, variabile
+@cindex variabile @code{NF}
+@item @code{NF}
+Il numero di campi nel corrente record in input.
+@code{NF} @`e impostato ogni volta che si legge un nuovo record,
+quando un nuovo campo viene creato,
+o quando si modifica @code{$0} (@pxref{Campi}).
+
+A differenza di molte altre variabili descritte in questa @value{SUBSECTION},
+l'assegnamento di un valore a @code{NF} pu@`o potenzialmente influenzare
+il funzionamento interno di @command{awk}. In particolare, assegnamenti
+a @code{NF} si possono usare per aggiungere o togliere campi dal
+record corrente. @xref{Cambiare i campi}.
+
+@cindex @code{FUNCTAB}, vettore
+@cindex vettore @code{FUNCTAB}
+@cindex @command{gawk}, vettore @code{FUNCTAB} in
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{FUNCTAB}
+@item @code{FUNCTAB #}
+Un vettore i cui indici e i corrispondenti valori sono i nomi di tutte le
+funzioni predefinite, definite dall'utente ed estese, presenti nel programma.
+
+@quotation NOTA
+Il tentativo di usare l'istruzione @code{delete} per eliminare il vettore
+@code{FUNCTAB} genera un errore fatale. Genera un errore fatale anche
+ogni tentativo di impostare un elemento di @code{FUNCTAB}.
+@end quotation
+
+@cindex @code{NR}, variabile
+@cindex variabile @code{NR}
+@item @code{NR}
+Il numero di record in input che @command{awk} ha elaborato dall'inizio
+dell'esecuzione del programma
+(@pxref{Record}).
+@command{awk} incrementa @code{NR} ogni volta che legge un nuovo record.
+
+@cindex @command{gawk}, vettore @code{PROCINFO} in
+@cindex @code{PROCINFO}, vettore
+@cindex vettore @code{PROCINFO}
+@cindex differenze tra @command{awk} e @command{gawk}, vettore @code{PROCINFO}
+@item @code{PROCINFO #}
+Gli elementi di questo vettore danno accesso a informazioni sul
+programma @command{awk} in esecuzione.
+I seguenti elementi (elencati in ordine alfabetico)
+sono sicuramente sempre disponibili:
+
+@table @code
+@cindex effettivo, @dfn{ID di gruppo} dell'utente di @command{gawk}
+@item PROCINFO["egid"]
+Il valore restituito dalla chiamata di sistema @code{getegid()}.
+
+@item PROCINFO["errno"]
+Il valore della variabile C @code{ERRNO} quando @code{ERRNO} @`e impostato
+al messaggio di errore a essa associato.
+
+@item PROCINFO["euid"]
+@cindex @dfn{ID effettivo} dell'utente di @command{gawk}
+Il valore restituito dalla chiamata di sistema @code{geteuid()}.
+
+@item PROCINFO["FS"]
+Questo elemento vale
+@code{"FS"} se @`e in uso la separazione in campi con @code{FS},
+@code{"FIELDWIDTHS"} se @`e in uso quella con @code{FIELDWIDTHS},
+oppure @code{"FPAT"} se @`e in uso l'individuazione di campo con @code{FPAT}.
+
+@item PROCINFO["gid"]
+@cindex @dfn{ID di gruppo} dell'utente @command{gawk}
+Il valore restituito dalla chiamata di sistema @code{getgid()} .
+
+@item PROCINFO["identifiers"]
+@cindex programma, identificativi in un
+@cindex identificativi in un programma
+Un sottovettore, indicizzato dai nomi di tutti gli identificativi usati
+all'interno del programma @command{awk}. Un @dfn{identificativo} @`e
+semplicemente il nome di una variabile
+(scalare o vettoriale), una funzione predefinita, una funzione definita
+dall'utente, o una funzione contenuta in un'estensione.
+Per ogni identificativo, il valore dell'elemento @`e uno dei seguenti:
+
+@table @code
+@item "array"
+L'identificativo @`e un vettore.
+
+@item "builtin"
+L'identificativo @`e una funzione predefinita.
+
+@item "extension"
+L'identificativo @`e una funzione in un'estensione caricata tramite
+@code{@@load} o con l'opzione @option{-l}.
+
+@item "scalar"
+L'identificativo @`e uno scalare.
+
+@item "untyped"
+L'identificativo non ha ancora un tipo (potrebbe essere usato come scalare o
+come vettore; @command{gawk} non @`e ancora in grado di dirlo).
+
+@item "user"
+L'identificativo @`e una funzione definita dall'utente.
+@end table
+
+@noindent
+I valori riportano ci@`o che @command{gawk} sa sugli identificativi
+dopo aver finito l'analisi iniziale del programma; questi valori @emph{non}
+vengono pi@`u aggiornati durante l'esecuzione del programma.
+
+@item PROCINFO["pgrpid"]
+@cindex @dfn{process group ID} del programma @command{gawk}
+Il @dfn{ID di gruppo del processo} del programma corrente.
+
+@item PROCINFO["pid"]
+@cindex @dfn{process ID} del programma @command{gawk}
+Il @dfn{process ID} del programma corrente.
+
+@item PROCINFO["ppid"]
+@cindex @dfn{parent process ID} del programma @command{gawk}
+Il @dfn{ID di processo del padre} del programma corrente.
+
+@item PROCINFO["strftime"]
+La stringa col formato di default usato per la funzione @code{strftime()}.
+Assegnando un nuovo valore a questo elemento si cambia quello di default.
+@xref{Funzioni di tempo}.
+
+@item PROCINFO["uid"]
+Il valore restituito dalla chiamata di sistema @code{getuid()}.
+
+@item PROCINFO["version"]
+@cindex versione di @command{gawk}
+@cindex @command{gawk}, versione di
+La versione di @command{gawk}.
+@end table
+
+I seguenti elementi addizionali del vettore
+sono disponibili per fornire informazioni sulle librerie MPFR e GMP,
+se la versione in uso di @command{gawk} consente il calcolo con precisione
+arbitraria
+(@pxref{Calcolo con precisione arbitraria}):
+
+@table @code
+@item PROCINFO["gmp_version"]
+@cindex versione della libreria GNU MP
+La versione della libreria GNU MP.
+
+@cindex versione della libreria GNU MPFR
+@item PROCINFO["mpfr_version"]
+La versione della libreria GNU MPFR.
+
+@item PROCINFO["prec_max"]
+@cindex precisione massima consentita dalla libreria MPFR
+La massima precisione consentita da MPFR.
+
+@item PROCINFO["prec_min"]
+@cindex precisione minima richiesta dalla libreria MPFR
+La precisione minima richiesta da MPFR.
+@end table
+
+I seguenti elementi addizionali del vettore
+sono disponibili per fornire
+informazioni sulla versione dell'estensione API, se la versione
+di @command{gawk} prevede il caricamento dinamico di funzioni di estensione
+@iftex
+(@pxrefil{Estensioni dinamiche}):
+@end iftex
+@ifnottex
+(@pxref{Estensioni dinamiche}):
+@end ifnottex
+
+@table @code
+@item PROCINFO["api_major"]
+@cindex versione dell'estensione API @command{gawk}
+@cindex estensione API, numero di versione
+La versione principale dell'estensione API.
+
+@item PROCINFO["api_minor"]
+La versione secondaria dell'estensione API.
+@end table
+
+@cindex gruppi supplementari Unix con @command{gawk}
+Su alcuni sistemi, ci possono essere elementi nel vettore, da @code{"group1"}
+fino a @code{"group@var{N}"}. @var{N} @`e il numero di
+gruppi supplementari che il processo [Unix] possiede. Si usi l'operatore
+@code{in} per verificare la presenza di questi elementi
+(@pxref{Visitare elementi}).
+
+I seguenti elementi consentono di modificare il comportamento di
+@command{gawk}:
+
+@item PROCINFO["NONFATAL"]
+Se questo elemento esiste, gli errori di I/O per tutte le ridirezioni
+consentono la prosecuzizone del programma.
+@xref{Continuazione dopo errori}.
+
+@item PROCINFO["@var{nome_output}", "NONFATAL"]
+Gli errori in output per il file @var{nome_output}
+consentono la prosecuzizone del programma.
+@xref{Continuazione dopo errori}.
+
+@table @code
+@item PROCINFO["@var{comando}", "pty"]
+Per una comunicazione bidirezionale con @var{comando}, si usi una pseudo-tty
+invece di impostare una @dfn{pipe} bidirezionale.
+@xref{I/O bidirezionale} per ulteriori informazioni.
+
+@item PROCINFO["@var{input_name}", "READ_TIMEOUT"]
+Imposta un tempo limite per leggere dalla ridirezione di input @var{input_name}.
+@xref{Timeout in lettura} per ulteriori informazioni.
+
+@item PROCINFO["sorted_in"]
+Se questo elemento esiste in @code{PROCINFO}, il suo valore controlla
+l'ordine in cui gli indici dei vettori saranno elaborati nei cicli
+@samp{for (@var{indice} in @var{vettore})}.
+Questa @`e una funzionalit@`a avanzata, la cui descrizione completa sar@`a vista
+pi@`u avanti; si veda
+@ref{Visitare un intero vettore}.
+@end table
+
+@cindex @code{RLENGTH}, variabile
+@cindex variabile @code{RLENGTH}
+@item @code{RLENGTH}
+La lunghezza della sottostringa individuata dalla funzione
+@code{match()}
+(@pxref{Funzioni per stringhe}).
+@code{RLENGTH} viene impostata quando si richiama la funzione @code{match()}.
+Il suo
+valore @`e la lunghezza della stringa individuata, oppure @minus{}1 se non @`e
+stata trovata alcuna corrispondenza.
+
+@cindex @code{RSTART}, variabile
+@cindex variabile @code{RSTART}
+@item @code{RSTART}
+L'indice, in caratteri, da cui parte la sottostringa che @`e individuata dalla
+funzione @code{match()}
+(@pxref{Funzioni per stringhe}).
+@code{RSTART} viene impostata quando si richiama la funzione @code{match()}.
+Il suo
+valore @`e la posizione nella stringa da cui inizia la sottostringa
+individuata, oppure zero, se non @`e stata trovata alcuna corrispondenza.
+
+@cindex @command{gawk}, variabile @code{RT} in
+@cindex @code{RT}, variabile
+@cindex variabile @code{RT}
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{RT}
+@item @code{RT #}
+Il testo in input che corrisponde al testo individuato da @code{RS},
+il separatore di record. Questa variabile viene impostata dopo aver letto
+ciascun record.
+
+@cindex @command{gawk}, vettore @code{SYMTAB} in
+@cindex @code{SYMTAB}, vettore
+@cindex vettore @code{SYMTAB}
+@cindex differenze tra @command{awk} e @command{gawk}, vettore @code{SYMTAB}
+@item @code{SYMTAB #}
+Un vettore i cui indici sono i nomi di tutte le variabili globali e i vettori
+definiti nel programma. @code{SYMTAB} rende visibile al
+programmatore @command{awk} la tabella dei simboli di @command{gawk}.
+Viene preparata nella fase di analisi iniziale del programma @command{gawk}
+ed @`e completata prima di cominciare a eseguire il programma.
+
+Il vettore pu@`o essere usato per accedere indirettamente, in lettura o in
+scrittura, al valore di una variabile:
+
+@example
+pippo = 5
+SYMTAB["pippo"] = 4
+print pippo # stampa 4
+@end example
+
+@noindent
+La funzione @code{isarray()} (@pxref{Funzioni per i tipi}) si pu@`o usare per
+controllare se un elemento in @code{SYMTAB} @`e un vettore.
+Inoltre, non @`e possibile usare l'istruzione @code{delete} con il vettore
+@code{SYMTAB}.
+
+@`E possibile aggiungere a @code{SYMTAB} un elemento che non sia un
+identificativo gi@`a esistente:
+
+@example
+SYMTAB["xxx"] = 5
+print SYMTAB["xxx"]
+@end example
+
+@noindent
+Il risultato @`e quello previsto: in questo caso @code{SYMTAB} si comporta
+come un normale vettore. La sola differenza @`e che non @`e poi possibile
+cancellare @code{SYMTAB["xxx"]}.
+
+@cindex Schorr, Andrew
+Il vettore @code{SYMTAB} @`e pi@`u interessante di quel che sembra. Andrew
+Schorr fa notare che effettivamente consente di ottenere dei puntatori ai dati
+in @command{awk}. Si consideri quest'esempio:
+
+@example
+# Moltiplicazione indiretta di una qualsiasi variabile per un
+# numero a piacere e restituzione del risultato
+
+function multiply(variabile, numero)
+@{
+ return SYMTAB[variabile] *= numero
+@}
+@end example
+
+@noindent
+Si potrebbe usare in questo modo:
+
+@example
+BEGIN @{
+ risposta = 10.5
+ multiply("risposta", 4)
+ print "La risposta @`e", risposta
+@}
+@end example
+
+@noindent
+Eseguendo, il risultato @`e:
+
+@example
+$ @kbd{gawk -f risposta.awk}
+@print{} La risposta @`e 42
+@end example
+
+@quotation NOTA
+Per evitare seri paradossi temporali,
+@footnote{Per non parlare dei grossi problemi di implementazione.}
+n@'e @code{FUNCTAB} n@'e @code{SYMTAB}
+sono disponibili come elementi all'interno del vettore @code{SYMTAB}.
+@end quotation
+@end table
+
+@sidebar Modificare @code{NR} e @code{FNR}
+@cindex @code{NR}, variabile, modifica di
+@cindex variabile @code{NR}, modifica di
+@cindex @code{FNR}, variabile, modifica di
+@cindex variabile @code{FNR}, modifica di
+@cindex angolo buio, variabili @code{FNR}/@code{NR}
+@command{awk} incrementa le variabili @code{NR} e @code{FNR}
+ogni volta che legge un record, invece che impostarle al valore assoluto del
+numero di record letti. Ci@`o significa che un programma pu@`o
+modificare queste variabili e i valori cos@`{@dotless{i}} assegnati sono incrementati per
+ogni record.
+@value{DARKCORNER}
+Si consideri l'esempio seguente:
+
+@example
+$ @kbd{echo '1}
+> @kbd{2}
+> @kbd{3}
+> @kbd{4' | awk 'NR == 2 @{ NR = 17 @}}
+> @kbd{@{ print NR @}'}
+@print{} 1
+@print{} 17
+@print{} 18
+@print{} 19
+@end example
+
+@noindent
+Prima che @code{FNR} venisse aggiunto al linguaggio @command{awk}
+(@pxref{V7/SVR3.1}),
+molti programmi @command{awk} usavano questa modalit@`a per
+contare il numero di record in un file impostando a zero @code{NR} al cambiare
+di @code{FILENAME}.
+@end sidebar
+
+@node ARGC e ARGV
+@subsection Usare @code{ARGC} e @code{ARGV}
+@cindex @code{ARGC}/@code{ARGV}, variabili, come usarle
+@cindex variabili @code{ARGC}/@code{ARGV}, come usarle
+@cindex argomenti, riga di comando
+@cindex riga di comando, argomenti
+
+@iftex
+La
+@end iftex
+@ref{Variabili auto-assegnate}
+conteneva il programma seguente che visualizzava le informazioni contenute
+in @code{ARGC} e @code{ARGV}:
+
+@example
+$ @kbd{awk 'BEGIN @{}
+> @kbd{for (i = 0; i < ARGC; i++)}
+> @kbd{print ARGV[i]}
+> @kbd{@}' inventory-shipped mail-list}
+@print{} awk
+@print{} inventory-shipped
+@print{} mail-list
+@end example
+
+@noindent
+In questo esempio, @code{ARGV[0]} contiene @samp{awk}, @code{ARGV[1]}
+contiene @samp{inventory-shipped} e @code{ARGV[2]} contiene
+@samp{mail-list}.
+Si noti che il nome del programma @command{awk} non @`e incluso in @code{ARGV}.
+Le altre opzioni della riga di comando, con i relativi argomenti,
+sono parimenti non presenti, compresi anche gli assegnamenti di
+variabile fatti tramite l'opzione @option{-v}
+(@pxref{Opzioni}).
+I normali assegnamenti di variabile sulla riga dei comandi @emph{sono}
+trattati come argomenti e quindi inseriti nel vettore @code{ARGV}.
+Dato il seguente programma in un file di nome @file{vediargomenti.awk}:
+
+@example
+BEGIN @{
+ printf "A=%d, B=%d\n", A, B
+ for (i = 0; i < ARGC; i++)
+ printf "\tARGV[%d] = %s\n", i, ARGV[i]
+@}
+END @{ printf "A=%d, B=%d\n", A, B @}
+@end example
+
+@noindent
+la sua esecuzione produce il seguente risultato:
+
+@example
+$ @kbd{awk -v A=1 -f vediargomenti.awk B=2 /dev/null}
+@print{} A=1, B=0
+@print{} ARGV[0] = awk
+@print{} ARGV[1] = B=2
+@print{} ARGV[2] = /dev/null
+@print{} A=1, B=2
+@end example
+
+Un programma pu@`o modificare @code{ARGC} e gli elementi di @code{ARGV}.
+Ogni volta che @command{awk} arriva alla fine di un file in input, usa
+il successivo elemento nel vettore @code{ARGV} come nome del successivo file
+in input. Cambiando il contenuto di quella stringa, un programma
+pu@`o
+modificare la lista dei file che sono letti.
+Si usi @code{"-"} per rappresentare lo standard input. Assegnando ulteriori
+elementi e incrementando @code{ARGC}
+verranno letti ulteriori file.
+
+Se il valore di @code{ARGC} viene diminuto, vengono ignorati i file in input
+posti alla fine della lista. Memorizzando il valore originale di @code{ARGC}
+da qualche altra parte, un programma pu@`o gestire gli argomenti
+ignorati come se fossero qualcosa di diverso dai @value{FN}.
+
+Per eliminare un file che sia in mezzo alla lista, si imposti in @code{ARGV}
+la stringa nulla
+(@code{""}) al posto del nome del file in questione. Come funzionalit@`a
+speciale, @command{awk} ignora valori di @value{FN} che siano stati
+rimpiazzati con la stringa nulla.
+Un'altra possibilit@`a @`e quella
+di usare l'istruzione @code{delete} per
+togliere elementi da @code{ARGV} (@pxref{Cancellazione}).
+
+Tutte queste azioni sono tipicamente eseguite nella regola @code{BEGIN},
+prima di iniziare l'elaborazione vera e propria dell'input.
+@xref{Programma split} e
+@ifnotdocbook
+@pxref{Programma tee}
+@end ifnotdocbook
+@ifdocbook
+@ref{Programma tee}
+@end ifdocbook
+per esempi
+su ognuno dei modi per togliere elementi dal vettore @code{ARGV}.
+
+Per passare direttamente delle opzioni a un programma scritto in
+@command{awk}, si devono terminare le opzioni di @command{awk} con
+@option{--} e poi inserire le opzioni destinate al programma @command{awk},
+come mostrato qui di seguito:
+
+@example
+awk -f mio_programma.awk -- -v -q file1 file2 @dots{}
+@end example
+
+Il seguente frammento di programma ispeziona @code{ARGV} per esaminare, e
+poi rimuovere, le opzioni sulla riga di comando viste sopra:
+
+@example
+BEGIN @{
+ for (i = 1; i < ARGC; i++) @{
+ if (ARGV[i] == "-v")
+ verbose = 1
+ else if (ARGV[i] == "-q")
+ debug = 1
+ else if (ARGV[i] ~ /^-./) @{
+ e = sprintf("%s: opzione non riconosciuta -- %c",
+ ARGV[0], substr(ARGV[i], 2, 1))
+ print e > "/dev/stderr"
+ @} else
+ break
+ delete ARGV[i]
+ @}
+@}
+@end example
+
+@cindex differenze tra @command{awk} e @command{gawk}, variabili @code{ARGC}/@code{ARGV}
+Terminare le opzioni di @command{awk} con @option{--} non @`e
+necessario in @command{gawk}. A meno che non si specifichi @option{--posix},
+@command{gawk} inserisce, senza emettere messaggi, ogni opzione non
+riconosciuta
+nel vettore @code{ARGV} perch@'e sia trattata dal programma @command{awk}.
+Dopo aver trovato un'opzione non riconosciuta, @command{gawk} non cerca
+ulteriori opzioni, anche se ce ne fossero di riconoscibili.
+La riga dei comandi precedente sarebbe
+con @command{gawk}:
+
+@example
+gawk -f mio_programma.awk -q -v file1 file2 @dots{}
+@end example
+
+@noindent
+Poich@'e @option{-q} non @`e un'opzione valida per @command{gawk}, quest'opzione
+e l'opzione @option{-v} che segue sono passate al programma @command{awk}.
+(@xref{Funzione getopt} per una funzione di libreria @command{awk}
+che analizza le opzioni della riga di comando.)
+
+Nel progettare un programma, si dovrebbero scegliere opzioni che non
+siano in conflitto con quelle di @command{gawk}, perch@'e ogni opzioni
+accettata da @command{gawk} verr@`a elaborata prima di passare il resto
+della riga dei comandi al programma @command{awk}.
+Usare @samp{#!} con l'opzione @option{-E} pu@`o essere utile in questo caso
+(@pxref{@dfn{Script} eseguibili}
+e
+@ifnotdocbook
+@pxref{Opzioni}).
+@end ifnotdocbook
+@ifdocbook
+@ref{Opzioni}).
+@end ifdocbook
+
+@node Sommario criteri e azioni
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+Coppie @dfn{criterio di ricerca--azione} sono gli elementi base di un
+programma @command{awk}. I criteri di ricerca possono essere espressioni
+normali, espressioni di intervallo, o costanti @dfn{regexp}; possono anche
+essere i criteri speciali @code{BEGIN}, @code{END},
+@code{BEGINFILE} o @code{ENDFILE}; o essere omessi. L'azione viene eseguita
+se il record corrente soddisfa il criterio di ricerca. Criteri di ricerca
+vuoti (omessi) corrispondono a
+tutti i record in input.
+
+@item
+L'I/O effettuato nelle azioni delle regole @code{BEGIN} ed @code{END}
+ha alcuni vincoli.
+Questo vale a maggior ragione per le regole @code{BEGINFILE} ed
+@code{ENDFILE}. Queste ultime due forniscono degli ``agganci'' per interagire
+con l'elaborazione dei file fatta da @command{gawk},
+consentendo di risolvere situazioni che altrimenti genererebbero degli
+errori fatali (ad esempio per un file che non si @`e autorizzati
+a leggere).
+
+@item
+Le variabili di shell possono essere usate nei programmi @command{awk}
+prestando la dovuta attenzione all'uso degli apici.
+@`E pi@`u facile passare una variabile di shell ad
+@command{awk} usando l'opzione @option{-v} e una variabile @command{awk}.
+
+@item
+Le azioni sono formate da istruzioni racchiuse tra parentesi graffe.
+Le istruzioni sono composte da
+espressioni, istruzioni di controllo,
+istruzioni composte,
+istruzioni di input/output e istruzioni di cancellazione.
+
+@item
+Le istruzioni di controllo in @command{awk} sono @code{if}-@code{else},
+@code{while}, @code{for} e @code{do}-@code{while}. @command{gawk}
+aggiunge l'istruzione @code{switch}. Ci sono due tipi di istruzione
+@code{for}: uno per eseguire dei cicli, e l'altro per esaminare un vettore.
+
+@item
+Le istruzioni @code{break} e @code{continue} permettono di uscire
+velocemente da un ciclo, o di passare alla successiva iterazione dello
+stesso (o di uscire da un'istruzione @code{switch}).
+
+@item
+Le istruzioni @code{next} e @code{nextfile} permettono, rispettivamente,
+di passare al record successivo, ricominciando l'elaborazione dalla prima
+regola del programma, o di passare al successivo file in input, sempre
+ripartendo dalla prima regola del programma.
+
+@item
+L'istruzione @code{exit} termina il programma. Quando @`e eseguita
+dall'interno di un'azione (o nel corpo di una funzione), trasferisce
+il controlla alle eventuali istruzioni @code{END}. Se @`e eseguita nel corpo
+di un'istruzione @code{END}, il programma @`e terminato
+immediatamente. @`E possibile specificare un valore numerico da usare come
+codice di ritorno di @command{awk}.
+
+@item
+Alcune variabili predefinite permettono di controllare @command{awk},
+principalmente per l'I/O. Altre variabili trasmettono informazioni
+da @command{awk} al programma.
+
+@item
+I vettori @code{ARGC} e @code{ARGV} rendono disponibili al programma gli
+argomenti della riga di comando. Una loro modifica all'interno di una regola
+@code{BEGIN} permette di controllare come @command{awk} elaborer@`a i @value{DF}
+in input.
+
+@end itemize
+
+@node Vettori
+@chapter Vettori in @command{awk}
+@cindex vettori
+
+Un @dfn{vettore} @`e una tabella di valori chiamati @dfn{elementi}. Gli
+elementi di un vettore sono individuati dai loro @dfn{indici}. Gli indici
+possono essere numeri o stringhe.
+
+Questo @value{CHAPTER} descrive come funzionano i vettori in @command{awk},
+come usare gli elementi di un vettore, come visitare tutti gli elementi
+di un vettore, e come rimuovere elementi da un vettore.
+Descrive anche come @command{awk} simula vettori multidimensionali,
+oltre ad alcuni aspetti meno ovvii sull'uso dei vettori.
+Il @value{CHAPTER} prosegue illustrando la funzionalit@`a di ordinamento dei
+vettori di @command{gawk}, e termina con una breve descrizione della capacit@`a
+di @command{gawk} di consentire veri vettori di vettori.
+
+@menu
+* Fondamenti sui vettori:: Informazioni di base sui vettori.
+* Indici numerici di vettore:: Come usare numeri come indici in
+ @command{awk}.
+* Indici non inizializzati:: Usare variabili non inizializzate come indici.
+* Cancellazione:: L'istruzione @code{delete} toglie un elemento
+ da un vettore.
+* Vettori multidimensionali:: Emulare vettori multidimensionali in
+ @command{awk}.
+* Vettori di vettori:: Vettori multidimensionali veri.
+* Sommario dei vettori:: Sommario dei vettori.
+@end menu
+
+@node Fondamenti sui vettori
+@section Informazioni di base sui vettori
+
+Questa @value{SECTION} espone le nozioni fondamentali: elaborare gli elementi
+di un vettore uno alla volta, e visitare sequenzialmente tutti gli elementi
+di un vettore.
+
+@menu
+* Introduzione ai vettori:: Introduzione ai vettori
+* Visitare elementi:: Come esaminare un elemento di un vettore.
+* Impostare elementi:: Come cambiare un elemento di un vettore.
+* Esempio di vettore:: Esempio semplice di vettore
+* Visitare un intero vettore:: Variazione dell'istruzione @code{for}. Esegue
+ un ciclo attraverso gli indici degli elementi
+ contenuti in un vettore.
+* Controllare visita:: Controllare l'ordine in cui i vettori sono
+ visitati.
+@end menu
+
+@node Introduzione ai vettori
+@subsection Introduzione ai vettori
+
+@cindex Wall, Larry
+@quotation
+@i{Visitare sequenzialmente un vettore associativo @`e come tentare di
+lapidare qualcuno usando una mitragliatrice Uzi carica.}
+@author Larry Wall
+@end quotation
+
+Il linguaggio @command{awk} mette a disposizione vettori monodimensionali per
+memorizzare gruppi di stringhe o di numeri correlati fra loro. Ogni vettore di
+@command{awk} deve avere un nome. I nomi dei vettori hanno la stessa sintassi
+dei nomi di variabile; qualsiasi nome valido di variabile potrebbe essere anche
+un valido nome di vettore. Un nome per@`o non pu@`o essere usato in entrambi i
+modi (come vettore e come variabile) nello stesso programma @command{awk}.
+
+I vettori in @command{awk} assomigliano superficialmente ai vettori in altri
+linguaggi di programmazione, ma ci sono differenze fondamentali. In
+@command{awk}, non @`e necessario specificare la dimensione di un vettore prima
+di iniziare a usarlo. In pi@`u, qualsiasi numero o stringa pu@`o essere usato
+come indice di un vettore, non solo numeri interi consecutivi.
+
+Nella maggior parte degli altri linguaggi, i vettori devono essere
+@dfn{dichiarati} prima dell'uso, specificando quanti elementi o componenti
+contengono. In questi linguaggi, la dichiarazione causa l'allocazione, per
+questi elementi, di un blocco di memoria contiguo.
+Normalmente, un indice di un vettore dev'essere un intero non negativo.
+Per esempio, l'indice zero specifica il primo elemento nel vettore, che @`e
+effettivamente memorizzato all'inizio di un blocco di memoria. L'indice uno
+specifica il secondo elemento, che @`e memorizzato subito dopo il primo elemento,
+e cos@`{@dotless{i}} via. @`E impossibile aggiungere ulteriori elementi al vettore, perch@'e
+esso pu@`o contenere solo il numero di elementi dichiarato.
+(Alcuni linguaggi consentono indici iniziali e finali arbitrari---p.es.,
+@samp{15 .. 27}---per@`o la dimensione del vettore rimane fissa una volta che
+il vettore sia stato dichiarato.)
+
+@c 1/2015: Do not put the numeric values into @code. Array element
+@c values are no different than scalar variable values.
+Un vettore contiguo di quattro elementi potrebbe essere come quello in
+@ifnotdocbook
+@ref{vettore-elementi},
+@end ifnotdocbook
+@ifdocbook
+come mostrato in @inlineraw{docbook, <xref linkend="vettore-elementi"/>}:
+@end ifdocbook
+concettualmente, se i valori degli elementi sono 8, @code{"pippo"},
+@code{""} e 30.
+
+@ifnotdocbook
+@float Figura,vettore-elementi
+@caption{Un vettore contiguo}
+@ifset SMALLPRINT
+@center @image{vettore-elementi, 11cm, , Un vettore contiguo}
+@end ifset
+@ifclear SMALLPRINT
+@center @image{vettore-elementi, , , Un vettore contiguo}
+@end ifclear
+@end float
+@end ifnotdocbook
+
+@docbook
+<figure id="vettore-elementi" float="0">
+<title>Un vettore contiguo</title>
+<mediaobject>
+<imageobject role="web"><imagedata fileref="vettore-elementi.png" format="PNG"/></imageobject>
+</mediaobject>
+</figure>
+@end docbook
+
+@noindent
+Vengono memorizzati solo i valori; gli indici sono definiti implicitamente
+dall'ordine dei valori. Qui, 8 @`e il valore il cui indice @`e zero, perch@'e 8
+appare nella posizione con zero elementi prima di essa.
+
+@cindex vettori, indicizzazione
+@cindex indicizzare i vettori
+@cindex associativi, vettori
+@cindex vettori associativi
+I vettori in @command{awk} non sono di questo tipo: sono invece
+@dfn{associativi}.
+Ci@`o significa che ogni vettore @`e un insieme di coppie, ognuna costituita
+da un indice e dal corrispondente valore dell'elemento del vettore:
+
+@ifnotdocbook
+@c extra empty column to indent it right
+@multitable @columnfractions .1 .1 .1
+@headitem @tab Indice @tab Valore
+@item @tab @code{3} @tab @code{30}
+@item @tab @code{1} @tab @code{"pippo"}
+@item @tab @code{0} @tab @code{8}
+@item @tab @code{2} @tab @code{""}
+@end multitable
+@end ifnotdocbook
+
+@docbook
+<informaltable>
+<tgroup cols="2">
+<colspec colname="1" align="left"/>
+<colspec colname="2" align="left"/>
+<thead>
+<row>
+<entry>Indice</entry>
+<entry>Valore</entry>
+</row>
+</thead>
+
+<tbody>
+<row>
+<entry><literal>3</literal></entry>
+<entry><literal>30</literal></entry>
+</row>
+
+<row>
+<entry><literal>1</literal></entry>
+<entry><literal>"pippo"</literal></entry>
+</row>
+
+<row>
+<entry><literal>0</literal></entry>
+<entry><literal>8</literal></entry>
+</row>
+
+<row>
+<entry><literal>2</literal></entry>
+<entry><literal>""</literal></entry>
+</row>
+
+</tbody>
+</tgroup>
+</informaltable>
+
+@end docbook
+
+@noindent
+Le coppie sono elencate in ordine casuale perch@'e il loro ordinamento @`e
+irrilevante.@footnote{L'ordine potr@`a variare nelle diverse implementazioni
+di @command{awk}, che tipicamente usa tabelle @dfn{hash} per memorizzare
+elementi e valori del vettore.}
+
+Un vantaggio dei vettori associativi @`e che si possono aggiungere nuove coppie
+in qualsiasi momento. Per esempio, supponiamo di aggiungere al vettore un
+decimo elemento il cui valore sia @w{@code{"numero dieci"}}. Il risultato sar@`a:
+
+@ifnotdocbook
+@c extra empty column to indent it right
+@multitable @columnfractions .1 .1 .3
+@headitem @tab Indice @tab Valore
+@item @tab @code{10} @tab @code{"numero dieci"}
+@item @tab @code{3} @tab @code{30}
+@item @tab @code{1} @tab @code{"pippo"}
+@item @tab @code{0} @tab @code{8}
+@item @tab @code{2} @tab @code{""}
+@end multitable
+@end ifnotdocbook
+
+@docbook
+<informaltable>
+<tgroup cols="2">
+<colspec colname="1" align="left"/>
+<colspec colname="2" align="left"/>
+<thead>
+<row>
+<entry>Indice</entry>
+<entry>Valore</entry>
+</row>
+</thead>
+<tbody>
+
+<row>
+<entry><literal>10</literal></entry>
+<entry><literal>"numero dieci"</literal></entry>
+</row>
+
+<row>
+<entry><literal>3</literal></entry>
+<entry><literal>30</literal></entry>
+</row>
+
+<row>
+<entry><literal>1</literal></entry>
+<entry><literal>"pippo"</literal></entry>
+</row>
+
+<row>
+<entry><literal>0</literal></entry>
+<entry><literal>8</literal></entry>
+</row>
+
+<row>
+<entry><literal>2</literal></entry>
+<entry><literal>""</literal></entry>
+</row>
+
+</tbody>
+</tgroup>
+</informaltable>
+
+@end docbook
+
+@noindent
+@cindex sparsi, vettori
+@cindex vettori sparsi
+Ora il vettore @`e @dfn{sparso}, il che significa semplicemente che non sono
+usati alcuni indici. Ha gli elementi 0, 1, 2, 3 e 10, ma mancano gli
+elementi 4, 5, 6, 7, 8 e 9.
+
+Un'altra caratteristica dei vettori associativi @`e che gli indici non devono
+essere necessariamente interi non negativi. Qualsiasi numero, o anche una
+stringa, pu@`o essere un indice. Per esempio, il seguente @`e un vettore che
+traduce delle parole dall'inglese all'italiano:
+
+@ifnotdocbook
+@multitable @columnfractions .1 .1 .1
+@headitem @tab Indice @tab Valore
+@item @tab @code{"dog"} @tab @code{"cane"}
+@item @tab @code{"cat"} @tab @code{"gatto"}
+@item @tab @code{"one"} @tab @code{"uno"}
+@item @tab @code{1} @tab @code{"uno"}
+@end multitable
+@end ifnotdocbook
+
+@docbook
+<informaltable>
+<tgroup cols="2">
+<colspec colname="1" align="left"/>
+<colspec colname="2" align="left"/>
+<thead>
+<row>
+<entry>Indice</entry>
+<entry>Valore</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry><literal>"dog"</literal></entry>
+<entry><literal>"cane"</literal></entry>
+</row>
+
+<row>
+<entry><literal>"cat"</literal></entry>
+<entry><literal>"gatto"</literal></entry>
+</row>
+
+<row>
+<entry><literal>"one"</literal></entry>
+<entry><literal>"uno"</literal></entry>
+</row>
+
+<row>
+<entry><literal>1</literal></entry>
+<entry><literal>"uno"</literal></entry>
+</row>
+
+</tbody>
+</tgroup>
+</informaltable>
+
+@end docbook
+
+@noindent
+Qui abbiamo deciso di tradurre il numero uno sia nella forma letterale che in
+quella numerica, per illustrare che un singolo vettore pu@`o avere come indici
+sia numeri che stringhe.
+(In effetti, gli indici dei vettori sono sempre stringhe.
+Ci sono alcune sottigliezze su come funzionano i numeri quando sono usati come
+indici dei vettori; questo verr@`a trattato in maggior dettaglio nella
+@ref{Indici numerici di vettore}.)
+Qui sopra, il numero @code{1} non @`e tra doppi apici, perch@'e @command{awk}
+lo converte automaticamente in una stringa.
+
+@cindex @command{gawk}, variabile @code{IGNORECASE} in
+@cindex maiuscolo/minuscolo, distinzione, indici dei vettori e
+@cindex vettori, ordinamento, variabile @code{IGNORECASE} e
+@cindex @code{IGNORECASE}, variabile, e indici dei vettori
+@cindex variabile @code{IGNORECASE}, e indici dei vettori
+Il valore di @code{IGNORECASE} non ha alcun effetto sull'indicizzazione dei
+vettori. Lo stesso valore di stringa usato per memorizzare un elemento di un
+vettore pu@`o essere usato per richiamarlo.
+Quando @command{awk} crea un vettore (p.es., con la funzione predefinita
+@code{split()}), gli indici di quel vettore sono numeri interi consecutivi
+a partire da uno.
+(@xref{Funzioni per stringhe}.)
+
+I vettori di @command{awk} sono efficienti: il tempo necessario per accedere a
+un elemento @`e indipendente dal numero di elementi nel vettore.
+
+@node Visitare elementi
+@subsection Come esaminare un elemento di un vettore
+@cindex vettori, esaminare elementi
+@cindex vettore, elementi di un
+@cindex elementi di un vettore
+
+Il modo principale di usare un vettore @`e quello di esaminare uno dei suoi
+elementi. Un @dfn{riferimento al vettore} @`e un'espressione come questa:
+
+@example
+@var{vettore}[@var{espressione-indice}]
+@end example
+
+@noindent
+Qui, @var{vettore} @`e il nome di un vettore. L'espressione
+@var{espressione-indice} @`e l'indice dell'elemento del vettore che si vuol
+esaminare.
+
+@c 1/2015: Having the 4.3 in @samp is a little iffy. It's essentially
+@c an expression though, so leave be. It's to early in the discussion
+@c to mention that it's really a string.
+Il valore del riferimento al vettore @`e il valore corrente di quell'elemento
+del vettore. Per esempio, @code{pippo[4.3]} @`e un'espressione che richiama
+l'elemento del vettore @code{pippo} il cui indice @`e @samp{4.3}.
+
+@cindex vettori, elementi non assegnati
+@cindex elementi di vettore non assegnati
+@cindex elementi di vettore vuoti
+Un riferimento a un elemento di un vettore il cui indice non esiste ancora
+restituisce un valore uguale a @code{""}, la stringa nulla. Questo comprende
+elementi a cui non @`e stato assegnato un valore ed elementi che sono stati
+eliminati (@pxref{Cancellazione}).
+
+@cindex elementi inesistenti di un vettore
+@cindex vettori, elementi che non esistono
+@quotation NOTA
+Un riferimento a un elemento inesistente crea @emph{automaticamente}
+quell'elemento di vettore, con la stringa nulla come valore. (In certi casi,
+ci@`o @`e indesiderabile, perch@'e potrebbe sprecare memoria all'interno di
+@command{awk}.)
+
+I programmatori principianti di @command{awk} fanno spesso l'errore di
+verificare se un elemento esiste controllando se il valore @`e vuoto:
+
+@example
+# Verifica se "pippo" esiste in a: @ii{Non corretto!}
+if (a["pippo"] != "") @dots{}
+@end example
+
+@noindent
+Questo @`e sbagliato per due motivi. Primo, @emph{crea} @code{a["pippo"]}
+se ancora non esisteva! Secondo, assegnare a un elemento di un vettore la
+stringa vuota come valore @`e un'operazione valida (anche se un po' insolita).
+@end quotation
+
+@c @cindex arrays, @code{in} operator and
+@cindex @code{in}, operatore, verificare se un elemento esiste in un vettore
+Per determinare se un elemento con un dato indice esiste in un vettore,
+si usi la seguente espressione:
+
+@example
+@var{indice} in @var{vettore}
+@end example
+
+@cindex effetti collaterali, indicizzazione di vettori
+@noindent
+Quest'espressione verifica se lo specifico indice @var{indice} esiste, senza
+l'effetto collaterale di creare quell'elemento nel caso che esso non sia
+presente. L'espressione ha il valore uno (vero) se
+@code{@var{vettore}[@var{indice}]}
+esiste e zero (falso) se non esiste.
+@c (Qui usiamo @var{indx}, perch@'e @samp{index} @`e il nome di una funzione
+@c predefinita.)
+Per esempio, quest'istruzione verifica se il vettore @code{frequenze}
+contiene l'indice @samp{2}:
+
+@example
+if (2 in frequenze)
+ print "L'indice 2 @`e presente."
+@end example
+
+Si noti che questo @emph{non} verifica se il vettore
+@code{frequenze} contiene un elemento il cui @emph{valore} @`e 2.
+Il solo modo far questo @`e quello di passare in rassegna tutti gli
+elementi. Inoltre, questo @emph{non} crea @code{frequenze[2]}, mentre la
+seguente alternativa (non corretta) lo fa:
+
+@example
+if (frequenze[2] != "")
+ print "L'indice 2 @`e presente."
+@end example
+
+@node Impostare elementi
+@subsection Assegnare un valore a elementi di un vettore
+@cindex vettori, elementi, assegnare valori
+@cindex elementi di vettori, assegnare valori
+
+Agli elementi di un vettore possono essere assegnati valori proprio come
+alle variabili di @command{awk}:
+
+@example
+@var{vettore}[@var{espressione-indice}] = @var{valore}
+@end example
+
+@noindent
+@var{vettore} @`e il nome di un vettore. L'espressione
+@var{espressione-indice} @`e l'indice dell'elemento del vettore a cui @`e
+assegnato il valore. L'espressione @var{valore} @`e il valore da assegnare
+a quell'elemento del vettore.
+
+@node Esempio di vettore
+@subsection Esempio semplice di vettore
+@cindex vettori, un esempio sull'uso
+
+Il seguente programma prende una lista di righe, ognuna delle quali inizia con
+un numero di riga, e le stampa in ordine di numero di riga. I numeri di riga
+non sono ordinati al momento della lettura, ma sono invece in ordine sparso.
+Questo programma ordina le righe mediante la creazione di un vettore che usa
+i numeri di riga come indici. Il programma stampa poi le righe
+ordinate secondo il loro numero. @`E un programma molto semplice e non @`e in
+grado di gestire numeri ripetuti, salti di riga o righe che non
+iniziano con un numero:
+
+@example
+@c file eg/misc/arraymax.awk
+@{
+ if ($1 > massimo)
+ massimo = $1
+ vett[$1] = $0
+@}
+
+END @{
+ for (x = 1; x <= massimo; x++)
+ print vett[x]
+@}
+@c endfile
+@end example
+
+La prima regola tiene traccia del numero di riga pi@`u grande visto
+durante la lettura;
+memorizza anche ogni riga nel vettore @code{vett}, usando come indice
+il numero di riga.
+La seconda regola viene eseguita dopo che @`e stato letto tutto l'input, per
+stampare tutte le righe.
+Quando questo programma viene eseguito col seguente input:
+
+@example
+@c file eg/misc/arraymax.data
+5 Io sono l'uomo Cinque
+2 Chi sei? Il nuovo numero due!
+4 . . . E quattro a terra
+1 Chi @`e il numero uno?
+3 Sei il tre.
+@c endfile
+@end example
+
+@noindent
+Il suo output @`e:
+
+@example
+1 Chi @`e il numero uno?
+2 Chi sei? Il nuovo numero due!
+3 Sei il tre.
+4 . . . E quattro a terra
+5 Io sono l'uomo Cinque
+@end example
+
+Se un numero di riga appare pi@`u di una volta, l'ultima riga con quel dato
+numero prevale sulle altre.
+Le righe non presenti nel vettore
+si possono saltare con un semplice perfezionamento della
+regola @code{END} del programma, in questo modo:
+
+@example
+END @{
+ for (x = 1; x <= massimo; x++)
+ if (x in vett)
+ print vett[x]
+@}
+@end example
+
+@node Visitare un intero vettore
+@subsection Visitare tutti gli elementi di un vettore
+@cindex elementi di vettori, visitare
+@cindex visitare vettori
+@cindex vettori, visitare
+@cindex cicli, @code{for}, visita di un vettore
+
+Nei programmi che usano vettori, @`e spesso necessario usare un ciclo che
+esegue un'azione su ciascun elemento di un vettore. In altri linguaggi, dove
+i vettori sono contigui e gli indici sono limitati ai numeri interi
+non negativi,
+questo @`e facile: tutti gli indici validi possono essere visitati partendo
+dall'indice pi@`u basso e arrivando a quello pi@`u alto. Questa tecnica non
+@`e applicabile in @command{awk}, perch@'e qualsiasi numero o stringa pu@`o
+fare da indice in un vettore. Perci@`o @command{awk} ha un tipo speciale di
+istruzione @code{for} per visitare un vettore:
+
+@example
+for (@var{variabile} in @var{vettore})
+ @var{corpo}
+@end example
+
+@noindent
+@cindex @code{in}, operatore, uso in cicli
+@cindex operatore @code{in}, uso in cicli
+Questo ciclo esegue @var{corpo} una volta per ogni indice in @var{vettore} che
+il programma ha usato precedentemente, con la variabile @var{variabile}
+impostata a quell'indice.
+
+@cindex vettori, istruzione @code{for} e
+@cindex @code{for}, istruzione, esecuzione di cicli su un vettore
+Il seguente programma usa questa forma dell'istruzione @code{for}. La
+prima regola visita i record in input e tiene nota di quali parole appaiono
+(almeno una volta) nell'input, memorizzando un 1 nel vettore @code{usate} con
+la parola come indice. La seconda regola visita gli elementi di
+@code{usate} per trovare tutte le parole distinte che appaiono nell'input.
+Il programma stampa poi ogni parola che @`e pi@`u lunga di 10 caratteri e
+anche il numero di tali parole.
+@xref{Funzioni per stringhe}
+per maggiori informazioni sulla funzione predefinita @code{length()}.
+
+@example
+# Registra un 1 per ogni parola usata almeno una volta
+@{
+ for (i = 1; i <= NF; i++)
+ usate[$i] = 1
+@}
+
+# Trova il numero di parole distinte lunghe pi@`u di 10 caratteri
+END @{
+ for (x in usate) @{
+ if (length(x) > 10) @{
+ ++numero_parole_lunghe
+ print x
+ @}
+ @}
+ print numero_parole_lunghe, "parole pi@`u lunghe di 10 caratteri"
+@}
+@end example
+
+@noindent
+@xref{Programma utilizzo parole}
+per un esempio di questo tipo pi@`u dettagliato.
+
+@cindex vettori, elementi di, ordine di accesso da parte dell'operatore @code{in}
+@cindex elementi di vettori, ordine di accesso da parte dell'operatore @code{in}
+@cindex @code{in}, operatore, ordine di accesso dei vettori
+@cindex operatore @code{in}, ordine di accesso dei vettori
+L'ordine nel quale gli elementi del vettore sono esaminati da quest'istruzione
+@`e determinato dalla disposizione interna degli elementi del vettore all'interno
+di @command{awk} e nell'@command{awk} standard non pu@`o essere controllato
+o cambiato. Questo pu@`o portare a dei problemi se vengono aggiunti nuovi
+elementi al @var{vettore} dall'istruzione eseguendo il corpo del ciclo;
+non @`e prevedibile se il ciclo @code{for} li potr@`a raggiungere. Similmente,
+modificare @var{variabile} all'interno del ciclo potrebbe produrre strani
+risultati. @`E meglio evitare di farlo.
+
+Di sicuro, @command{gawk} imposta la lista di elementi su cui eseguire
+l'iterazione prima che inizi il ciclo, e non la cambia in corso d'opera.
+Ma non tutte le versioni di @command{awk} fanno cos@`{@dotless{i}}. Si consideri questo
+programma, chiamato @file{vediciclo.awk}:
+
+@example
+BEGIN @{
+ a["questo"] = "questo"
+ a["@`e"] = "@`e"
+ a["un"] = "un"
+ a["ciclo"] = "ciclo"
+ for (i in a) @{
+ j++
+ a[j] = j
+ print i
+ @}
+@}
+@end example
+
+Ecco quel che accade quando viene eseguito con @command{gawk} (e @command{mawk}):
+
+@example
+$ @kbd{gawk -f vediciclo.awk}
+@print{} questo
+@print{} ciclo
+@print{} un
+@print{} @`e
+@end example
+
+Se si usa invece BWK @command{awk}:
+
+@example
+$ @kbd{nawk -f vediciclo.awk}
+@print{} ciclo
+@print{} questo
+@print{} @`e
+@print{} un
+@print{} 1
+@end example
+
+@node Controllare visita
+@subsection Visita di vettori in ordine predefinito con @command{gawk}
+
+Questa @value{SUBSECTION} descrive una funzionalit@`a disponibile solo in
+@command{gawk}.
+
+Per default, quando un ciclo @code{for} visita un vettore, l'ordine
+@`e indeterminato, il che vuol dire che l'implementazione di @command{awk}
+determina l'ordine in cui il vettore viene attraversato.
+Quest'ordine normalmente @`e basato sull'implementazione interna dei vettori
+e varia da una versione di @command{awk} alla successiva.
+
+@cindex vettori, ordine di visita, controllo dell'
+@cindex controllare l'ordine di visita dei vettori
+Spesso, tuttavia, servirebbe fare qualcosa di semplice, come
+``visitare il vettore confrontando gli indici in ordine crescente,''
+o ``visitare il vettore confrontando i valori in ordine decrescente.''
+@command{gawk} fornisce due meccanismi che permettono di farlo.
+
+@itemize @value{BULLET}
+@item
+Assegnare a @code{PROCINFO["sorted_in"]} un valore a scelta fra
+alcuni valori predefiniti.
+Si vedano pi@`u sotto i valori ammessi.
+
+@item
+Impostare @code{PROCINFO["sorted_in"]} al nome di una funzione definita
+dall'utente, da usare per il confronto tra gli elementi di un vettore. Questa
+funzionalit@`a avanzata verr@`a descritta in seguito in @ref{Ordinamento di vettori}.
+@end itemize
+
+@cindex @code{PROCINFO}, valori di @code{sorted_in}
+Sono disponibili i seguenti valori speciali per @code{PROCINFO["sorted_in"]}:
+
+@table @code
+@item "@@unsorted"
+Lasciare gli elementi del vettore in ordine arbitrario
+(questo @`e il comportamento di default di @command{awk}).
+
+@item "@@ind_str_asc"
+Ordinare in ordine crescente di indice, confrontando tra loro gli indici
+come stringhe; questo @`e l'ordinamento pi@`u normale.
+(Internamente, gli indici dei vettori sono sempre stringhe, per cui con
+@samp{a[2*5] = 1} l'indice @`e la stringa @code{"10"} e non il numero 10.)
+
+@item "@@ind_num_asc"
+Ordinare in ordine crescente di indice, ma nell'elaborazione gli indici vengono
+trattati come numeri. Gli indici con valore non numerico verranno posizionati
+come se fossero uguali a zero.
+
+@item "@@val_type_asc"
+Ordinare secondo il valore degli elementi in ordine crescente (invece che in
+base agli indici). L'ordinamento @`e in base al tipo assegnato all'elemento
+(@pxref{Tipi di variabile e confronti}).
+Tutti i valori numerici precedono tutti i valori di tipo stringa,
+che a loro volta vengono prima dei sottovettori.
+(I sottovettori non sono ancora stati descritti;
+@pxref{Vettori di vettori}.)
+
+@item "@@val_str_asc"
+Ordinare secondo il valore degli elementi in ordine crescente (invece che in
+base agli indici). I valori scalari sono confrontati come stringhe.
+I sottovettori, se presenti, vengono per ultimi.
+
+@item "@@val_num_asc"
+Ordinare secondo il valore degli elementi in ordine crescente (invece che in
+base agli indici). I valori scalari sono confrontati come numeri.
+I sottovettori, se presenti, vengono per ultimi.
+Quando i valori numerici coincidono, vengono usati i valori di tipo stringa
+per stabilire un ordinamento: ci@`o garantisce risultati coerenti tra differenti
+versioni della funzione C @code{qsort()},@footnote{Quando due elementi
+risultano uguali, la funzione C @code{qsort()} non garantisce
+che dopo l'ordinamento venga rispettato il loro ordine relativo originale.
+Usando il valore di stringa per stabilire un ordinamento univoco quando i
+valori numerici sono uguali assicura che il comportamento di @command{gawk}
+sia coerente in differenti ambienti.} che @command{gawk} usa internamente
+per effettuare l'ordinamento.
+
+@item "@@ind_str_desc"
+Ordinare come fa @code{"@@ind_str_asc"}, ma gli
+indici di tipo stringa sono ordinati dal pi@`u alto al pi@`u basso.
+
+@item "@@ind_num_desc"
+Ordinare come fa @code{"@@ind_num_asc"}, ma gli
+indici numerici sono ordinati dal pi@`u alto al pi@`u basso.
+
+@item "@@val_type_desc"
+Ordinare come fa @code{"@@val_type_asc"}, ma i valori
+degli elementi, a seconda del tipo, sono ordinati dal pi@`u alto al pi@`u basso.
+I sottovettori, se presenti, vengono per primi.
+
+@item "@@val_str_desc"
+Ordinare come fa @code{"@@val_str_asc"}, ma i valori degli
+elementi, trattati come stringhe, sono ordinati dal pi@`u alto al pi@`u basso.
+I sottovettori, se presenti, vengono per primi.
+
+@item "@@val_num_desc"
+Ordinare come fa @code{"@@val_num_asc"}, ma i valori degli
+elementi, trattati come numeri, sono ordinati dal pi@`u alto al pi@`u basso.
+I sottovettori, se presenti, vengono per primi.
+@end table
+
+L'ordine in cui il vettore @`e visitato viene determinato prima di iniziare
+l'esecuzione del ciclo @code{for}. Cambiare @code{PROCINFO["sorted_in"]}
+all'interno del corpo del ciclo non influisce sul ciclo stesso.
+Per esempio:
+
+@example
+$ @kbd{gawk '}
+> @kbd{BEGIN @{}
+> @kbd{ a[4] = 4}
+> @kbd{ a[3] = 3}
+> @kbd{ for (i in a)}
+> @kbd{ print i, a[i]}
+> @kbd{@}'}
+@print{} 4 4
+@print{} 3 3
+$ @kbd{gawk '}
+> @kbd{BEGIN @{}
+> @kbd{ PROCINFO["sorted_in"] = "@@ind_str_asc"}
+> @kbd{ a[4] = 4}
+> @kbd{ a[3] = 3}
+> @kbd{ for (i in a)}
+> @kbd{ print i, a[i]}
+> @kbd{@}'}
+@print{} 3 3
+@print{} 4 4
+@end example
+
+Quando si ordina un vettore in base al valore dei suoi elementi, se viene
+trovato un valore che @`e un sottovettore, questo @`e considerato pi@`u grande di
+qualsiasi stringa o valore numerico, indipendentemente da quel che contiene
+lo stesso sottovettore, e tutti i sottovettori sono trattati come se fossero
+l'uno uguale all'altro. Il loro ordine reciproco @`e determinato dai loro
+indici, visti come stringhe.
+
+Di seguito sono elencati alcuni punti da tener presenti sulla visita
+ordinata dei vettori:
+
+@itemize @value{BULLET}
+@item
+Il valore di @code{PROCINFO["sorted_in"]} @`e globale. Cio@`e, ha effetto su tutti
+i cicli @code{for} relativi a qualsiasi vettore. Se si deve cambiarlo
+all'interno del proprio codice, si dovrebbe vedere se era gi@`a stato
+definito in precedenza, e salvare il valore relativo, per ripristinarlo
+successivamente:
+
+@example
+@dots{}
+if ("sorted_in" in PROCINFO) @{
+ ordine_salvato = PROCINFO["sorted_in"]
+ PROCINFO["sorted_in"] = "@@val_str_desc" # o qualcos'altro
+@}
+@dots{}
+if (ordine_salvato)
+ PROCINFO["sorted_in"] = ordine_salvato
+@end example
+
+@item
+Come gi@`a accennato, l'ordine di visita di default del vettore
+@`e rappresentato da @code{"@@unsorted"}. Si pu@`o ottenere il comportamento di
+default anche assegnando la stringa nulla a @code{PROCINFO["sorted_in"]} o
+semplicemente eliminando l'elemento @code{"sorted_in"} dal vettore
+@code{PROCINFO} con l'istruzione @code{delete}.
+(L'istruzione @code{delete} non @`e stata ancora descritta; @pxref{Cancellazione}.)
+@end itemize
+
+Inoltre, @command{gawk} fornisce funzioni predefinite per l'ordinamento
+dei vettori; si veda @ref{Funzioni di ordinamento di vettori}.
+
+@node Indici numerici di vettore
+@section Usare numeri per indicizzare i vettori
+
+@cindex numeri, come indici di vettore
+@cindex vettori, indici numerici di
+@cindex indici di vettori, numeri come
+@cindex @code{CONVFMT}, variabile, e indici di vettore
+Un aspetto importante da ricordare riguardo ai vettori @`e che
+@emph{gli indici dei vettori sono sempre stringhe}.
+Quando un valore numerico @`e usato come indice,
+viene convertito in un valore di tipo stringa prima di essere usato per
+l'indicizzazione (@pxref{Conversione}).
+Ci@`o vuol dire che il valore della variabile predefinita @code{CONVFMT} pu@`o
+influire su come un programma ha accesso agli elementi di un vettore.
+Per esempio:
+
+@example
+xyz = 12.153
+dati[xyz] = 1
+CONVFMT = "%2.2f"
+if (xyz in dati)
+ printf "%s @`e in dati\n", xyz
+else
+ printf "%s non @`e in dati\n", xyz
+@end example
+
+@noindent
+Il risultato @`e @samp{12.15 non @`e in dati}. La prima istruzione d@`a a
+@code{xyz} un valore numerico. L'assegnamento a @code{dati[xyz]}
+indicizza @code{dati} col valore di tipo stringa @code{"12.153"}
+(usando il valore di conversione di default @code{CONVFMT}, @code{"%.6g"}).
+Quindi, all'elemento del vettore @code{dati["12.153"]} @`e assegnato il valore
+uno. Il programma cambia poi
+il valore di @code{CONVFMT}. La verifica @samp{(xyz in dati)} genera un nuovo
+valore di stringa da @code{xyz}---questa volta @code{"12.15"}---perch@'e il
+valore di @code{CONVFMT} consente solo due cifre decimali. Questa
+verifica d@`a esito negativo, perch@'e @code{"12.15"} @`e diverso da @code{"12.153"}.
+
+@cindex convertire numeri interi che sono indici di vettore
+@cindex numeri interi, indici di vettore
+Secondo le regole di conversione
+(@pxref{Conversione}), i valori numerici interi
+vengono convertiti in stringhe sempre come interi, indipendentemente dal
+valore che potrebbe avere @code{CONVFMT}. E infatti il caso
+seguente produce il risultato atteso:
+
+@example
+for (i = 1; i <= maxsub; i++)
+ @ii{fa qualcosa con} vettore[i]
+@end example
+
+La regola ``i valori numerici interi si convertono sempre in stringhe intere''
+ha un'altra conseguenza per l'indicizzazione dei vettori.
+Le costanti ottali ed esadecimali
+@ifnotdocbook
+(@pxref{Numeri non-decimali})
+@end ifnotdocbook
+@ifdocbook
+(trattate in @ref{Numeri non-decimali})
+@end ifdocbook
+vengono convertite internamente in numeri, e la loro forma originale
+non viene pi@`u ricordata. Ci@`o significa, per esempio, che
+@code{vettore[17]},
+@code{vettore[021]} e
+@code{vettore[0x11]} fanno riferimento tutti allo stesso
+elemento!
+
+Come molte cose in @command{awk}, molto spesso le cose
+funzionano come ci si aspetta. @`E utile comunque avere una
+conoscenza precisa delle regole applicate, poich@'e a volte possono avere
+effetti difficili da individuare sui programmi.
+
+@node Indici non inizializzati
+@section Usare variabili non inizializzate come indici
+
+@cindex variabili non inizializzate, come indici di vettore
+@cindex non inizializzate, variabili, come indici di vettore
+@cindex indici di vettore, variabili non inizializzate come
+@cindex vettori, indici, variabili non inizializzate come
+Supponiamo che sia necessario scrivere un programma
+per stampare i dati di input in ordine inverso.
+Un tentativo ragionevole per far ci@`o (con qualche dato di
+prova) potrebbe essere qualcosa di questo tipo:
+
+@example
+$ @kbd{echo 'riga 1}
+> @kbd{riga 2}
+> @kbd{riga 3' | awk '@{ l[righe] = $0; ++righe @}}
+> @kbd{END @{}
+> @kbd{for (i = righe - 1; i >= 0; i--)}
+> @kbd{print l[i]}
+> @kbd{@}'}
+@print{} riga 3
+@print{} riga 2
+@end example
+
+Sfortunatamente, la prima riga di dati in input non appare
+nell'output!
+
+A prima vista, verrebbe da dire che questo programma avrebbe dovuto
+funzionare. La variabile @code{righe}
+non @`e inizializzata, e le variabili non inizializzate hanno il valore numerico
+zero. Cos@`{@dotless{i}}, @command{awk} dovrebbe aver stampato il valore @code{l[0]}.
+
+Qui il problema @`e che gli indici per i vettori di @command{awk} sono
+@emph{sempre} stringhe. Le variabili non inizializzate, quando sono usate come
+stringhe, hanno il valore @code{""}, e non zero. Quindi, @samp{riga 1}
+finisce per essere memorizzata in @code{l[""]}.
+La seguente variante del programma funziona correttamente:
+
+@example
+@{ l[righe++] = $0 @}
+END @{
+ for (i = righe - 1; i >= 0; i--)
+ print l[i]
+@}
+@end example
+
+Qui, @samp{++} forza @code{righe} a essere di tipo numerico, rendendo
+quindi il ``vecchio valore'' uno zero numerico. Questo viene poi convertito
+in @code{"0"} come l'indice del vettore.
+
+@cindex nulle, stringhe, come indici di vettore
+@cindex stringhe nulle, come indici di vettore
+@cindex angolo buio, indici di vettori
+@cindex @dfn{lint}, controlli, indici di vettori
+@cindex controlli @dfn{lint}, indici di vettori
+Anche se la cosa pu@`o sembrare strana, la stringa nulla
+(@code{""}) @`e un indice di vettore valido.
+@value{DARKCORNER}
+Se viene fornita l'opzione @option{--lint} sulla riga di comando
+@pxref{Opzioni}), @command{gawk} avvisa quando la stringa nulla viene usata
+come indice.
+
+@node Cancellazione
+@section L'istruzione @code{delete}
+@cindex @code{delete}, istruzione
+@cindex istruzione @code{delete}
+@cindex eliminare elementi di vettori
+@cindex vettori, elementi, eliminazione di
+@cindex elementi di vettori, eliminazione di
+
+Per rimuovere un singolo elemento da un vettore si usa l'istruzione
+@code{delete}:
+
+@example
+delete @var{vettore}[@var{espressione-indice}]
+@end example
+
+Una volta che un elemento di un vettore @`e stato eliminato, il valore che aveva
+quell'elemento non @`e pi@`u disponibile. @`E come se quell'elemento non sia
+mai stato referenziato oppure come se non gli sia mai stato assegnato un
+valore. Il seguente @`e un esempio di eliminazione di elementi da un vettore:
+
+@example
+for (i in frequenze)
+ delete frequenze[i]
+@end example
+
+@noindent
+Quest'esempio rimuove tutti gli elementi dal vettore @code{frequenze}. Una
+volta che un elemento @`e stato eliminato, una successiva istruzione @code{for}
+che visiti il vettore non trover@`a quell'elemento, e l'uso dell'operatore
+@code{in} per controllare la presenza di quell'elemento restituisce zero (cio@`e
+falso):
+
+@example
+delete pippo[4]
+if (4 in pippo)
+ print "Questo non verr@`a mai stampato"
+@end example
+
+@cindex nulle, stringhe, ed eliminazione di elementi di un vettore
+@cindex stringhe nulle, ed eliminazione di elementi di un vettore
+@`E importante notare che eliminare un elemento @emph{non} @`e la stessa cosa
+che assegnargli un valore nullo (la stringa vuota, @code{""}).
+Per esempio:
+
+@example
+pippo[4] = ""
+if (4 in pippo)
+ print "Questo viene stampato, anche se pippo[4] @`e vuoto"
+@end example
+
+@cindex @dfn{lint}, controlli, elementi di vettori
+@cindex controlli @dfn{lint}, elementi di vettori
+@cindex elementi di vettori, controlli @dfn{lint} per
+Non @`e un errore eliminare un elemento che non esiste.
+Tuttavia, se viene data l'opzione @option{--lint} sulla riga di comando
+(@pxref{Opzioni}),
+@command{gawk} emette un messaggio di avvertimento quando viene eliminato un
+elemento che non @`e presente in un vettore.
+
+@cindex comuni, estensioni, @code{delete} per eliminare interi vettori
+@cindex estensioni comuni@comma{} @code{delete} per eliminare interi vettori
+@cindex vettori, eliminare l'intero contenuto
+@cindex eliminare interi vettori
+@cindex @code{delete}, @var{vettore}
+@cindex differenze tra @command{awk} e @command{gawk}, elementi dei vettori, eliminazione
+Tutti gli elementi di un vettore possono essere eliminati con una singola
+istruzione omettendo l'indice nell'istruzione @code{delete},
+in questo modo:
+
+
+@example
+delete @var{vettore}
+@end example
+
+L'uso di questa versione dell'istruzione @code{delete} @`e circa tre volte pi@`u
+efficiente dell'equivalente ciclo che elimina gli elementi uno
+alla volta.
+
+Questa forma dell'istruzione @code{delete} @`e ammessa anche
+da BWK @command{awk} e da @command{mawk}, e anche da
+diverse altre implementazioni.
+
+@cindex Brian Kernighan, @command{awk} di
+@quotation NOTA
+Per molti anni, l'uso di @code{delete} senza un indice era un'estensione
+comune. A settembre 2012 si @`e deciso di includerla nello
+standard POSIX. Si veda @uref{http://austingroupbugs.net/view.php?id=544,
+il sito dell'Austin Group}.
+@end quotation
+
+@cindex portabilit@`a, eliminazione di elementi di un vettore
+@cindex Brennan, Michael
+La seguente istruzione fornisce un modo portabile, anche se non evidente,
+per svuotare un vettore:@footnote{Un ringraziamento a Michael
+Brennan per la segnalazione.}
+
+@example
+split("", vettore)
+@end example
+
+@cindex @code{split()}, funzione, eliminazione di elementi di vettori
+@cindex funzione @code{split()}, eliminazione di elementi di vettori
+La funzione @code{split()}
+(@pxref{Funzioni per stringhe})
+dapprima svuota il vettore indicato. La chiamata chiede di dividere
+la stringa nulla. Poich@'e non c'@`e nulla da dividere, la
+funzione si limita a svuotare il vettore e poi termina.
+
+@quotation ATTENZIONE
+L'eliminazione di tutti gli elementi di un vettore non cambia il suo tipo; non
+si pu@`o svuotare un vettore e poi usare il nome del vettore come scalare
+(cio@`e, come una variabile semplice). Per esempio, questo non @`e consentito:
+
+@example
+a[1] = 3
+delete a
+a = 3
+@end example
+@end quotation
+
+@node Vettori multidimensionali
+@section Vettori multidimensionali
+
+@menu
+* Visitare vettori multidimensionali:: Visitare vettori multidimensionali.
+@end menu
+
+@cindex indici di vettori multidimensionali
+@cindex vettori multidimensionali
+@cindex multidimensionali, vettori
+Un @dfn{vettore multidimensionale} @`e un vettore in cui un elemento @`e
+identificato da un insieme di indici invece che da un indice singolo. Per
+esempio, un vettore bidimenisonale richiede due indici. Il modo consueto (in
+molti linguaggi, compreso @command{awk}) per far riferimento a un elemento di
+un vettore multidimensionale chiamato @code{griglia} @`e con
+@code{griglia[@var{x},@var{y}]}.
+
+@cindex @code{SUBSEP}, variabile, e vettori multidimensionali
+@cindex variabile @code{SUBSEP}, e vettori multidimensionali
+I vettori multidimensionali sono resi disponibili in @command{awk} attraverso
+la concatenazione di pi@`u indici in una stringa;
+@command{awk} converte gli indici in stringhe
+(@pxref{Conversione}) e
+le concatena assieme, inserendo un separatore tra ognuna di loro. Ne
+risulta una sola stringa che include i valori di ogni indice. La
+stringa cos@`{@dotless{i}} composta viene usata come un singolo indice in un vettore
+ordinario monodimensionale. Il separatore usato @`e il valore della variabile
+predefinita @code{SUBSEP}.
+
+Per esempio, supponiamo di valutare l'espressione @samp{pippo[5,12] = "valore"}
+quando il valore di @code{SUBSEP} @`e @code{"@@"}. I numeri 5 e 12 vengono
+convertiti in stringhe che sono poi
+concatenate con un @samp{@@} tra di essi, dando @code{"5@@12"}; di conseguenza,
+l'elemento del vettore @code{pippo["5@@12"]} @`e impostato a @code{"valore"}.
+
+Una volta che il valore dell'elemento @`e memorizzato, @command{awk}
+ignora se sia stato memorizzato con un solo indice o con una
+serie di indici. Le due espressioni @samp{pippo[5,12]} e
+@w{@samp{pippo[5 SUBSEP 12]}} sono sempre equivalenti.
+
+Il valore di default di @code{SUBSEP} @`e la stringa @code{"\034"},
+che contiene un carattere non stampabile che difficilmente appare in
+un programma di @command{awk} e nella maggior parte dei dati di input.
+Il vantaggio di scegliere un carattere improbabile discende dal fatto che i
+valori degli indici che contengono una stringa corrispondente a @code{SUBSEP}
+possono portare a stringhe risultanti ambigue. Supponendo che
+@code{SUBSEP} valga @code{"@@"}, @w{@samp{pippo["a@@b", "c"]}} e
+@w{@samp{pippo["a", "b@@c"]}} risultano indistinguibili perch@'e entrambi
+sarebbero in realt@`a memorizzati come @samp{pippo["a@@b@@c"]}.
+
+@cindex @code{in}, operatore, verificare se un elemento esiste in un vettore multidimensionale
+Per verificare se una determinata sequenza di indici esiste in un vettore
+multidimensionale, si usa lo stesso operatore (@code{in}) che viene usato
+per i vettori monodimensionali. Si scrive l'intera sequenza di indici tra
+parentesi, separati da virgole, come operando di sinistra:
+
+@example
+if ((@var{indice1}, @var{indice2}, @dots{}) in @var{vettore})
+ @dots{}
+@end example
+
+Qui vediamo un esempio, avendo in input un vettore bidimensionale
+di campi, ruota questo vettore di 90 gradi in senso orario e stampa il
+risultato. Si suppone che tutte le righe in input contengano lo stesso
+numero di elementi:
+
+@example
+@{
+ if (max_nf < NF)
+ max_nf = NF
+ max_nr = NR
+ for (x = 1; x <= NF; x++)
+ vettore[x, NR] = $x
+@}
+
+END @{
+ for (x = 1; x <= max_nf; x++) @{
+ for (y = max_nr; y >= 1; --y)
+ printf("%s ", vettore[x, y])
+ printf("\n")
+ @}
+@}
+@end example
+
+@noindent
+Dato l'input:
+
+@example
+1 2 3 4 5 6
+2 3 4 5 6 1
+3 4 5 6 1 2
+4 5 6 1 2 3
+@end example
+
+@noindent
+il programma produce il seguente output:
+
+@example
+4 3 2 1
+5 4 3 2
+6 5 4 3
+1 6 5 4
+2 1 6 5
+3 2 1 6
+@end example
+
+@node Visitare vettori multidimensionali
+@subsection Visitare vettori multidimensionali
+
+Non c'@`e un'istruzione @code{for} particolare per visitare un
+vettore ``multidimensionale''. Non ce ne pu@`o essere una, perch@'e
+@command{awk} in realt@`a non ha
+vettori o elementi multidimensionali: c'@`e solo una modalit@`a
+multidimensionale per @emph{accedere} a un vettore.
+
+@cindex indici di vettori multidimensionali, visitare gli
+@cindex vettori, multidimensionali, visitare
+@cindex visitare vettori multidimensionali
+Comunque, se un programma ha un vettore al quale si accede sempre in
+modalit@`a multidimensionale, si pu@`o ottenere il risultato di visitarlo
+combinando l'istruzione di visita @code{for}
+(@pxref{Visitare un intero vettore}) con la funzione
+interna @code{split()}
+(@pxref{Funzioni per stringhe}).
+Si procede nel seguente modo:
+
+@example
+for (indice_combinato in vettore) @{
+ split(indice_combinato, indici_separati, SUBSEP)
+ @dots{}
+@}
+@end example
+
+@noindent
+Questo imposta la variabile @code{indice_combinato} a ogni
+concatenazione di indici contenuta nel vettore, e la suddivide
+nei singoli indici separandoli
+in corrispondenza del valore di
+@code{SUBSEP}. I singoli indici diventano poi gli elementi
+del vettore @code{indici_separati}.
+
+Perci@`o, se un valore @`e stato precedentemente memorizzato in
+@code{vettore[1, "pippo"]}, esiste in @code{vettore} un elemento con indice
+@code{"1\034pippo"} (ricordare che il valore di default di @code{SUBSEP}
+@`e il carattere con codice ottale 034).
+Prima o poi, l'istruzione @code{for} trova quell'indice e fa un'iterazione
+con la variabile @code{indice_combinato} impostata a @code{"1\034pippo"}.
+Poi viene chiamata la funzione @code{split()} in questo modo:
+
+@example
+split("1\034pippo", indici_separati, "\034")
+@end example
+
+@noindent
+Il risultato @`e quello di impostare @code{indici_separati[1]} a @code{"1"} e
+@code{indici_separati[2]} a @code{"pippo"}. Ecco fatto!
+La sequenza originale degli indici separati @`e ripristinata.
+
+
+@node Vettori di vettori
+@section Vettori di vettori
+@cindex vettori di vettori
+
+@command{gawk} migliora l'accesso ai vettori multidimensionali di
+@command{awk} standard e mette a disposizione dei veri vettori di vettori.
+Agli elementi di un sottovettore si fa riferimento tramite il loro indice
+racchiuso tra parentesi quadre, proprio come gli elementi del vettore
+principale. Per esempio, quel che segue crea un sottovettore con due elementi
+all'indice @code{1} del vettore principale @code{a}:
+
+@example
+a[1][1] = 1
+a[1][2] = 2
+@end example
+
+Questo simula un vero vettore bidimensionale. Ogni elemento di un sottovettore
+pu@`o contenere un altro sottovettore come valore, che a sua volta pu@`o
+contenere anche ulteriori vettori. In questo modo, si possono creare vettori
+di tre o pi@`u dimensioni.
+Gli indici possono essere costituiti da qualunque espressione di
+@command{awk}, compresi dei
+valori scalari separati da virgole (cio@`e, un indice multidimensionale simulato
+di @command{awk}). Quindi, la seguente espressione @`e valida in
+@command{gawk}:
+
+@example
+a[1][3][1, "nome"] = "barney"
+@end example
+
+Ogni sottovettore e il vettore principale possono essere di diversa lunghezza.
+Di fatto, gli elementi di un vettore o un suo sottovettore non devono essere
+necessariamente tutti dello stesso tipo. Ci@`o significa che il vettore
+principale come anche uno qualsiasi dei suoi sottovettori pu@`o essere
+non rettangolare,
+o avere una struttura frastagliata. Si pu@`o assegnare un valore scalare
+all'indice @code{4} del vettore principale @code{a}, anche se @code{a[1]}
+@`e esso stesso un vettore e non uno scalare:
+
+@example
+a[4] = "Un elemento in un vettore frastagliato"
+@end example
+
+I termini @dfn{dimensione}, @dfn{riga} e @dfn{colonna} sono privi di
+significato quando sono applicati
+a questo tipo di vettore, ma d'ora in poi useremo ``dimensione'' per indicare
+il numero massimo di indici necessario per far riferimento a un elemento
+esistente. Il tipo di ogni elemento che @`e gi@`a stato assegnato non pu@`o essere
+cambiato assegnando un valore di tipo diverso. Prima si deve eliminare
+l'elemento corrente, per togliere completamente dalla memoria di
+@command{gawk} ogni riferimento a quell'indice:
+
+@example
+delete a[4]
+a[4][5][6][7] = "Un elemento in un vettore quadridimensionale"
+@end example
+
+@noindent
+Le due istruzioni rimuovono il valore scalare dall'indice @code{4} e
+inseriscono poi un
+sottovettore interno a tre indici contenente uno scalare. Si pu@`o anche
+eliminare un intero sottovettore o un sottovettore di sottovettori:
+
+@example
+delete a[4][5]
+a[4][5] = "Un elemento nel sottovettore a[4]"
+@end example
+
+Si deve per@`o ricordare che non @`e consentito eliminare il vettore principale
+@code{a} e poi usarlo come scalare.
+
+Le funzioni predefinite che accettano come argomenti dei vettori possono
+essere usate
+anche con i sottovettori. Per esempio, il seguente frammento di codice usa
+@code{length()} (@pxref{Funzioni per stringhe})
+per determinare il numero di elementi nel vettore principale @code{a}
+e nei suoi sottovettori:
+
+@example
+print length(a), length(a[1]), length(a[1][3])
+@end example
+
+@noindent
+Il risultato per il nostro vettore principale @code{a} @`e il seguente:
+
+@example
+2, 3, 1
+@end example
+
+@noindent
+L'espressione @samp{@var{indice} in @var{vettore}}
+(@pxref{Visitare elementi}) funziona allo stesso modo sia per
+i vettori regolari in stile @command{awk}
+che per i vettori di vettori. Per esempio, le espressioni @samp{1 in a},
+@samp{3 in a[1]} e @samp{(1, "nome") in a[1][3]} risultano tutte di valore
+uno (vero) per il nostro vettore @code{a}.
+
+L'istruzione @samp{for (elemento in vettore)} (@pxref{Visitare un intero vettore})
+pu@`o essere nidificata per visitare tutti gli
+elementi di un vettore di vettori che abbia una struttura rettangolare. Per
+stampare il contenuto (valori scalari) di un vettore di vettori bidimensionale
+(cio@`e nel quale ogni elemento di primo livello @`e esso stesso un
+vettore, non necessariamente di lunghezza uguale agli altri)
+si pu@`o usare il seguente codice:
+
+@example
+for (i in vettore)
+ for (j in vettore[i])
+ print vettore[i][j]
+@end example
+
+La funzione @code{isarray()} (@pxref{Funzioni per i tipi})
+permette di verificare se un elemento di un vettore @`e esso stesso un vettore:
+
+@example
+for (i in vettore) @{
+ if (isarray(vettore[i]) @{
+ for (j in vettore[i]) @{
+ print vettore[i][j]
+ @}
+ @}
+ else
+ print vettore[i]
+@}
+@end example
+
+Se la struttura di un vettore di vettori frastagliato @`e nota in anticipo,
+si pu@`o spesso trovare il modo per visitarlo usando istruzioni di controllo.
+Per esempio,
+il seguente codice stampa gli elementi del nostro vettore principale @code{a}:
+
+@example
+for (i in a) @{
+ for (j in a[i]) @{
+ if (j == 3) @{
+ for (k in a[i][j])
+ print a[i][j][k]
+ @} else
+ print a[i][j]
+ @}
+@}
+@end example
+
+@noindent
+@xref{Visitare vettori} per una funzione definita dall'utente che
+``visita'' un vettore di vettori di dimensioni arbitrarie.
+
+Si ricordi che un riferimento a un elemento di un vettore non
+inizializzato genera un elemento con valore uguale a @code{""}, la stringa
+nulla. Questo ha
+un'importante implicazione quando s'intende usare un sottovettore come
+argomento di una funzione, come illustrato nel seguente esempio:
+
+@example
+$ @kbd{gawk 'BEGIN @{ split("a b c d", b[1]); print b[1][1] @}'}
+@error{} gawk: riga com.:1: fatale: split: secondo argomento
+@error{} non-vettoriale
+@end example
+
+Il modo per aggirare quest'ostacolo @`e quello di definire prima @code{b[1]}
+come vettore creando un indice arbitrario:
+
+@example
+$ @kbd{gawk 'BEGIN @{ b[1][1] = ""; split("a b c d", b[1]); print b[1][1] @}'}
+@print{} a
+@end example
+
+@node Sommario dei vettori
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+@command{awk} standard dispone di vettori associativi monodimensionali
+(vettori indicizzati da valori di tipo stringa). Tutti i vettori sono
+associativi; gli indici numerici vengono convertiti automaticamente in
+stringhe.
+
+@item
+Agli elementi dei vettori si fa riferimento come
+@code{@var{vettore}[@var{indice}]}. Fare riferimento a un elemento lo
+crea se questo non esiste ancora.
+
+@item
+Il modo corretto per vedere se un vettore ha un elemento con un dato indice
+@`e quello di usare l'operatore @code{in}: @samp{@var{indice} in @var{vettore}}.
+
+@item
+Si usa @samp{for (@var{indice} in @var{vettore}) @dots{}} per visitare
+ogni singolo elemento di un vettore. Nel corpo del ciclo,
+@var{indice} assume via via il valore dell'indice di ogni elemento del vettore.
+
+@item
+L'ordine in cui il ciclo @samp{for (@var{indice} in @var{vettore})}
+attraversa un vettore non @`e definito in POSIX @command{awk} e varia a seconda
+dell'implementazione. @command{gawk} consente di controllare l'ordinamento
+di visita
+assegnando speciali valori predefiniti a @code{PROCINFO["sorted_in"]}.
+
+@item
+Si usa @samp{delete @var{vettore}[@var{indice}]} per eliminare un singolo
+elemento di un vettore.
+Per eliminare tutti gli elementi di un vettore,
+si usa @samp{delete @var{vettore}}.
+Quest'ultima funzionalit@`a @`e stata per molti anni un'estensione comune
+e ora @`e standard, ma potrebbe non essere disponibile in tutte le
+versioni commerciali di @command{awk}.
+
+@item
+@command{awk} standard simula vettori multidimensionali ammettendo pi@`u indici
+separati da virgole. I loro valori sono concatenati in un'unica
+stringa, separati dal valore di @code{SUBSEP}. Il modo di creazione
+dell'indice non viene immagazzinato; cos@`{@dotless{i}},
+cambiare @code{SUBSEP} potrebbe avere conseguenze inaspettate. Si pu@`o usare
+@samp{(@var{sub1}, @var{sub2}, @dots{}) in @var{vettore}} per vedere se
+un certo indice multidimensionale esiste in @var{vettore}.
+
+@item
+@command{gawk} consente di avere a disposizione veri vettori di vettori.
+Si usa una coppia
+di parentesi quadre per ogni dimensione in tali vettori:
+@code{dati[riga][colonna]}, per esempio. Gli elementi del vettore possono
+poi essere valori scalari (numeri o stringhe) o altri vettori.
+
+@item
+Si usa la funzione predefinita @code{isarray()} per determinare se un elemento
+di un vettore @`e esso stesso un sottovettore.
+
+@end itemize
+
+@node Funzioni
+@chapter Funzioni
+
+@cindex funzioni predefinite
+@cindex predefinite, funzioni
+Questo @value{CHAPTER} descrive le funzioni predefinite di @command{awk},
+che sono di tre tipi: numeriche, di stringa, e di I/O.
+@command{gawk} mette a disposizione ulteriori tipi di funzioni
+per gestire valori che rappresentano marcature temporali, per manipolare bit, per
+ordinare vettori, per fornire informazioni sui tipi di variabile,
+per internazionalizzare e localizzare i programmi.@footnote{Per
+un'introduzione alle tematiche suddette, si pu@`o consultare l'articolo
+"Localizzazione dei programmi" nel
+@uref{http://www.pluto.it/files/journal/pj0404/l10n.html, sito pluto.it.}}
+
+Oltre alle funzioni predefinite, @command{awk} consente di
+scrivere nuove funzioni utilizzabili all'interno di un programma.
+La seconda met@`a di questo @value{CHAPTER} descrive le funzioni
+@dfn{definite dall'utente}.
+Vengono infine descritte le chiamate indirette a una funzione, un'estensione
+specifica di @command{gawk} che consente di stabilire durante l'esecuzione del
+programma quale funzione chiamare.
+
+@menu
+* Funzioni predefinite:: Riepilogo delle funzioni predefinite.
+* Funzioni definite dall'utente:: Descrizione dettagliata delle funzioni
+ definite dall'utente.
+* Chiamate indirette:: Scegliere la funzione da chiamare in
+ fase di esecuzione del programma.
+* Sommario delle funzioni:: Sommario delle funzioni.
+@end menu
+
+@node Funzioni predefinite
+@section Funzioni predefinite
+
+Le funzioni @dfn{predefinite} sono sempre disponibili per essere chiamate
+da un programma @command{awk}. Questa @value{SECTION} definisce tutte le
+funzioni predefinite di @command{awk}; di alcune di queste si fa menzione
+in altre @value{SECTIONS},
+ma sono comunque riassunte anche qui per comodit@`a.
+
+@menu
+* Chiamare funzioni predefinite:: Come chiamare funzioni predefinite.
+* Funzioni numeriche:: Funzioni che trattano numeri, comprese
+ @code{int()}, @code{sin()} e @code{rand()}.
+* Funzioni per stringhe:: Funzioni di manipolazione di stringhe,
+ come @code{split()}, @code{match()}
+ e @code{sprintf()}.
+* Funzioni di I/O:: Funzioni per i file e per i comandi
+ della shell.
+* Funzioni di tempo:: Funzione per gestire marcature temporali.
+* Funzioni a livello di bit:: Funzioni per operazioni di
+ manipolazione bit.
+* Funzioni per i tipi:: Funzioni per informazioni sul tipo
+ di una variabile.
+* Funzioni di internazionalizzazione:: Funzioni per tradurre stringhe.
+@end menu
+
+@node Chiamare funzioni predefinite
+@subsection Chiamare funzioni predefinite
+
+Per chiamare una delle funzioni predefinite di @command{awk},
+si scrive il nome della funzione seguito dai suoi argomenti racchiusi
+tra parentesi. Per esempio, @samp{atan2(y + z, 1)}
+@`e una chiamata alla funzione @code{atan2()} e ha due argomenti.
+
+@cindex convenzioni di programmazione, nelle chiamate di funzione
+@cindex spazio bianco, nelle chiamate di funzione
+La presenza di spazi bianchi tra il nome della funzione predefinita
+e la parentesi aperta @`e consentita, ma @`e buona norma quella di evitare
+di inserire spazi bianchi in quella posizione.
+Le funzioni definite dall'utente non consentono che vi siano spazi bianchi
+fra nome funzione e aperta parentesi,
+ed @`e pi@`u semplice evitare errori seguendo una semplice convenzione che
+resta sempre valida: non inserire spazi dopo il nome di una funzione.
+
+@cindex risoluzione di problemi, @command{gawk}, errori fatali@comma{} argomenti di funzione e
+@cindex problemi, risoluzione di, @command{gawk}, errori fatali@comma{} argomenti di funzione e
+@cindex @command{gawk}, argomenti di funzione e
+@cindex differenze tra @command{awk} e @command{gawk}, argomenti di funzione (@command{gawk})
+Ogni funzione predefinita accetta un certo numero di argomenti.
+In alcuni casi, gli argomenti possono essere omessi. I valori di default per
+gli argomenti omessi variano
+da funzione a funzione e sono descritti insieme a
+ciascuna funzione. In alcune implementazioni di @command{awk}, gli
+eventuali argomenti in pi@`u specificati per le funzioni predefinite sono
+ignorati. Tuttavia, in @command{gawk},
+@`e un errore fatale fornire argomenti in pi@`u a una funzione predefinita.
+
+Quando si richiama una funzione viene calcolato, prima di effettuare la
+chiamata, il valore assunto dalle espressioni che descrivono i parametri
+da passare alla funzione.
+Per esempio, nel seguente frammento di codice:
+
+@example
+i = 4
+j = sqrt(i++)
+@end example
+
+@cindex ordine di valutazione, funzioni
+@cindex funzioni predefinite, ordine di valutazione
+@cindex predefinite, funzioni, ordine di valutazione
+@noindent
+la variabile @code{i} @`e incrementata al valore cinque prima di chiamare
+la funzione @code{sqrt()} alla quale viene fornito come parametro il valore
+quattro.
+L'ordine di valutazione delle espressioni usate come parametri per la
+funzione @`e indefinito. Per questo motivo, si deve evitare di scrivere
+programmi che presuppongono che i parametri siano valutati da sinistra a
+destra o da destra a sinistra. Per esempio:
+
+@example
+i = 5
+j = atan2(++i, i *= 2)
+@end example
+
+Se l'ordine di valutazione @`e da sinistra a destra, @code{i} assume dapprima
+il valore 6, e quindi il valore 12, e la funzione @code{atan2()} @`e chiamata
+con i due argomenti 6 e 12. Ma se l'ordine di valutazione @`e da destra a
+sinistra, @code{i} assume dapprima il valore 10, e poi il valore 11, e la
+funzione @code{atan2()} @`e chiamata con i due argomenti 11 e 10.
+
+@node Funzioni numeriche
+@subsection Funzioni numeriche
+@cindex funzioni numeriche
+@cindex numeriche, funzioni
+
+La seguente lista descrive tutte le
+funzioni predefinite che hanno a che fare con i numeri.
+I parametri facoltativi sono racchiusi tra parentesi quadre@w{ ([ ]):}
+
+@c @asis for docbook
+@table @asis
+@item @code{atan2(@var{y}, @var{x})}
+@cindexawkfunc{atan2}
+@cindex arcotangente
+Restituisce l'arcotangente di @code{@var{y} / @var{x}} in radianti.
+Si pu@`o usare @samp{pi = atan2(0, -1)} per ottenere il valore di
+@value{PI} greco.
+
+@item @code{cos(@var{x})}
+@cindexawkfunc{cos}
+@cindex coseno
+Restituisce il coseno di @var{x}, con @var{x} in radianti.
+
+@item @code{exp(@var{x})}
+@cindexawkfunc{exp}
+@cindex esponenziale
+Restituisce l'esponenziale di @var{x} (@code{e ^ @var{x}}) o un messaggio
+di errore se @var{x} @`e fuori dall'intervallo consentito.
+L'intervallo entro il quale pu@`o variare @var{x}
+dipende dalla rappresentazione dei numeri in virgola mobile nella macchina in
+uso.
+
+@item @code{int(@var{x})}
+@cindexawkfunc{int}
+@cindex arrotondamento all'intero pi@`u vicino
+Restituisce l'intero pi@`u vicino a @var{x}, situato tra @var{x} e zero,
+troncato togliendo i decimali.
+Per esempio, @code{int(3)} @`e 3, @code{int(3.9)} @`e 3, @code{int(-3.9)}
+@`e @minus{}3, e @code{int(-3)} @`e ancora @minus{}3.
+
+@item @code{intdiv(@var{numeratore}, @var{denominatore}, @var{risultato})}
+@cindexawkfunc{intdiv}
+@cindex funzione @code{intdiv}
+Esegue una divisione tra numeri interi, simile alla funzione standard C
+che ha lo stesso nome. Dapprima, il @code{numeratore} e il
+@code{denominatore} vengono troncati, eliminando la parte decimale,
+per trasformarli in numeri interi.
+Il vettore @code{risultato} viene dapprima svuotato, e poi viene impostato
+l'elemento @code{risultato["quotient"]} al risultato della divisione
+@samp{numeratore / denominatore}, troncato a numero intero
+mediante l'eliminazione dei decimali,
+e viene impostato l'elemento @code{risultato["remainder"]} al
+risultato dell'operazione @samp{numeratore % denominatore}, troncato a
+numero intero allo stesso modo del risultato. Questa funzione @`e
+rivolta principalmente a chi usa numeri interi di lunghezza arbitraria;
+consente di evitare la creazione di numeri in virgola mobile
+di precisione arbitaria usando la funzionalit@`a MPFR
+(@pxref{Interi a precisione arbitraria}).
+
+Questa funzione @`e un'estensione @code{gawk}. Non @`e disponibile in
+modalit@`a compatibile (@pxref{Opzioni}).
+
+@item @code{log(@var{x})}
+@cindexawkfunc{log}
+@cindex logaritmo
+Restituisce il logaritmo naturale di @var{x}, se @var{x} @`e positivo;
+altrimenti, restituisce @code{NaN} (``not a number'') sui sistemi che
+implementano lo standard IEEE 754.
+Inoltre, @command{gawk} stampa un messaggio di avvertimento qualora @code{x}
+sia negativo.
+
+@item @code{rand()}
+@cindexawkfunc{rand}
+@cindex numeri casuali, funzioni @code{rand()}/@code{srand()}
+Restituisce un numero casuale. I valori di @code{rand()} sono
+uniformemente distribuiti tra zero e uno.
+Il valore potrebbe essere zero ma non @`e mai uno.@footnote{La versione C di
+@code{rand()} in molti sistemi Unix
+produce notoriamente delle sequenze piuttosto mediocri di numeri casuali.
+Tuttavia, non @`e prescritto che un'implementazione di @command{awk}
+debba usare la funzione @code{rand()} del linguaggio C per implementare
+la versione @command{awk} di @code{rand()}.
+In effetti, @command{gawk} usa, per generare numeri casuali,
+la funzione @code{random()} di BSD, che @`e
+notevolmente migliore di @code{rand()}}
+
+Spesso servono dei numeri casuali interi invece che frazionari.
+La seguente funzione definita dall'utente pu@`o essere usata per ottenere
+un numero casuale non negativo inferiore a @var{n}:
+
+@example
+function randint(n)
+@{
+ return int(n * rand())
+@}
+@end example
+
+@noindent
+La moltiplicazione produce un numero casuale maggiore o uguale a zero e
+minore di @code{n}. Tramite @code{int()}, questo risultato diventa
+un intero tra zero e @code{n} @minus{} 1, estremi inclusi.
+
+Il seguente esempio usa una funzione simile per generate interi casuali
+fra uno e @var{n}. Il programma stampa un numero casuale per
+ogni record in input:
+
+@example
+# funzione per simulare un tiro di dado.
+function roll(n) @{ return 1 + int(rand() * n) @}
+
+# Tira 3 dadi a sei facce e
+# stampa il numero di punti.
+@{
+ printf("%d punteggio\n", roll(6) + roll(6) + roll(6))
+@}
+@end example
+
+@cindex inizializzazione generazione di numeri casuali
+@cindex numeri casuali, inizializzazione generazione di
+@cindex numeri casuali, seme di
+@quotation ATTENZIONE
+Nella maggior parte delle implementazioni di @command{awk}, compreso
+@command{gawk},
+@code{rand()} inizia a generare numeri casuali partendo sempre
+dallo stesso numero, o @dfn{seme}, per ogni invocazione di
+@command{awk}.@footnote{@command{mawk}
+usa un seme differente ogni volta.} @`E per questo motivo che
+un programma genera sempre gli stessi risultati ogni volta che lo si esegue.
+I numeri sono casuali all'interno di una singola esecuzione di @command{awk}
+ma "prevedibili" in ogni successiva esecuzione.
+Ci@`o torna utile in fase di test, ma se si desidera che
+un programma generi sequenze differenti di numeri casuali ogni volta
+che @`e chiamato, occorre impostare il seme a un valore che cambi
+per ogni esecuzione. Per fare questo, @`e prevista la funzione @code{srand()}.
+@end quotation
+
+@item @code{sin(@var{x})}
+@cindexawkfunc{sin}
+@cindex seno
+Restituisce il seno di @var{x}, con @var{x} espresso in radianti.
+
+@item @code{sqrt(@var{x})}
+@cindexawkfunc{sqrt}
+@cindex radice quadrata
+Restituisce la radice quadrata positiva di @var{x}.
+@command{gawk} stampa un messaggio di avvertimento
+se @var{x} @`e un numero negativo. Quindi, @code{sqrt(4)} vale 2.
+
+@item @code{srand(}[@var{x}]@code{)}
+@cindexawkfunc{srand}
+Imposta al valore @var{x} il numero di partenza, o seme,
+utilizzato per generare numeri casuali.
+
+Ogni seme genera una sequenza particolare di numeri casuali.@footnote{I
+numeri casuali generati da un computer non sono veramente casuali.
+Tecnicamente sono conosciuti come numeri @dfn{pseudo-casuali}. Ci@`o vuol dire
+che, anche se i numeri in una sequenza sembrano casuali, @`e possibile
+in realt@`a generare la stessa sequenza di numeri casuali pi@`u e pi@`u volte.}
+Quindi, impostando il seme allo stesso valore una seconda volta,
+viene prodotta ancora la stessa sequenza di numeri casuali.
+
+@quotation ATTENZIONE
+Differenti implementazioni di @command{awk} usano internamente differenti
+generatori di numeri casuali. Non si deve dare per scontato che lo stesso
+programma @command{awk}
+generi la stessa serie di numeri casuali se viene eseguito da differenti
+versioni di @command{awk}.
+@end quotation
+
+Se si omette l'argomento @var{x}, scrivendo @samp{srand()}, viene usato
+come seme la data e ora corrente. @`E questo il modo per ottenere numeri
+casuali che sono veramente imprevedibili.
+
+Il valore restituito da @code{srand()} @`e quello del seme precedente.
+Questo per facilitare il monitoraggio dei semi, nel caso occorra riprodurre
+in maniera coerente delle sequenze di numeri casuali.
+
+POSIX non specifica quale debba essere il seme iniziale, che quindi varia
+a seconda delle implementazioni @command{awk}.
+@end table
+
+@node Funzioni per stringhe
+@subsection Funzioni di manipolazione di stringhe
+@cindex funzioni di manipolazione di stringhe
+
+Le funzioni in questa @value{SECTION} leggono o modificano il testo di
+una o pi@`u stringhe.
+
+@command{gawk} implementa la localizzazione
+(@pxref{Localizzazioni}) ed effettua
+ogni manipolazione di stringhe trattando ogni singolo @emph{carattere}, non
+ogni singolo @emph{byte}.
+Questa distinzione @`e particolarmente importante da comprendere per
+quelle localizzazioni in cui un singolo carattere pu@`o essere rappresentato
+da pi@`u di un byte.
+Quindi, per esempio, la funzione @code{length()} restituisce il numero di
+caratteri in una stringa, e non il numero di byte usato per rappresentare quei
+caratteri. Allo stesso modo, @code{index()} restituisce indici di caratteri, e
+non indici di byte.
+
+@quotation ATTENZIONE
+Un certo numero di funzioni riguarda indici all'interno di stringhe. Per
+queste funzioni, il primo carattere di una stringa @`e alla posizione
+(all'indice) uno. Questo comportamento @`e differente da quello del C e dei
+linguaggi che da esso discendono, nei quali il primo carattere @`e alla posizione
+zero. @`E importante ricordarlo quando si fanno calcoli sugli indici, in
+particolare se si ha familiarit@`a con il linguaggio C.
+@end quotation
+
+Nella lista seguente, i parametri facoltativi sono racchiusi tra parentesi
+quadre@w{ ([ ]).}
+Parecchie funzioni operano sostituzioni in una stringa; la spiegazione
+completa di ci@`o @`e contenuta nella descrizione della funzione @code{sub()},
+che si trova quasi alla fine di questa lista, ordinata alfabeticamente.
+
+Le funzioni specifiche di @command{gawk} sono contrassegnate col simbolo
+del cancelletto (@samp{#}). Tali funzioni non sono disponibili in modalit@`a
+compatibile (@pxref{Opzioni}):
+
+
+@menu
+* Dettagli ostici:: Pi@`u di quel che si vorrebbe sapere su @samp{\}
+ e @samp{&} con @code{sub()}, @code{gsub()}, e
+ @code{gensub()}.
+@end menu
+
+@c @asis for docbook
+@table @asis
+@item @code{asort(}@var{sorgente} [@code{,} @var{destinazione} [@code{,} @var{come} ] ]@code{) #}
+@itemx @code{asorti(}@var{sorgente} [@code{,} @var{destinazione} [@code{,} @var{come} ] ]@code{) #}
+@cindexgawkfunc{asorti}
+@cindex vettori, ordinamento dei
+@cindex ordinamento di vettori
+@cindex vettori, determinare il numero degli elementi
+@cindexgawkfunc{asort}
+@cindex ordinamento vettori per indici
+@cindex vettori, ordinamento per indici
+@cindex indici di vettori, ordinamento per
+Queste due funzioni sono abbastanza simili, e quindi sono descritte
+insieme.
+
+@quotation NOTA
+La seguente descrizione ignora il terzo argomento, @var{come}, perch@'e
+richiede la conoscenza di funzionalit@`a di cui non si @`e ancora parlato. Per
+questo motivo la seguente trattazione @`e volutamente semplificata. (In seguito
+l'argomento verr@`a trattato in maniera pi@`u esauriente; si veda @ref{Funzioni di
+ordinamento di vettori} per la descrizione completa.)
+@end quotation
+
+Entrambe le funzioni restituiscono il numero di elementi nel vettore @var{sorgente}.
+Con @command{asort()}, @command{gawk} ordina i valori di @var{sorgente}
+e rimpiazza gli indici dei valori ordinati di @var{sorgente} con
+numeri interi sequenziali, a partire da uno. Se si specifica il vettore
+opzionale @var{destinazione},
+@var{sorgente} @`e copiato in @var{destinazione}. @var{destinazione}
+viene quindi ordinato, lasciando immodificati gli indici di @var{sorgente}.
+
+@cindex @command{gawk}, variabile @code{IGNORECASE} in
+Nel confronto tra stringhe, la variabile @code{IGNORECASE} influenza
+l'ordinamento
+(@pxref{Funzioni di ordinamento di vettori}). Se il vettore
+@var{sorgente} contiene sottovettori come valori
+(@pxref{Vettori di vettori}), questi saranno alla fine, dopo tutti i valori
+scalari.
+I sottovettori @emph{non} vengono ordinati ricorsivamente.
+
+Per esempio, se i contenuti del vettore @code{a} sono i seguenti:
+
+@example
+a["ultimo"] = "de"
+a["primo"] = "sac"
+a["mediano"] = "cul"
+@end example
+
+@noindent
+Una chiamata a @code{asort()}:
+
+@example
+asort(a)
+@end example
+
+@noindent
+genera i seguenti contenuti di @code{a}:
+
+@example
+a[1] = "cul"
+a[2] = "de"
+a[3] = "sac"
+@end example
+
+La funzione @code{asorti()} si comporta in maniera simile ad @code{asort()};
+tuttavia l'ordinamento avviene in base agli @emph{indici}, e non in base ai
+valori. Quindi, nell'esempio seguente, a partire dallo stesso insieme iniziale
+di indici e valori nel vettore @code{a}, la chiamata di @samp{asorti(a)}
+produrrebbe:
+
+@example
+a[1] = "mediano"
+a[2] = "primo"
+a[3] = "ultimo"
+@end example
+
+@item @code{gensub(@var{regexp}, @var{rimpiazzo}, @var{come}} [@code{, @var{obiettivo}}]@code{) #}
+@cindexgawkfunc{gensub}
+@cindex cercare e rimpiazzare in stringhe
+@cindex sostituzione in stringa
+Ricerca nella stringa @var{obiettivo} delle corrispondenze
+all'espressione regolare @var{regexp}.
+Se @var{come} @`e una stringa che inizia
+con @samp{g} o @samp{G} (abbreviazione di ``global''), sostituisce
+ogni occorrenza di @var{regexp} con la stringa
+@var{rimpiazzo}. Altrimenti, @var{come} @`e visto come un numero che indica
+quale corrispondenza di @var{regexp} va rimpiazzata. Se non si specifica
+il nome dell'@var{obiettivo}, si
+opera su @code{$0}. La funzione restituisce come risultato la stringa
+modificata, e la stringa originale di partenza @emph{non} viene modificata.
+
+@code{gensub()} @`e una funzione generale di sostituzione. Mira a fornire
+pi@`u funzionalit@`a rispetto alle funzioni standard @code{sub()} e
+@code{gsub()}.
+
+@code{gensub()} prevede una funzionalit@`a ulteriore, non disponibile in
+@code{sub()} o @code{gsub()}: la possibilit@`a di specificare componenti di
+una @dfn{regexp} nel testo da sostituire. Questo @`e fatto utilizzando delle
+parentesi nella @dfn{regexp} per designare i componenti, e quindi inserendo
+@samp{\@var{N}} nel testo di rimpiazzo, dove @var{N} @`e una cifra da 1 a 9.
+Per esempio:
+
+@example
+$ @kbd{gawk '}
+> @kbd{BEGIN @{}
+> @kbd{a = "abc def"}
+> @kbd{b = gensub(/(.+) (.+)/, "\\2 \\1", "g", a)}
+> @kbd{print b}
+> @kbd{@}'}
+@print{} def abc
+@end example
+
+@noindent
+Come con @code{sub()}, occorre battere due barre inverse, per ottenerne
+una come componente della stringa.
+Nel testo di rimpiazzo, la sequenza @samp{\0} rappresenta l'intero testo
+corrispondente, e lo stesso vale per
+il carattere @samp{&}.
+
+Il seguente esempio mostra come @`e possibile usare il terzo argomento
+per controllare quale corrispondenza
+della @dfn{regexp} sia da modificare:
+
+@example
+$ @kbd{echo a b c a b c |}
+> @kbd{gawk '@{ print gensub(/a/, "AA", 2) @}'}
+@print{} a b c AA b c
+@end example
+
+In questo caso, @code{$0} @`e la stringa obiettivo di default.
+@code{gensub()} restituisce la nuova stringa come risultato, e questa
+@`e passata direttamente a @code{print} per essere stampata.
+
+@c @cindex avvertimenti automatici
+@c @cindex automatici, avvertimenti
+Se l'argomento @var{come} @`e una stringa che non inizia con @samp{g} o
+@samp{G}, o se @`e un numero minore o uguale a zero, si effettua solo una
+sostituzione. Se @var{come} @`e zero, @command{gawk} emette
+un messaggio di avvertimento.
+
+Se @var{regexp} non viene trovata in @var{obiettivo}, il valore
+restituito da @code{gensub()}
+@`e il valore originale e non modificato di @var{obiettivo}.
+
+@item @code{gsub(@var{regexp}, @var{rimpiazzo}} [@code{, @var{obiettivo}}]@code{)}
+@cindexawkfunc{gsub}
+Ricerca in @var{obiettivo}
+@emph{tutte} le sottostringhe corrispondenti al criterio di ricerca, le
+pi@`u lunghe possibili partendo da sinistra, @emph{non sovrapposte tra loro},
+e le sostituisce con @var{rimpiazzo}.
+La lettera @samp{g} in @code{gsub()} significa
+``global'', e richiede di sostituire dappertutto. Per esempio:
+
+@example
+@{ gsub(/Inghilterra/, "Regno Unito"); print @}
+@end example
+
+@noindent
+sostituisce tutte le occorrenze della stringa @samp{Inghilterra} con
+@samp{Regno Unito} in tutti i record in input.
+
+La funzione @code{gsub()} restituisce il numero di sostituzioni effettuate.
+Se la variabile da cercare e modificare (@var{obiettivo}) @`e omessa,
+viene usato l'intero record in input.
+Come in @code{sub()}, i caratteri @samp{&} e @samp{\} sono speciali,
+e il terzo argomento dev'essere modificabile.
+
+@item @code{index(@var{dove}, @var{cosa})}
+@cindexawkfunc{index}
+@cindex ricerca in stringhe
+@cindex trovare sottostringhe in una stringa
+Ricerca nella stringa @var{dove} la prima occorrenza della stringa @var{cosa},
+e restituisce la posizione in caratteri dell'inizio di quest'occorrenza nella
+stringa @var{dove}. Si consideri il seguente esempio:
+
+@example
+$ @kbd{awk 'BEGIN @{ print index("noccioline", "oli") @}'}
+@print{} 6
+@end example
+
+@noindent
+Se @var{cosa} non viene trovato, @code{index()} restituisce zero.
+
+@cindex angolo buio, @dfn{regexp} come secondo argomento di @code{index()}
+In BWK @command{awk} e @command{gawk},
+@`e un errore fatale usare una costante @dfn{regexp} per @var{cosa}.
+Altre implementazioni lo consentono, considerando semplicemente
+la costante @dfn{regexp} come un'espressione che significa
+@samp{$0 ~ /@dfn{regexp}/}. @value{DARKCORNER}
+
+@item @code{length(}[@var{stringa}]@code{)}
+@cindexawkfunc{length}
+@cindex stringa, lunghezza di una
+@cindex lunghezza di una stringa
+Restituisce il numero di caratteri in @var{stringa}. Se
+@var{stringa} @`e un numero, viene restituita la lunghezza della stringa
+di cifre che rappresenta quel numero. Per esempio, @code{length("abcde")} @`e
+cinque.
+Invece, @code{length(15 * 35)} restituisce tre. In questo esempio,
+@iftex
+@math{15 @cdot 35 = 525},
+@end iftex
+@ifnottex
+@ifnotdocbook
+15 * 35 = 525,
+@end ifnotdocbook
+@end ifnottex
+@docbook
+15 &sdot; 35 = 525,
+@end docbook
+e 525 @`e quindi convertito alla stringa @code{"525"}, che @`e composta da
+tre caratteri.
+
+@cindex lunghezza di un record in input
+@cindex record in input, lunghezza di un
+Se non si specifica alcun argomento, @code{length()} restituisce la
+lunghezza di @code{$0}.
+
+@c @cindex historical features
+@cindex portabilit@`a, funzione @code{length()}
+@cindex POSIX @command{awk}, funzione @code{length()} e
+@quotation NOTA
+In alcune delle prime versioni di @command{awk}, la funzione @code{length()}
+poteva essere richiamata senza alcuna parentesi. Farlo @`e considerata
+una cattiva abitudine, sebbene il POSIX standard 2008 lo consenta esplicitamente,
+per compatibilit@`a con la vecchia prassi. Per garantire la massima
+portabilit@`a ai programmi, @`e meglio mettere sempre le parentesi.
+@end quotation
+
+@cindex angolo buio, funzione @code{length()}
+Se @code{length()} @`e chiamata con una variabile che non @`e stata usata,
+@command{gawk} considera la variabile come uno scalare. Altre
+implementazioni di @command{awk} non assegnano nessun tipo alla variabile.
+@value{DARKCORNER}
+Si consideri:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print length(x) ; x[1] = 1 @}'}
+@print{} 0
+@error{} gawk: riga com.:1: fatale: tentativo di usare
+@error{} scalare 'x' come vettore
+
+$ @kbd{nawk 'BEGIN @{ print length(x) ; x[1] = 1 @}'}
+@print{} 0
+@end example
+
+@noindent
+Se @option{--lint} @`e
+stato specificato sulla riga di comando, @command{gawk} emette un
+avvertimento a questo riguardo.
+
+@cindex estensioni comuni, @code{length()} applicato a un vettore
+@cindex comuni, estensioni@comma{} @code{length()} applicato a un vettore
+@cindex differenze tra @command{gawk} e @command{awk}
+@cindex numero di elementi di un vettore
+@cindex vettore, determinare il numero degli elementi
+In @command{gawk} e in parecchie altre implementazioni @command{awk},
+se l'argomento @`e un vettore, la funzione @code{length()} restituisce il numero
+di elementi nel vettore. @value{COMMONEXT}
+Ci@`o @`e meno utile di quel che sembra a prima vista, in quanto
+non @`e affatto detto che il vettore abbia come indici i numeri da 1 al
+numero di elementi che contiene.
+Se @option{--lint} @`e
+stato specificato sulla riga di comando,
+(@pxref{Opzioni}),
+@command{gawk} avvisa che l'uso di un vettore come argomento non
+@`e portabile.
+Se si specifica l'opzione @option{--posix}, l'uso di un vettore come
+argomento genera un errore fatale
+@iftex
+(@pxrefil{Vettori}).
+@end iftex
+@ifnottex
+(@pxref{Vettori}).
+@end ifnottex
+
+@item @code{match(@var{stringa}, @var{regexp}} [@code{, @var{vettore}}]@code{)}
+@cindexawkfunc{match}
+@cindex stringa, ricercare espressioni regolari in una
+@cindex ricerca @dfn{regexp} in stringhe
+Ricerca in @var{stringa} la
+sottostringa pi@`u lunga, a partire da sinistra, che corrisponde
+all'espressione regolare @var{regexp} e restituisce la posizione
+del carattere (indice) con cui inizia la sottostringa (uno, se
+la corrispondenza parte dall'inizio di @var{stringa}). Se non viene
+trovata alcuna corrispondenza, restituisce zero.
+
+L'argomento @var{regexp} pu@`o essere sia una costante @dfn{regexp}
+(@code{/}@dots{}@code{/}) che una costante stringa (@code{"}@dots{}@code{"}).
+In quest'ultimo caso, la stringa @`e trattata come una @dfn{regexp}
+per la quale cercare una corrispondenza.
+@xref{Espressioni regolari calcolate} per una
+spiegazione sulla differenza tra le due forme e sulle loro
+implicazioni riguardo al modo per scrivere correttamente un programma.
+
+L'ordine dei primi due argomenti @`e l'opposto di molte altre funzioni che
+trattano stringhe e che hanno a che fare con espressioni regolari, come
+@code{sub()} e @code{gsub()}. Potrebbe essere di aiuto ricordare che
+per @code{match()}, l'ordine @`e lo stesso che per l'operatore @samp{~} :
+@samp{@var{stringa} ~ @var{regexp}}.
+
+@cindex @code{RSTART}, variabile, funzione @code{match()} e
+@cindex variabile @code{RSTART}, funzione @code{match()} e
+@cindex @code{RLENGTH}, variabile, funzione @code{match()} e
+@cindex variabile @code{RLENGTH}, funzione @code{match()} e
+@cindex funzione @code{match()}, variabili @code{RSTART}/@code{RLENGTH}
+@cindex @code{match()}, funzione, variabili @code{RSTART}/@code{RLENGTH}
+La funzione @code{match()} imposta la variabile predefinita @code{RSTART}
+all'indice.
+Imposta anche la variabile predefinita @code{RLENGTH} alla
+lunghezza in caratteri della sottostringa individuata. Se non viene
+trovata alcuna corrispondenza, @code{RSTART} @`e impostata a zero, e
+@code{RLENGTH} a @minus{}1.
+
+Per esempio:
+
+@example
+@c file eg/misc/findpat.awk
+@{
+ if ($1 == "TROVA")
+ regexp = $2
+ else @{
+ dove = match($0, regexp)
+ if (dove != 0)
+ print "Corrispondenza di", regexp, "alla posiz.", \
+ dove, "in", $0
+ @}
+@}
+@c endfile
+@end example
+
+@noindent
+Questo programma ricerca delle righe che corrispondono all'espressione
+regolare contenuta nella variabile
+@code{regexp}. Quest'espressione regolare pu@`o essere modificata. Se la
+prima parola in una riga @`e @samp{TROVA}, @code{regexp} diventa la
+seconda parola su quella riga. Quindi, dato:
+
+@example
+@c file eg/misc/findpat.data
+TROVA or+e
+Il mio programma corre
+ma non troppo velocemente
+TROVA Melvin
+JF+KM
+Questa riga appartiene a Reality Engineering Co.
+Melvin @`e passato da qui.
+@c endfile
+@end example
+
+@noindent
+@command{awk} stampa:
+
+@example
+Corrispondenza di or+e alla posiz. 19 in Il mio programma corre
+Corrispondenza di Melvin alla posiz. 1 in Melvin @`e passato da qui.
+@end example
+
+@cindex differenze tra @command{awk} e @command{gawk}, funzione @code{match()}
+Se @var{vettore} esiste gi@`a, viene cancellato, e quindi l'elemento numero
+zero di @var{vettore} @`e impostato all'intera parte di @var{stringa}
+individuata da @var{regexp}. Se @var{regexp} contiene parentesi,
+gli elementi aventi per indici numeri interi in @var{vettore} sono
+impostati per contenere ognuno la parte di @var{stringa} individuata dalla
+corrispondente sottoespressione delimitata da parentesi.
+Per esempio:
+
+@example
+$ @kbd{echo pippoooopaperpluttttttt |}
+> @kbd{gawk '@{ match($0, /(pippo+).+(plut*)/, vett)}
+> @kbd{print vett[1], vett[2] @}'}
+@print{} pippoooo pluttttttt
+@end example
+
+Inoltre,
+sono disponibili indici multidimensionali che contengono
+la posizione di partenza e la lunghezza di ogni sottoespressione
+individuata:
+
+@example
+$ @kbd{echo pippoooopaperpluttttttt |}
+> @kbd{gawk '@{ match($0, /(pippo+).+(plut*)/, vett)}
+> @kbd{print vett[1], vett[2]}
+> @kbd{print vett[1, "start"], vett[1, "length"]}
+> @kbd{print vett[2, "start"], vett[2, "length"]}
+> @kbd{@}'}
+@print{} pippoooo pluttttttt
+@print{} 1 8
+@print{} 14 10
+@end example
+
+Possono non esserci indici che individuino inizio e posizione
+per ogni sottoespressione
+fra parentesi, perch@'e non tutte potrebbero aver individuato del testo;
+quindi, andrebbero esaminati usando l'operatore @code{in}
+(@pxref{Visitare elementi}).
+
+@cindex risoluzione di problemi, funzione @code{match()}
+@cindex problemi, risoluzione di, funzione @code{match()}
+L'argomento @var{vettore} di @code{match()} @`e un'estensione
+@command{gawk}. In modalit@`a compatibile
+(@pxref{Opzioni}),
+l'impiego di un terzo argomento causa un errore fatale.
+
+@item @code{patsplit(@var{stringa}, @var{vettore}} [@code{, @var{regexpdelim}} [@code{, @var{separatori}} ] ]@code{) #}
+@cindexgawkfunc{patsplit}
+@cindex dividere in un vettore una stringa
+@cindex creare un vettore da una stringa
+Divide
+@var{stringa} in parti definite da @var{regexpdelim}
+e memorizza i pezzi in @var{vettore} e le stringhe di separazione nel
+vettore @var{separatori}. Il primo pezzo @`e memorizzato in
+@code{@var{vettore}[1]}, il secondo pezzo in @code{@var{vettore}[2]}, e
+cos@`{@dotless{i}} via. Il terzo argomento, @var{regexpdelim}, @`e
+una @dfn{regexp} che descrive i campi in @var{stringa} (allo stesso modo in
+cui @code{FPAT} @`e una @dfn{regexp} che descrive i campi nei record
+in input).
+Pu@`o essere una costante @dfn{regexp} o una stringa.
+Se @var{regexpdelim} @`e omesso, viene usato il valore di @code{FPAT}.
+@code{patsplit()} restituisce il numero di elementi creati.
+@code{@var{separatori}[@var{i}]} @`e
+la stringa che separa
+l'elemento @code{@var{vettore}[@var{i}]} e @code{@var{vettore}[@var{i}+1]}.
+Ogni separatore iniziale sar@`a in @code{@var{separatori}[0]}.
+
+La funzione @code{patsplit()} divide delle stringhe in pezzi in modo
+simile a quello con cui le righe in input vengono divise in campi
+usando @code{FPAT}
+(@pxref{Separazione in base al contenuto}).
+
+Prima di dividere la stringa, @code{patsplit()} cancella ogni elemento che
+fosse eventualmente presente
+nei vettori @var{vettore} e @var{separatori}.
+
+@item @code{split(@var{stringa}, @var{vettore}} [@code{, @var{separacampo}} [@code{, @var{separatori}} ] ]@code{)}
+@cindexawkfunc{split}
+Divide @var{stringa} in pezzi separati da @var{separacampo}
+e memorizza i pezzi in @var{vettore} e le stringhe di separazione nel
+vettore @var{separatori}. Il primo pezzo @`e memorizzato in
+@code{@var{vettore}[1]}, il secondo pezzo in @code{@var{vettore}[2]}, e
+cos@`{@dotless{i}} via. Il valore della stringa specificata nel terzo argomento,
+@var{separacampo}, @`e una @dfn{regexp} che indica come dividere @var{stringa}
+(analogamente a come @code{FS} pu@`o essere un @dfn{regexp} che indica dove
+dividere i record in input).
+Se @var{separacampo} @`e omesso, si usa il valore di @code{FS}.
+@code{split()} restituisce il numero di elementi creati.
+@var{separatori} @`e un'estensione @command{gawk}, in cui
+@code{@var{separatori}[@var{i}]}
+@`e la stringa che separa @code{@var{vettore}[@var{i}]} e
+@code{@var{vettore}[@var{i}+1]}.
+Se @var{separacampo} @`e uno spazio bianco, ogni eventuale spazio bianco
+a inizio stringa viene messo in @code{@var{separatori}[0]} e ogni
+eventuale spazio bianco a fine stringa viene messo in
+@code{@var{separatori}[@var{n}]}, dove @var{n} @`e il valore restituito da
+@code{split()} (cio@`e il numero di elementi in @var{vettore}).
+
+La funzione @code{split()} divide le stringhe in pezzi in modo simile
+a quello con cui le righe in input sono divise in campi. Per esempio:
+
+@example
+split("cul-de-sac", a, "-", separatori)
+@end example
+
+@noindent
+@cindex stringhe, divisione, esempio
+divide la stringa @code{"cul-de-sac"} in tre campi usando @samp{-} come
+separatore. Il vettore @code{a} ha i seguenti contenuti:
+
+@example
+a[1] = "cul"
+a[2] = "de"
+a[3] = "sac"
+@end example
+
+e imposta il contenuto del vettore @code{separatori} come segue:
+
+@example
+seps[1] = "-"
+seps[2] = "-"
+@end example
+
+@noindent
+Il valore restituito da questa chiamata a @code{split()} @`e tre.
+
+@cindex differenze tra @command{awk} e @command{gawk}, funzione @code{split()}
+Come nella divisione in campi dei record in input, quando il valore di
+@var{separacampo} @`e @w{@code{" "}}, gli spazi bianchi a inizio e fine stringa
+vengono ignorati nell'assegnare valori agli elementi di @var{vettore} ma non nel
+vettore @var{separatori}, e gli elementi sono separati da uno o pi@`u spazi
+bianchi. Inoltre, come nel caso della divisione dei record in input, se
+@var{separacampo} @`e la stringa nulla, ogni singolo carattere nella stringa
+costituisce un elemento del vettore.
+@value{COMMONEXT}
+
+Si noti, tuttavia, che @code{RS} non influisce sul comportamento di
+@code{split()}.
+Anche se @samp{RS = ""} fa s@`{@dotless{i}} che il carattere di ritorno a capo sia un
+separatore di campo,
+questo non influenza il modo in cui @code{split()} divide le stringhe.
+
+@cindex angolo buio, funzione @code{split()}
+Recenti implementazioni di @command{awk}, incluso @command{gawk},
+consentono che il terzo argomento sia una costante @dfn{regexp}
+(@w{@code{/}@dots{}@code{/}})
+o anche una stringa. @value{DARKCORNER}
+Anche lo standard POSIX permette questo.
+@xref{Espressioni regolari calcolate} per la spiegazione della differenza
+tra l'uso di una costante stringa e l'uso di una costante @dfn{regexp},
+sulle loro implicazioni riguardo a come scrivere correttamente un programma.
+
+Prima di dividere la stringa, @code{split()} cancella ogni elemento
+eventualmente gi@`a presente
+nei vettori @var{vettore} e @var{separatori}.
+
+Se @var{stringa} @`e la stringa nulla, il vettore non ha elementi.
+(Quindi, in questo modo si pu@`o cancellare un intero vettore con una sola
+istruzione).
+@xref{Cancellazione}.)
+
+Se in @var{stringa} non viene trovato @var{separacampo} (ma la stringa
+non @`e la stringa nulla),
+@var{vettore} ha solo un elemento. Il valore di quell'elemento @`e la
+@var{stringa} originale.
+
+In modalit@`a POSIX (@pxref{Opzioni}), il quarto argomento non @`e disponibile.
+
+@item @code{sprintf(@var{formato}, @var{espressione1}, @dots{})}
+@cindexawkfunc{sprintf}
+@cindex formattare stringhe
+@cindex stringhe, formattazione
+Restituisce (senza stamparla) la stringa che @code{printf} avrebbe
+stampato con gli stessi argomenti
+(@pxref{Printf}).
+Per esempio:
+
+@example
+pival = sprintf("pi = %.2f (approx.)", 22/7)
+@end example
+
+@noindent
+assegna la stringa @w{@samp{pi = 3.14 (approx.)}} alla variabile @code{pival}.
+
+@cindexgawkfunc{strtonum}
+@cindex conversione di una stringa in un numero
+@cindex stringhe, conversione in numeri
+@item @code{strtonum(@var{stringa}) #}
+Esamina @var{stringa} e restituisce il suo valore numerico. Se
+@var{stringa} inizia con la cifra @samp{0}, @code{strtonum()} presuppone
+che @var{stringa} sia un numero ottale. Se @var{stringa} inizia con
+@samp{0x} o @samp{0X}, @code{strtonum()} presuppone che @var{stringa} sia un
+numero esadecimale.
+Per esempio:
+
+@example
+$ @kbd{echo 0x11 |}
+> @kbd{gawk '@{ printf "%d\n", strtonum($1) @}'}
+@print{} 17
+@end example
+
+Usare la funzione @code{strtonum()} @emph{non} @`e lo stesso che aggiungere
+zero al valore di una stringa;
+la conversione automatica di stringhe in numeri
+si applica solo a dati decimali, non a quelli ottali o
+esadecimali.@footnote{Tranne nel caso si usi l'opzione
+@option{--non-decimal-data}, il che non @`e consigliato.
+@xref{Dati non decimali} per ulteriori informazioni.}
+
+Si noti anche che @code{strtonum()} usa il separatore decimale della
+localizzazione corrente per riconoscere i numeri
+(@pxref{Localizzazioni}).
+
+@item @code{sub(@var{regexp}, @var{rimpiazzo}} [@code{, @var{obiettivo}}]@code{)}
+@cindexawkfunc{sub}
+@cindex rimpiazzare in una stringa
+@cindex stringa, rimpiazzare in una
+Ricerca in @var{obiettivo}, che @`e visto come una stringa,
+la prima sottostringa pi@`u lunga possibile,
+a partire da sinistra, che corrisponde all'espressione regolare @var{regexp}.
+Modifica l'intera stringa sostituendo il testo individuato con
+@var{rimpiazzo}.
+La stringa cos@`{@dotless{i}} modificata diventa il nuovo valore di @var{obiettivo}.
+Restituisce il numero di sostituzioni fatte (zero o uno).
+
+L'argomento @var{regexp} pu@`o essere o una costante @dfn{regexp}
+(@code{/}@dots{}@code{/}) o una constante stringa (@code{"}@dots{}@code{"}).
+In quest'ultimo caso, la stringa @`e trattata come una @dfn{regexp}
+da individuare.
+@xref{Espressioni regolari calcolate} per la spiegazione della differenza tra
+le due forme, delle loro implicazioni riguardo al modo di scrivere
+correttamente un programma.
+
+Questa funzione @`e particolare perch@'e @var{obiettivo} non @`e semplicemente usato
+per calcolare un valore, e non basta che sia un'espressione qualsiasi:
+dev'essere una variabile, un campo, o un elemento di vettore in cui
+@code{sub()} possa memorizzare un valore modificato. Se questo argomento @`e
+omesso, il comportamento di default @`e
+quello di usare e modificare
+@code{$0}.@footnote{Si noti che questo significa che il record sar@`a dapprima
+ricostruito, usando il valore di @code{OFS} se qualche campo @`e stato cambiato,
+e che i campi saranno aggiornati dopo la sostituzione, anche se l'operazione in
+s@'e non cambia il record (@`e una ``no-op'') come @samp{sub(/^/, "")}.} Per
+esempio:
+
+@example
+str = "acqua, acqua dappertutto"
+sub(/cqu/, "vari", str)
+@end example
+
+@noindent
+modifica @code{stringa} facendola divenire
+@w{@samp{avaria, acqua dappertutto}},
+rimpiazzando l'occorrenza pi@`u lunga,
+a partire da sinistra, di @samp{cqu} con @samp{vari}.
+
+Se il carattere speciale @samp{&} compare in @var{rimpiazzo}, designa
+l'esatta sottostringa individuata da @var{regexp}. (Se
+@dfn{regexp} pu@`o individuare pi@`u di una stringa, questa sottostringa
+pu@`o assumere valori diversi.) Per esempio:
+
+@example
+@{ sub(/candidato/, "& e sua moglie"); print @}
+@end example
+
+@noindent
+cambia la prima occorrenza di @samp{candidato} a @samp{candidato
+e sua moglie} in ogni riga in input.
+Ecco un altro esempio:
+
+@example
+$ @kbd{awk 'BEGIN @{}
+> @kbd{str = "daabaaa"}
+> @kbd{sub(/a+/, "C&C", str)}
+> @kbd{print str}
+> @kbd{@}'}
+@print{} dCaaCbaaa
+@end example
+
+@noindent
+questo mostra come @samp{&} possa rappresentare una stringa variabile
+e illustra anche la regola
+``a partire da sinistra, la pi@`u lunga'' nell'individuazione di @dfn{regexp}
+(@pxref{Pi@`u lungo da sinistra}).
+
+L'effetto di questo carattere speciale (@samp{&}) pu@`o essere neutralizzato
+anteponendogli una barra inversa nella stringa. Come al solito, per
+inserire una barra inversa nella
+stringa, occorre scrivere due barre inverse. Quindi, occorre scrivere
+@samp{\\&} in una costante stringa per includere un carattere @samp{&}
+nel rimpiazzo.
+Per esempio, quanto segue mostra come rimpiazzare il primo @samp{|} su
+ogni riga con un @samp{&}:
+
+@example
+@{ sub(/\|/, "\\&"); print @}
+@end example
+
+@cindex @code{sub()}, funzione, argomenti di
+@cindex funzione @code{sub()}, argomenti di
+@cindex @code{gsub()}, funzione, argomenti di
+@cindex funzione @code{gsub()}, argomenti di
+Come gi@`a accennato, il terzo argomento di @code{sub()} dev'essere
+una variabile, un campo, o un elemento di vettore.
+Alcune versioni di @command{awk} accettano come terzo argomento
+un'espressione che non @`e un @dfn{lvalue}. In tal caso, @code{sub()}
+cerca ugualmente l'espressione e restituisce zero o uno, ma il risultato
+della sostituzione (se ce n'@`e uno) viene scartato perch@'e non c'@`e un posto
+dove memorizzarlo. Tali versioni di @command{awk} accettano espressioni
+come le seguente:
+
+@example
+sub(/USA/, "Stati Uniti", "gli USA e il Canada")
+@end example
+
+@noindent
+@cindex risoluzione di problemi, funzioni @code{gsub()}/@code{sub()}
+@cindex problemi, risoluzione di, funzioni @code{gsub()}/@code{sub()}
+Per compatibilit@`a storica, @command{gawk} accetta un tale codice erroneo.
+Tuttavia, l'uso di qualsiasi altra espressione non modificabile
+come terzo parametro causa un errore fatale, e il programma
+non viene portato a termine.
+
+Infine, se la @var{regexp} non @`e una costante @dfn{regexp}, @`e convertita
+in una stringa, e quindi il valore di quella stringa @`e trattato come
+la @dfn{regexp} da individuare.
+
+@item @code{substr(@var{stringa}, @var{inizio}} [@code{, @var{lunghezza}} ]@code{)}
+@cindexawkfunc{substr}
+@cindex sottostringa
+Restituisce una sottostringa di @var{stringa} lunga @var{lunghezza} caratteri,
+iniziando dal carattere numero @var{inizio}. Il primo carattere di una
+stringa @`e il carattere numero uno.@footnote{Questo @`e differente da
+C e C++, in cui il primo carattere ha il numero zero.}
+Per esempio, @code{substr("Washington", 5, 3)} restituisce @code{"ing"}.
+
+Se @var{lunghezza} non @`e presente, @code{substr()} restituisce l'intero
+suffisso di
+@var{stringa} a partire dal carattere numero @var{inizio}. Per esempio,
+@code{substr("Washington", 5)} restituisce @code{"ington"}. L'intero
+suffisso @`e restituito anche
+se @var{lunghezza} @`e maggiore del numero di caratteri disponibili
+nella stringa, a partire dal carattere @var{inizio}.
+
+@cindex Brian Kernighan, @command{awk} di
+Se @var{inizio} @`e minore di uno, @code{substr()} lo tratta come se
+fosse uno. (POSIX non specifica cosa fare in questo caso:
+BWK @command{awk} si comporta cos@`{@dotless{i}}, e quindi @command{gawk} fa lo stesso.)
+Se @var{inizio} @`e maggiore del numero di caratteri
+nella stringa, @code{substr()} restituisce la stringa nulla.
+Analogamente, se @var{lunghezza} @`e presente ma minore o uguale a zero,
+viene restituita la stringa nulla.
+
+@cindex risoluzione di problemi, funzione @code{substr()}
+@cindex problemi, risoluzione di, funzione @code{substr()}
+La stringa restituita da @code{substr()} @emph{non pu@`o} essere
+assegnata. Quindi, @`e un errore tentare di modificare una porzione di
+una stringa, come si vede nel seguente esempio:
+
+@example
+stringa = "abcdef"
+# tentare di ottenere "abCDEf", non @`e possibile
+substr(stringa, 3, 3) = "CDE"
+@end example
+
+@noindent
+@`E anche un errore usare @code{substr()} come terzo argomento
+di @code{sub()} o @code{gsub()}:
+
+@example
+gsub(/xyz/, "pdq", substr($0, 5, 20)) # SBAGLIATO
+@end example
+
+@cindex portabilit@`a, funzione @code{substr()}
+(Alcune versioni commerciali di @command{awk} consentono un tale uso di
+@code{substr()}, ma un tale codice non @`e portabile.)
+
+Se si devono sostituire pezzi di una stringa,
+si combini @code{substr()}
+con una concatenazione di stringa, nel modo seguente:
+
+@example
+stringa = "abcdef"
+@dots{}
+stringa = substr(stringa, 1, 2) "CDE" substr(stringa, 6)
+@end example
+
+@cindex maiuscolo/minuscolo, conversione da/a
+@cindex stringhe, convertire maiuscolo/minuscolo
+@item @code{tolower(@var{stringa})}
+@cindexawkfunc{tolower}
+@cindex convertire stringa in minuscolo
+Restituisce una copia di @var{stringa}, con ogni carattere maiuscolo
+nella stringa rimpiazzato dal suo corrispondente carattere minuscolo.
+I caratteri non alfabetici non vengono modificati. Per esempio,
+@code{tolower("MaIuScOlO MiNuScOlO 123")} restituisce
+@code{"maiuscolo minuscolo 123"}.
+
+@item @code{toupper(@var{stringa})}
+@cindexawkfunc{toupper}
+@cindex convertire stringa in maiuscolo
+Restituisce una copia di @var{stringa}, con ogni carattere minuscolo
+nella stringa rimpiazzato dal suo corrispondente carattere maiuscolo.
+I caratteri non alfabetici non vengono modificati. Per esempio,
+@code{tolower("MaIuScOlO MiNuScOlO 123")} restituisce
+@code{"MAIUSCOLO MINUSCOLO 123"}.
+@end table
+
+@sidebar Individuare la stringa nulla
+@cindex individuare la stringa nulla
+@cindex stringa nulla, individuare la
+@cindex @code{*} (asterisco), operatore @code{*}, individuare la stringa nulla
+@cindex asterisco (@code{*}), operatore @code{*}, individuare la stringa nulla
+
+In @command{awk}, l'operatore @samp{*} pu@`o individuare la stringa nulla.
+Questo @`e particolarmente importante per le funzioni @code{sub()},
+@code{gsub()} e @code{gensub()}. Per esempio:
+
+@example
+$ @kbd{echo abc | awk '@{ gsub(/m*/, "X"); print @}'}
+@print{} XaXbXcX
+@end example
+
+@noindent
+Sebbene questo sia abbastanza sensato, pu@`o suscitare una certa sorpresa.
+@end sidebar
+
+
+@node Dettagli ostici
+@subsubsection Ulteriori dettagli su @samp{\} e @samp{&} con @code{sub()}, @code{gsub()} e @code{gensub()}
+
+@cindex protezione caratteri nelle funzioni @code{gsub()}/@code{gensub()}/@code{sub()}
+@cindex funzione @code{sub()}, protezione caratteri
+@cindex @code{sub()}, funzione, protezione caratteri
+@cindex funzione @code{gsub()}, protezione caratteri
+@cindex @code{gsub()}, funzione, protezione caratteri
+@cindex funzione @code{gensub()} (@command{gawk}), protezione caratteri
+@cindex @code{gensub()}, funzione (@command{gawk}), protezione caratteri
+@cindex @code{\} (barra inversa), @code{gsub()}/@code{gensub()}/@code{sub()} funzioni e
+@cindex barra inversa (@code{\}), @code{gsub()}/@code{gensub()}/@code{sub()} funzioni e
+@cindex @code{&} (e commerciale), funzioni @code{gsub()}/@code{gensub()}/@code{sub()} e
+@cindex e commerciale (@code{&}), funzioni @code{gsub()}/@code{gensub()}/@code{sub()} e
+
+@quotation ATTENZIONE
+Si dice che questa sottosezione possa causare dei mal di testa.
+In prima lettura pu@`o essere benissimo saltata.
+@end quotation
+
+Quando si usa @code{sub()}, @code{gsub()} o @code{gensub()}, e si
+desidera includere delle
+barre inverse e delle "e commerciali" (@code{&}) nel testo da sostituire
+@`e necessario ricordare che ci sono parecchi livelli di
+@dfn{protezione caratteri} in gioco.
+
+Anzitutto, vi @`e il livello @dfn{lessicale}, quello in cui @command{awk}
+legge un programma e ne costruisce una copia interna da eseguire.
+Poi c'@`e il momento dell'esecuzione, quello in cui @command{awk}
+esamina effettivamente la stringa da sostituire, per determinare cosa
+fare.
+
+@cindex Brian Kernighan, @command{awk} di
+In entrambi i livelli, @command{awk} ricerca un dato insieme di caratteri
+che possono venire dopo una
+barra inversa. A livello lessicale, cerca le sequenze di protezione
+elencate in @ref{Sequenze di protezione}.
+Quindi, per ogni @samp{\} che @command{awk} elabora al momento
+dell'esecuzione, occorre immetterne due a livello lessicale.
+Quando un carattere che non ha necessit@`a di una sequenza di protezione
+segue una @samp{\}, sia BWK @command{awk} che @command{gawk} semplicemente
+rimuovono la @samp{\} stessa e
+mettono il carattere seguente nella stringa. Quindi, per esempio,
+@code{"a\qb"} @`e trattato come se si fosse scritto @code{"aqb"}.
+
+Al momento dell'esecuzione, le varie funzioni gestiscono sequenze di
+@samp{\} e @samp{&} in maniera differente. La situazione @`e (purtroppo)
+piuttosto complessa.
+Storicamente, le funzioni @code{sub()} e @code{gsub()} trattavano la
+sequenza di due caratteri @samp{\&} in maniera speciale; questa sequenza
+era rimpiazzata nel testo
+generato da un singolo carattere @samp{&}. Ogni altra @samp{\} contenuta
+nella stringa @var{rimpiazzo} che non era posta prima di una @samp{&} era
+lasciata passare senza modifiche.
+Questo @`e illustrato nella @ref{table-sub-escapes}.
+
+@c Thank to Karl Berry for help with the TeX stuff.
+@float Tabella,table-sub-escapes
+@caption{Elaborazione storica delle sequenze di protezione per @code{sub()} e @code{gsub()}}
+@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
+ Immissione!@code{sub()} vede!@code{sub()} genera_cr
+_hrulefill!_hrulefill!_hrulefill_cr
+ @code{\&}! @code{&}!Il testo individuato_cr
+ @code{\\&}! @code{\&}!Il carattere @samp{&}_cr
+ @code{\\\&}! @code{\&}!Il carattere @samp{&}_cr
+ @code{\\\\&}! @code{\\&}!I caratteri @samp{\&}_cr
+ @code{\\\\\&}! @code{\\&}!I caratteri @samp{\&}_cr
+@code{\\\\\\&}! @code{\\\&}!I caratteri @samp{\\&}_cr
+ @code{\\q}! @code{\q}!I caratteri @samp{\q}_cr
+}
+_bigskip}
+@end tex
+@ifdocbook
+@multitable @columnfractions .20 .20 .60
+@headitem Immissione @tab @code{sub()} vede @tab @code{sub()} genera
+@item @code{\&} @tab @code{&} @tab Il testo individuato
+@item @code{\\&} @tab @code{\&} @tab Il carattere @samp{&}
+@item @code{\\\&} @tab @code{\&} @tab Il carattere @samp{&}
+@item @code{\\\\&} @tab @code{\\&} @tab I caratteri @samp{\&}
+@item @code{\\\\\&} @tab @code{\\&} @tab I caratteri @samp{\&}
+@item @code{\\\\\\&} @tab @code{\\\&} @tab I caratteri @samp{\\&}
+@item @code{\\q} @tab @code{\q} @tab I caratteri @samp{\q}
+@end multitable
+@end ifdocbook
+@ifnottex
+@ifnotdocbook
+@display
+ Immissione @code{sub()} vede @code{sub()} genera
+ --------------- ------------- ---------------
+ @code{\&} @code{&} Il testo individuato
+ @code{\\&} @code{\&} La lettera @samp{&}
+ @code{\\\&} @code{\&} La lettera @samp{&}
+ @code{\\\\&} @code{\\&} Le lettere @samp{\&}
+ @code{\\\\\&} @code{\\&} Le lettere @samp{\&}
+@code{\\\\\\&} @code{\\\&} Le lettere @samp{\\&}
+ @code{\\q} @code{\q} Le lettere @samp{\q}
+@end display
+@end ifnotdocbook
+@end ifnottex
+@end float
+
+@noindent
+Questa tabella mostra l'elaborazione a livello lessicale, in cui
+un numero dispari di barre inverse diventa un numero pari al momento
+dell'esecuzione,
+e mostra anche l'elaborazione in fase di esecuzione fatta da @code{sub()}.
+(Per amor di semplicit@`a le tavole che ancora seguono mostrano solo il caso
+di un numero pari di barre inverse immesso a livello lessicale.)
+
+Il problema con l'approccio storico @`e che non c'@`e modo di ottenere
+un carattere @samp{\} seguito dal testo individuato.
+
+Parecchie edizioni dello standard POSIX hanno provato a risolvere questo
+problema, senza riuscirci. I dettagli sono irrilevanti in questo contesto.
+
+A un certo punto, il manutentore di @command{gawk} ha presentato una
+proposta per una revisione dello standard per tornare
+a regole che corrispondano pi@`u da vicino alla prassi originalmente seguita.
+Le regole proposte hanno dei casi speciali che rendono possibile
+produrre una @samp{\} prima del
+testo individuato. Questo si pu@`o vedere nella
+@ref{table-sub-proposed}.
+
+@float Tabella,table-sub-proposed
+@caption{Regole @command{gawk} per @code{sub()} e barra inversa}
+@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
+ Immissione!@code{sub()} vede!@code{sub()} genera_cr
+_hrulefill!_hrulefill!_hrulefill_cr
+@code{\\\\\\&}! @code{\\\&}!I caratteri @samp{\&}_cr
+@code{\\\\&}! @code{\\&}!Il carattere @samp{\}, seguito dal testo individuato_cr
+ @code{\\&}! @code{\&}!Il carattere @samp{&}_cr
+ @code{\\q}! @code{\q}!I caratteri @samp{\q}_cr
+ @code{\\\\}! @code{\\}!@code{\\}_cr
+}
+_bigskip}
+@end tex
+@ifdocbook
+@multitable @columnfractions .20 .20 .60
+@headitem Immissione @tab @code{sub()} vede @tab @code{sub()} genera
+@item @code{\\\\\\&} @tab @code{\\\&} @tab I caratteri @samp{\&}
+@item @code{\\\\&} @tab @code{\\&} @tab Il carattere @samp{\}, seguito dal testo individuato
+@item @code{\\&} @tab @code{\&} @tab Il carattere @samp{&}
+@item @code{\\q} @tab @code{\q} @tab I caratteri @samp{\q}
+@item @code{\\\\} @tab @code{\\} @tab @code{\\}
+@end multitable
+@end ifdocbook
+@ifnottex
+@ifnotdocbook
+@display
+Immissione @code{sub()} vede @code{sub()} genera
+--------- ---------- ---------------
+@code{\\\\\\&} @code{\\\&} Il carattere @samp{\&}
+ @code{\\\\&} @code{\\&} Il carattere @samp{\}, seguito dal testo individuato
+ @code{\\&} @code{\&} Il carattere @samp{&}
+ @code{\\q} @code{\q} I caratteri @samp{\q}
+ @code{\\\\} @code{\\} @code{\\}
+@end display
+@end ifnotdocbook
+@end ifnottex
+@end float
+
+In breve, al momento dell'esecuzione, ci sono ora tre sequenze speciali
+di caratteri (@samp{\\\&}, @samp{\\&}, e @samp{\&}) mentre tradizionalmente
+ce n'era una sola. Tuttavia, come nel caso storico, ogni @samp{\} che
+non fa parte di una di queste tre sequenze non @`e speciale e appare
+nell'output cos@`{@dotless{i}} come @`e scritto.
+
+@command{gawk} 3.0 e 3.1 seguono queste regole per @code{sub()} e
+@code{gsub()}. La revisione dello standard POSIX ha richiesto molto pi@`u tempo
+di quel che ci si attendeva. Inoltre, la proposta del manutentore di
+@command{gawk} @`e andata persa durante il processo di standardizzazione. Le
+regole finali risultanti sono un po' pi@`u semplici. I risultati sono simili,
+tranne che in un caso.
+
+@cindex POSIX @command{awk}, funzioni @code{gsub()}/@code{sub()} e
+Le regole POSIX stabiliscono che @samp{\&} nella stringa di rimpiazzo
+produca il carattere @samp{&}, @samp{\\} produce il carattere @samp{\},
+e che @samp{\} seguito da qualsiasi carattere non @`e speciale; la @samp{\}
+@`e messa direttamente nell'output.
+Queste regole sono presentate nella @ref{table-posix-sub}.
+
+@float Tabella,table-posix-sub
+@caption{Regole POSIX per @code{sub()} e @code{gsub()}}
+@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
+ Immissione!@code{sub()} vede!@code{sub()} genera_cr
+_hrulefill!_hrulefill!_hrulefill_cr
+@code{\\\\\\&}! @code{\\\&}!I caratteri @samp{\&}_cr
+@code{\\\\&}! @code{\\&}!Il carattere @samp{\}, seguito dal testo individuato_cr
+ @code{\\&}! @code{\&}!Il carattere @samp{&}_cr
+ @code{\\q}! @code{\q}!I caratteri @samp{\q}_cr
+ @code{\\\\}! @code{\\}!@code{\}_cr
+}
+_bigskip}
+@end tex
+@ifdocbook
+@multitable @columnfractions .20 .20 .60
+@headitemImmissione @tab @code{sub()} vede @tab @code{sub()} genera
+@item @code{\\\\\\&} @tab @code{\\\&} @tab I caratteri @samp{\&}
+@item @code{\\\\&} @tab @code{\\&} @tab Il carattere @samp{\}, seguito dal testo individuato
+@item @code{\\&} @tab @code{\&} @tab I caratteri @samp{&}
+@item @code{\\q} @tab @code{\q} @tab I caratteri @samp{\q}
+@item @code{\\\\} @tab @code{\\} @tab @code{\}
+@end multitable
+@end ifdocbook
+@ifnottex
+@ifnotdocbook
+@display
+Immissione @code{sub()} vede @code{sub()} genera
+--------- ---------- ---------------
+@code{\\\\\\&} @code{\\\&} I caratteri @samp{\&}
+ @code{\\\\&} @code{\\&} Il carattere @samp{\}, seguito dal testo individuato
+ @code{\\&} @code{\&} Il carattere @samp{&}
+ @code{\\q} @code{\q} I caratteri @samp{\q}
+ @code{\\\\} @code{\\} @code{\}
+@end display
+@end ifnotdocbook
+@end ifnottex
+@end float
+
+Il solo caso in cui la differenza @`e rilevante @`e l'ultimo: @samp{\\\\}
+@`e visto come @samp{\\} e produce @samp{\} invece che @samp{\\}.
+
+A partire dalla @value{PVERSION} 3.1.4, @command{gawk} ha seguito le regole
+POSIX quando si specifica @option{--posix} (@pxref{Opzioni}). Altrimenti, ha
+continuato a seguire le regole proposte [a POSIX], poich@'e questa @`e stato il
+comportamento seguito per parecchi anni.
+
+Quando la @value{PVERSION} 4.0.0 @`e stata rilasciata, il manutentore di
+@command{gawk}
+ha stabilito come default le regole POSIX, interrompendo cos@`{@dotless{i}} oltre
+un decennio di compatibilit@`a
+all'indietro.@footnote{Questa decisione si @`e dimostrata piuttosto avventata,
+anche se una nota in questa sezione avvertiva che la successiva versione
+principale di @command{gawk} avrebbe adottato le regole POSIX.}
+Inutile dire che questa non @`e stata una buona idea, e quindi dalla
+@value{PVERSION} 4.0.1, @command{gawk} ha ripreso il suo comportamento
+tradizionale, seguendo le regole POSIX solo quando si specifica l'opzione
+@option{--posix}.
+
+Le regole per @code{gensub()} sono molto pi@`u semplici. Al momento
+dell'esecuzione, quando @command{gawk} vede una @samp{\}, se il carattere
+seguente @`e una cifra,
+il testo individuato dalla corrispondente sottoespressione tra parentesi
+@`e inserito nell'output generato. Altrimenti, qualsiasi carattere segua la
+@samp{\} viene inserito nel testo generato, mentre la @samp{\} va persa,
+come si vede nella @ref{table-gensub-escapes}.
+
+@float Tabella,table-gensub-escapes
+@caption{Elaborazione sequenze di protezione in @code{gensub()}}
+@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
+ Immissione!@code{gensub()} vede!@code{gensub()} genera_cr
+_hrulefill!_hrulefill!_hrulefill_cr
+ @code{&}! @code{&}!Il testo individuato_cr
+ @code{\\&}! @code{\&}!Il carattere @samp{&}_cr
+ @code{\\\\}! @code{\\}!Il carattere @samp{\}_cr
+ @code{\\\\&}! @code{\\&}!Il carattere @samp{\}, seguito dal testo individuato_cr
+@code{\\\\\\&}! @code{\\\&}!I caratteri @samp{\&}_cr
+ @code{\\q}! @code{\q}!Il carattere @samp{q}_cr
+}
+_bigskip}
+@end tex
+@ifdocbook
+@multitable @columnfractions .20 .20 .60
+@headitem Immissione @tab @code{gensub()} vede @tab @code{gensub()} genera
+@item @code{&} @tab @code{&} @tab Il testo individuato
+@item @code{\\&} @tab @code{\&} @tab Il carattere @samp{&}
+@item @code{\\\\} @tab @code{\\} @tab Il carattere @samp{\}
+@item @code{\\\\&} @tab @code{\\&} @tab Il carattere @samp{\}, seguito dal testo individuato
+@item @code{\\\\\\&} @tab @code{\\\&} @tab I caratteri @samp{\&}
+@item @code{\\q} @tab @code{\q} @tab Il carattere @samp{q}
+@end multitable
+@end ifdocbook
+@ifnottex
+@ifnotdocbook
+@display
+ Immissione @code{gensub()} vede @code{gensub()} genera
+ --------- ------------- ------------------
+ @code{&} @code{&} Il testo individuato
+ @code{\\&} @code{\&} Il carattere @samp{&}
+ @code{\\\\} @code{\\} Il carattere @samp{\}
+ @code{\\\\&} @code{\\&} Il carattere @samp{\}, seguito dal testo individuato
+@code{\\\\\\&} @code{\\\&} I caratteri @samp{\&}
+ @code{\\q} @code{\q} Il carattere @samp{q}
+@end display
+@end ifnotdocbook
+@end ifnottex
+@end float
+
+A causa della complessit@`a dell'elaborazione a livello lessicale e in fase
+di esecuzione, e dei casi speciali di @code{sub()} e @code{gsub()},
+si raccomanda l'uso di @command{gawk} e di @code{gensub()} quando ci siano
+da fare delle sostituzioni.
+
+@node Funzioni di I/O
+@subsection Funzioni di Input/Output
+@cindex input/output, funzioni di
+@cindex funzioni di input/output
+
+Le seguenti funzioni riguardano l'input/output (I/O).
+I parametri facoltativi sono racchiusi tra parentesi quadre ([ ]):
+
+@table @asis
+@item @code{close(}@var{nome_file} [@code{,} @var{come}]@code{)}
+@cindexawkfunc{close}
+@cindex file, chiusura
+@cindex chiudere un file o un coprocesso
+Chiude il file @var{nome_file} in input o in output. Alternativamente,
+l'argomento pu@`o essere un comando della shell usato per creare un
+coprocesso, o per ridirigere
+verso o da una @dfn{pipe}; questo coprocesso o @dfn{pipe} viene chiuso.
+@xref{Chiusura file e @dfn{pipe}}
+per ulteriori informazioni.
+
+Quando si chiude un coprocesso, pu@`o talora essere utile chiudere dapprima
+un lato della @dfn{pipe} bidirezionale e quindi chiudere l'altro.
+Questo si pu@`o fare fornendo un secondo argomento a @code{close()}.
+Questo secondo argomento (@var{come})
+dovrebbe essere una delle due stringhe @code{"to"} o @code{"from"},
+che indicano quale lato della @dfn{pipe} chiudere. La stringa pu@`o essere
+scritta indifferentemente in maiuscolo o in minuscolo.
+@xref{I/O bidirezionale},
+che tratta questa funzionalit@`a con maggior dettaglio e mostra un esempio.
+
+Si noti che il secondo argomento di @code{close()} @`e
+un'estensione @command{gawk}; non @`e disponibile in modalit@`a compatibile
+(@pxref{Opzioni}).
+
+@item @code{fflush(}[@var{nome_file}]@code{)}
+@cindexawkfunc{fflush}
+@cindex scrivere su disco i buffer di output contenuti in memoria
+Scrive su disco ogni output contenuto in memoria, associato con
+@var{nome_file}, che @`e o un
+file aperto in scrittura o un comando della shell che ridirige output a
+una @dfn{pipe} o a un coprocesso.
+
+@cindex buffer, scrivere su disco un
+@cindex memoria tampone, scrivere su disco
+@cindex output, bufferizzazione
+@cindex output, nella memoria tampone (buffer)
+Molti programmi di utilit@`a @dfn{bufferizzano} il loro output (cio@`e,
+accumulano in memoria record da scrivere in un file su disco o sullo
+schermo, fin quando non arriva il momento giusto per inviare i
+dati al dispositivo di output).
+Questo @`e spesso pi@`u efficiente che scrivere
+ogni particella di informazione non appena diventa disponibile. Tuttavia,
+qualche volta @`e necessario forzare un programma a @dfn{svuotare}
+i suoi buffer (cio@`e, inviare l'informazione alla sua destinazione,
+anche se un buffer non @`e pieno).
+Questo @`e lo scopo della funzione @code{fflush()}; anche
+@command{gawk} scrive il suo output in un buffer, e la funzione @code{fflush()}
+forza @command{gawk} a svuotare i suoi buffer.
+
+@cindex estensioni comuni, funzione @code{fflush()}
+@cindex Brian Kernighan, @command{awk} di
+Brian Kernighan ha aggiunto @code{fflush()} al suo @command{awk} nell'aprile
+1992. Per due decenni @`e rimasta un'estensione comune. A Dicembre
+2012 @`e stata accettata e inclusa nello standard POSIX.
+Si veda @uref{http://austingroupbugs.net/view.php?id=634, il sito Web dell'Austin Group}.
+
+POSIX standardizza @code{fflush()} come segue: se non c'@`e alcun
+argomento, o se l'argomento @`e la stringa nulla (@w{@code{""}}),
+@command{awk} svuota i buffer di @emph{tutti} i file in output e di
+@emph{tutte} le @dfn{pipe}.
+
+@quotation NOTA
+Prima della @value{PVERSION} 4.0.2, @command{gawk}
+avrebbe svuotato solo i buffer dello standard output se non era
+specificato alcun argomento,
+e svuotato tutti i buffer dei file in output e delle @dfn{pipe} se
+l'argomento era la stringa nulla.
+Questo @`e stato modificato per essere compatibile con l'@command{awk} di
+Kernighan, nella speranza che standardizzare questa
+funzionalit@`a in POSIX sarebbe stato pi@`u agevole (come poi @`e effettivamente
+successo).
+
+Con @command{gawk},
+si pu@`o usare @samp{fflush("/dev/stdout")} se si desidera solo svuotare i
+buffer dello standard output.
+@end quotation
+
+@c @cindex automatic warnings
+@c @cindex warnings, automatic
+@cindex risoluzione di problemi, funzione @code{fflush()}
+@cindex problemi, risoluzione di, funzione @code{fflush()}
+@code{fflush()} restituisce zero se il buffer @`e svuotato con successo;
+altrimenti, restituisce un valore diverso da zero. (@command{gawk}
+restituisce @minus{}1.)
+Nel caso in cui tutti i buffer vadano svuotati, il valore restituito @`e zero
+solo se tutti i buffer sono stati svuotati con successo. Altrimenti,
+@`e @minus{}1, e @command{gawk} avvisa riguardo al @var{nome_file}
+che ha problemi.
+
+@command{gawk} invia anche un messaggio di avvertimento se si tenta di svuotare i
+buffer di un file o @dfn{pipe} che era stato aperto in lettura
+(p.es. con @code{getline}),
+o se @var{nome_file} non @`e un file, una @dfn{pipe}, o un coprocesso aperto.
+in tal caso, @code{fflush()} restituisce ancora @minus{}1.
+
+@sidebar Bufferizzazione interattiva e non interattiva
+@cindex bufferizzazione, interattiva vs.@: non interattiva
+
+A complicare ulteriormente le cose, i problemi di bufferizzazione possono
+peggiorare se il programma eseguito
+@`e @dfn{interattivo} (cio@`e, se
+comunica con un utente seduto davanti a una tastiera).@footnote{Un programma
+@`e interattivo se il suo standard output @`e connesso a un dispositivo
+terminale. Ai giorni nostri, questo vuol dire davanti a uno
+schermo e a una tastiera.}
+
+@c Thanks to Walter.Mecky@dresdnerbank.de for this example, and for
+@c motivating me to write this section.
+I programmi interattivi normalmente @dfn{bufferizzano per riga} il loro
+output (cio@`e, scrivono in output una riga alla volta). I programmi
+non-interattivi attendono di aver riempito un buffer, il che pu@`o voler dire
+anche parecchie righe di output.
+Ecco un esempio della differenza:
+
+@example
+$ @kbd{awk '@{ print $1 + $2 @}'}
+@kbd{1 1}
+@print{} 2
+@kbd{2 3}
+@print{} 5
+@kbd{Ctrl-d}
+@end example
+
+@noindent
+Ogni riga di output @`e stampata immediatamente. Si confronti questo
+comportamente con quello di questo esempio:
+
+@example
+$ @kbd{awk '@{ print $1 + $2 @}' | cat}
+@kbd{1 1}
+@kbd{2 3}
+@kbd{Ctrl-d}
+@print{} 2
+@print{} 5
+@end example
+
+@noindent
+In questo caso, nessun output viene stampato finch@'e non @`e stato battuto il
+@kbd{Ctrl-d}, perch@'e l'output @`e bufferizzato e inviato tramite
+@dfn{pipe} al comando @command{cat} in un colpo solo.
+@end sidebar
+
+@item @code{system(@var{comando})}
+@cindexawkfunc{system}
+@cindex chiamare comandi di shell
+@cindex interagire con altri programmi
+Esegue il comando del sistema operativo @var{comando} e quindi
+ritorna al programma @command{awk}.
+Restituisce il codice ritorno di @var{comando}.
+
+Per esempio, inserendo il seguente frammento di codice in un programma
+@command{awk}:
+
+@example
+END @{
+ system("date | mail -s 'awk completato' root")
+@}
+@end example
+
+@noindent
+all'amministratore di sistema viene inviato un messaggio di posta quando
+il programma @command{awk} termina di elaborare l'input e inizia
+l'elaborazione da eseguire alla fine dell'input.
+
+Si noti che la ridirezione di @code{print} o @code{printf} in una
+@dfn{pipe} @`e spesso sufficiente per ottenere lo stesso risultato.
+Se @`e necessario eseguire parecchi comandi, @`e pi@`u efficiente
+stamparli verso una @dfn{pipe} diretta alla shell:
+
+@example
+while (@var{ancora lavoro da fare})
+ print @var{comando} | "/bin/sh"
+close("/bin/sh")
+@end example
+
+@noindent
+@cindex risoluzione di problemi, funzione @code{system()}
+@cindex problemi, risoluzione di, funzione @code{system()}
+@cindex @option{--sandbox}, opzione, disabilitare la funzione @code{system()}
+@cindex opzione @option{--sandbox}, disabilitare la funzione @code{system()}
+Tuttavia, nel caso che il programma @command{awk} sia interattivo,
+@code{system()} @`e utile per eseguire grossi programmi autonomi,
+come ad esempio la shell o un programma di modifica testi.
+Alcuni sistemi operativi non consentono di implementare la funzione
+@code{system()}.
+Richiamare @code{system()} in sistemi in cui non @`e disponibile provoca
+un errore fatale.
+
+@quotation NOTA
+Quando si specifica l'opzione @option{--sandbox}, la funzione @code{system()} @`e
+disabilitata (@pxref{Opzioni}).
+@end quotation
+
+Nei sistemi aderenti allo standard POSIX, il codice di ritorno di un
+comando @`e un numero contenuto in 16 bit. Il valore del codice di ritorno
+passato alla funzione C @code{exit()} alla fine del programma @`e contenuto
+negli 8 bit di valore pi@`u alto dei 16 bit (la met@`a sinistra) che compongono
+il numero. I bit di valore pi@`u basso (la met@`a destra) indicano se il
+processo @`e stato terminato da un segnale (bit 7), e, se questo @`e il caso,
+il numero del segnale che ha provocato la terminazione (bit 0--6).
+
+Tradizionalmente, la funzione @code{system()} di @command{awk} si @`e
+semplicemente limitata a restituire il valore del codice di ritorno
+diviso per 256 (ossia la met@`a sinistra del numero di 16 bit, spostata
+a destra). In una situazione normale questo equivale a utilizzare il
+codice di ritornodi @code{system()}, ma nel caso in cui il programma sia
+stato terminato da un segnale, il valore diventa un numero frazionale a
+virgola mobile.@footnote{In uno scambio di messaggi privato il Dr.@:
+Kernighan mi ha comunicato che questo modo di procedere @`e probabilmente
+errato.} POSIX stabilisce che la chiamata a @code{system()} dall'interno
+di @command{awk} dovrebbe restituire l'intero valore a 16 bit.
+
+@command{gawk} si trova in qualche modo a met@`a strada.
+I valori del codice di ritorno sono descritti nella
+@ref{table-system-return-values}.
+
+@float Tabella,table-system-return-values
+@caption{Valori codici di ritorno da chiamata a @code{system()}}
+@multitable @columnfractions .40 .60
+@headitem Situazione @tab Valore codice di ritorno da @code{system()}
+@item @option{--traditional} @tab Valore dalla funzione C @code{system()}/256
+@item @option{--posix} @tab Valore dalla funzione C @code{system()}
+@item Uscita normale dal comando @tab Codice di ritorno del comando
+@item Terminazione da un segnale @tab 256 + numero segnale "assassino"
+@item Terminazione da un segnale con dump memoria @tab 512 + numero segnale "assassino"
+@item Qualsiasi tipo di errore @tab @minus{}1
+@end multitable
+@end float
+@end table
+
+@sidebar Controllare la bufferizzazione dell'output con @code{system()}
+@cindex buffer, scrivere su disco un
+@cindex bufferizzazione, dell'input/output
+@cindex output, bufferizzazione
+@cindex bufferizzazione, dell'output
+
+La funzione @code{fflush()} consente un controllo esplicito sulla
+bufferizzazione dell'output per singoli file e @dfn{pipe}.
+Tuttavia, il suo utilizzo non @`e portabile su molte delle meno recenti
+implementazioni di @command{awk}. Un metodo alternativo per forzare la
+scrittura dell'output @`e una chiamata a
+@code{system()} che abbia come argomento la stringa nulla:
+
+@example
+system("") # scrive l'output su disco
+@end example
+
+@noindent
+@command{gawk} tratta questo uso della funzione @code{system()} come un
+caso speciale, e si guarda bene dall'invocare la shell (o un altro
+interprete di comandi) con un comando nullo.
+Quindi, con @command{gawk}, questa maniera di procedere non @`e solo utile,
+ma @`e anche efficiente.
+Questo metodo dovrebbe funzionare anche con
+altre implementazioni di @command{awk}, ma non @`e detto che eviti una
+invocazione non necessaria della shell. (Altre implementazioni potrebbero
+limitarsi a forzare la scrittura del buffer associato con lo
+standard output, e non necessariamente di tutto l'output bufferizzato.)
+
+Avendo in mente le attese di un programmatore, sarebbe sensato che
+@code{system()} forzi la scrittura su disco di tutto l'output disponibile.
+Il programma seguente:
+
+@example
+BEGIN @{
+ print "prima riga stampata"
+ system("echo system echo")
+ print "seconda riga stampata"
+@}
+@end example
+
+@noindent
+deve stampare:
+
+@example
+prima riga stampata
+system echo
+seconda riga stampata
+@end example
+
+@noindent
+e non:
+
+@example
+system echo
+prima riga stampata
+seconda riga stampata
+@end example
+
+Se @command{awk} non forzasse la scrittura dei suoi buffer prima di
+invocare @code{system()}, l'output sarebbe quest'ultimo (quello non voluto).
+@end sidebar
+
+@node Funzioni di tempo
+@subsection Funzioni per gestire marcature temporali
+@cindex funzioni di tempo
+
+@cindex marcature temporali
+@cindex data e ora, si veda marcature temporali
+@cindex @dfn{log} (registro), file di, marcature temporali nei
+@cindex registro (@dfn{log}), file di, marcature temporali nel
+@cindex file di registro (@dfn{log}), marcature temporali nei
+@cindex @command{gawk}, data e ora (marcature temporali)
+@cindex POSIX @command{awk}, marcature temporali e
+I programmi @command{awk} sono frequentemente usati per elaborare file di
+registro [file con estensione .log], che contengono l'informazione sulla data e
+l'ora (marcatura temporale) in cui un particolare record @`e stato registrato sul log.
+Molti programmi registrano questa informazione nel formato restituito
+dalla chiamata di sistema @code{time()}, la quale misura il numero di secondi
+trascorsi a partire da una certa data iniziale (Epoca). Nei sistemi aderenti
+allo standard POSIX, questo @`e il numero di secondi a partire dal primo gennaio
+1970, ora di Greenwich (1970-01-01 00:00:00 UTC), senza includere i secondi
+@ifclear FOR_PRINT
+@iftex
+intercalari.@footnote{@xrefIl{Glossario},
+@end iftex
+@ifnottex
+intercalari.@footnote{@xref{Glossario},
+@end ifnottex
+in particolare le voci ``Epoca'' e ``UTC.''}
+@end ifclear
+@ifset FOR_PRINT
+intercalari.
+@end ifset
+Tutti i sistemi noti aderenti allo standard POSIX gestiscono le marcature
+temporali da 0 fino a
+@iftex
+@math{2^{31} - 1},
+@end iftex
+@ifinfo
+2^31 - 1,
+@end ifinfo
+@ifnottex
+@ifnotinfo
+2@sup{31} @minus{} 1,
+@end ifnotinfo
+@end ifnottex
+il che @`e sufficiente per rappresentare date e ore fino a inizio 2038
+(2038-01-19 03:14:07 UTC). Molti sistemi supportano una maggiore estensione
+di date, compresi dei valori negativi per rappresentare delle date
+anteriori all'Epoca.
+
+@cindex @command{date}, programma di utilit@`a GNU
+@cindex programma di utilit@`a @command{date} GNU
+@cindex tempo, ottenerlo
+Per facilitare l'elaborazione di tali file di registro, e per produrre
+dei rapporti utili, @command{gawk} prevede le seguenti funzioni per
+lavorare con le marcature temporali. Si tratta di estensioni @command{gawk};
+non sono previste nello standard POSIX.@footnote{Il comando di utilit@`a GNU
+@command{date} pu@`o fare anche molte delle cose qui descritte. Pu@`o essere
+preferibile usarlo per semplici operazioni relative a data e ora in semplici
+script della shell.} Tuttavia, anche versioni recenti di @command{mawk}
+(@pxref{Altre versioni}) prevedono queste funzioni. I parametri facoltativi
+sono racchiusi tra parentesi quadre ([ ]):
+
+@c @asis for docbook
+@table @asis
+@item @code{mktime(@var{specifiche_data}} [@code{, @var{utc-flag}} ]@code{)}
+@cindexgawkfunc{mktime}
+@cindex generare data e ora
+Trasforma @var{specifiche_data} in una marcatura temporale nello stesso formato
+restituito da @code{systime()}. @`E simile alla funzione omonima
+in ISO C. L'argomento, @var{specifiche_data}, @`e una stringa della forma
+@w{@code{"@var{AAAA} @var{MM} @var{GG} @var{HH} @var{MM} @var{SS} [@var{DST}]"}}.
+La stringa consiste di sei o sette numeri che rappresentano,
+rispettivamente,
+l'anno in quattro cifre, il mese da 1 a 12, il giorno del mese
+da 1 a 31, l'ora del giorno da 0 a 23, il minuto da 0 a
+59, il secondo da 0 a 60,@footnote{Occasionalmente ci sono dei
+minuti in un anno con un secondo intercalare, il che spiega perch@'e i
+secondi possono arrivare fino a 60.}
+e un'indicazione opzionale relativa all'ora legale.
+
+I valori di questi numeri possono non essere negli intervalli specificati; per
+esempio, un'ora di @minus{}1 sta a indicare 1 ora prima di mezzanotte.
+Viene adottato il calendario gregoriano con l'origine posta all'anno zero,
+con l'anno 0 che viene prima dell'anno 1 e l'anno @minus{}1 che viene prima
+dell'anno 0. Se il flag @var{utc-flag} @`e specificato ed @`e diverso da zero
+e dalla stringa nulla, si suppone che l'ora sia quella del fuso orario UTC;
+altrimenti l'ora @`e considerata essere quella del fuso orario locale. Se
+l'indicatore dell'ora legale @`e positivo, si presuppone che l'ora sia quella
+legale; se @`e 0, l'ora considerata @`e quella di Greenwich (standard time); se
+invece @`e negativo (questo @`e il default), @code{mktime()} tenta di
+determinare se @`e in vigore l'ora legale o no, nel momento specificato.
+
+Se @var{specifiche_data} non contiene elementi in numero sufficiente, o se
+la data e ora risultante sono fuori dall'intervallo previsto,
+@code{mktime()} restituisce @minus{}1.
+
+@cindex @command{gawk}, vettore @code{PROCINFO} in
+@cindex @code{PROCINFO}, vettore
+@cindex vettore @code{PROCINFO}
+@item @code{strftime(}[@var{formato} [@code{,} @var{data_e_ora} [@code{,} @var{utc}] ] ]@code{)}
+@cindexgawkfunc{strftime}
+@cindex formato stringa marcature temporali
+@cindex formato stringa data e ora
+@cindex data e ora, formato stringa
+@cindex marcature temporali, formato stringa
+Formatta la data e ora specificata da @var{data_e_ora} in base alle indicazioni
+contenute nella stringa @var{formato} e restituisce il risultato.
+@`E simile alla funzione omonima in ISO C.
+Se @var{utc} @`e presente ed @`e diverso da zero o dalla stringa nulla,
+il valore @`e formattato come UTC (Tempo Coordinato Universale,
+gi@`a noto come GMT o Tempo Medio di Greenwich).
+Altrimenti, il valore @`e formattato per il fuso orario locale.
+La stringa @var{data_e_ora} @`e nello stesso formato del valore restituito
+dalla funzione @code{systime()}. Se non si specifica l'argomento
+@var{data_e_ora}, @command{gawk} usa l'ora del giorno corrente per la
+formattazione.
+Omettendo l'argomento @var{formato}, @code{strftime()} usa
+il valore di @code{PROCINFO["strftime"]} come stringa di formattazione
+(@pxref{Variabili predefinite}).
+Il valore di default della stringa @`e
+@code{@w{"%a %b %e %H:%M:%S %Z %Y"}}. Questa stringa di formattazione
+produce lo stesso output del programma di utilit@`a equivalente
+@command{date}.
+Si pu@`o assegnare un nuovo valore a @code{PROCINFO["strftime"]} per
+modificare la formattazione di default; si veda
+la lista che segue per le varie direttive di formattazione.
+
+@item @code{systime()}
+@cindexgawkfunc{systime}
+@cindex marcature temporali
+@cindex data e ora, si veda marcature temporali
+@cindex data e ora corrente del sistema
+Restituisce l'ora corrente come numero di secondi a partire dall'Epoca
+del sistema. Sui sistemi aderenti allo standard POSIX, questo @`e il numero
+di secondi trascorsi a partire dal primo gennaio 1970, ora di Greenwich
+(1970-01-01 00:00:00 UTC), senza includere i secondi intercalari.
+@end table
+
+La funzione @code{systime()} consente di confrontare una marcatura temporale
+in un file di registro con la data e ora correnti. In particolare, @`e facile
+determinare quanto tempo prima un particolare record @`e stato registrato.
+@`E anche possibile produrre record di registro usando il formato
+``secondi a partire dall'Epoca''.
+
+@cindex conversione di date in marcature temporali
+@cindex date, conversione in marcature temporali
+@cindex marcature temporali, conversione date nelle
+La funzione @code{mktime()} consente di convertire una rappresentazione in
+forma testuale di una data e ora in una marcatura temporale.
+Questo semplifica i confronti prima/dopo tra differenti date e ore, in
+particolare quando si abbia a che fare con date e ore provenienti da una
+fonte esterna, come un file di registro.
+
+La funzione @code{strftime()} permette di trasformare facilmente una marcatura
+temporale in un'informazione intelligibile. @`E analoga come tipo alla funzione
+@code{sprintf()} (@pxref{Funzioni per stringhe}), nel senso che copia
+letteralmente ci@`o che non @`e una specifica di formato nella stringa che viene
+restituita, mentre sostituisce i valori di data e ora a seconda delle
+specifiche di formato contenute nella stringa @var{formato}.
+
+@cindex specificatori di formato, funzione @code{strftime()} di (@command{gawk})
+@cindex formato, specificatori di, funzione @code{strftime()} di (@command{gawk})
+Per @code{strftime()} lo standard
+1999 ISO C@footnote{Sfortunatamente,
+non tutte le funzioni @code{strftime()} dei vari sistemi operativi
+ammettono tutte le conversioni qui elencate.}
+consente le seguenti specifiche di formattazione delle date:
+
+@table @code
+@item %a
+Il nome abbreviato del giorno della settimana nella lingua locale.
+
+@item %A
+Il nome completo del giorno della settimana nella lingua locale.
+
+@item %b
+Il nome abbreviato del mese dell'anno nella lingua locale.
+
+@item %B
+Il nome completo del mese dell'anno nella lingua locale.
+
+@item %c
+Il formato ``appropriato'' della rappresentazione della data e ora
+nella lingua locale.
+(Questo @`e @samp{%A %B %d %T %Y} per la localizzazione @code{"C"}.)
+
+@item %C
+La parte che designa il secolo nell'anno corrente.
+Si ottiene dividendo per 100 l'anno, e
+troncando verso il basso
+all'intero pi@`u vicino.
+
+@item %d
+Il giorno del mese come numero decimale (01--31).
+
+@item %D
+Equivale a specificare @samp{%m/%d/%y}.
+
+@item %e
+Il giorno del mese, preceduto da uno spazio se di tratta di una cifra sola.
+
+@item %F
+Equivale a specificare @samp{%Y-%m-%d}.
+Questo @`e il formato ISO 8601 della data.
+
+@item %g
+L'anno (ultime due cifre) ricavato prendendo il resto della divisione per 100
+dell'anno a cui appartiene la settimana, secondo ISO 8601, come numero decimale
+(00--99). Per esempio, il primo gennaio 2012, fa parte della settimana 53 del
+2011. Quindi, l'anno relativo al numero di settimana ISO di quella data @`e 2011
+(ossia 11), anche se la data in s@'e @`e nel 2012. Analogamente, il 31 dicembre
+2012, @`e nella prima settimana del 2013. Quindi, l'anno relativo al numero di
+settimana ISO di quella data @`e 2013 (ossia 13), anche se la data in s@'e @`e nel
+2012.
+
+@item %G
+L'anno intero relativo al numero di settimana ISO, come numero decimale.
+
+@item %h
+Equivalente a @samp{%b}.
+
+@item %H
+L'ora (in un orologio a 24 ore) come numero decimale (00--23).
+
+@item %I
+L'ora (in un orologio a 12 ore) come numero decimale (01--12).
+
+@item %j
+Il giorno dell'anno come numero decimale (001--366).
+
+@item %m
+Il mese come numero decimale (01--12).
+
+@item %M
+Il minuto come numero decimale (00--59).
+
+@item %n
+Un carattere di ritorno a capo (ASCII LF).
+
+@item %p
+L'equivalente nella lingua locale delle designazioni AM/PM
+(mattino/pomerigggio) associate a un orologio a 12 ore.
+
+@item %r
+L'ora locale nel formato a 12 ore.
+(Questo @`e @samp{%I:%M:%S %p} nella localizzazione @code{"C"}.)
+
+@item %R
+Equivalente a specificare @samp{%H:%M}.
+
+@item %S
+Il secondo come numero decimale (00--60).
+
+@item %t
+Un carattere di tabulazione [TAB].
+
+@item %T
+Equivalente a specificare @samp{%H:%M:%S}.
+
+@item %u
+Il numero del giorno della settimana come numero decimale (1--7).
+Luned@`{@dotless{i}} @`e il giorno numero 1.
+
+@item %U
+Il numero di settimana dell'anno (con la prima domenica dell'anno presa
+come primo giorno della prima settimana) come numero decimale (00--53).
+
+@c @cindex ISO 8601
+@item %V
+Il numero di settimana dell'anno (con il primo luned@`{@dotless{i}} dell'anno preso
+come primo giorno della prima settimana) come numero decimale (01--53).
+Il metodo per determinare il numero di settimana @`e quello specificato
+dallo standard ISO 8601.
+(In pratica: se la settimana che contiene il primo gennaio ha quattro o
+pi@`u giorni nel nuovo anno, allora
+@`e la settimana numero uno; altrimenti @`e l'ultima settimana
+[52 o 53] dell'anno
+precedente, e la settimana successiva @`e la settimana numero uno.)
+
+@item %w
+Il giorno della settimana come numero decimale (0--6).
+Domenica @`e il giorno zero.
+
+@item %W
+Il numero di settimana dell'anno (con il primo luned@`{@dotless{i}} come primo giorno
+della settimana numero uno)
+come numero decimale (00--53).
+
+@item %x
+Il formato ``appropriato'' della rappresentazione della data
+nella lingua locale.
+(Questo @`e @samp{%A %B %d %Y} nella localizzazione @code{"C"}.)
+
+@item %X
+Il formato ``appropriato'' della rappresentazione della data.
+(Questo @`e @samp{%T} nella localizzazione @code{"C"}.)
+
+@item %y
+L'anno modulo 100 (le ultime due cifre) come numero decimale (00--99).
+
+@item %Y
+L'anno come numero decimale (p.es., 2015).
+
+@c @cindex RFC 822
+@c @cindex RFC 1036
+@item %z
+La differenza di fuso orario [rispetto all'ora di Greenwich] in formato
+@samp{+@var{OOMM}} (p.es., il
+formato necessario per produrre intestazioni di data conformi agli standard
+RFC 822/RFC 1036).
+
+@item %Z
+Il nome o l'abbreviazione della zona di fuso orario (@dfn{time zone}); se il fuso
+orario non @`e determinabile, @`e impostata alla stringa nulla.
+
+@item %Ec %EC %Ex %EX %Ey %EY %Od %Oe %OH
+@itemx %OI %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy
+``notazioni alternative'' di specifica
+in cui solo la seconda lettera (@samp{%c}, @samp{%C} e cos@`{@dotless{i}} via) @`e
+significativa.@footnote{Se questo risulta incomprensibile, non @`e il
+caso di preoccuparsi; queste notazioni hanno lo scopo di facilitare
+la ``internazionalizzazione'' dei programmi.
+Altre funzionalit@`a di internazionalizzazione sono descritte in
+@ref{Internazionalizzazione}.}
+(Queste facilitano la compatibilit@`a con il programma di utilit@`a
+POSIX @command{date}.)
+
+@item %%
+Un singolo carattere @samp{%}.
+@end table
+
+Se uno specificatore di conversione non @`e tra quelli elencati sopra, il
+comportamento @`e indefinito.@footnote{Questo @`e perch@'e ISO C lascia
+indefinito il comportamento della versione C di @code{strftime()} e
+@command{gawk} usa la versione di sistema di @code{strftime()},
+se disponibile.
+Tipicamente, lo specificatore di conversione "non previsto" non appare
+nella stringa risultante, o appare cos@`{@dotless{i}} come @`e scritto.}
+
+Per sistemi che non aderiscono completamente agli standard
+@command{gawk} utilizza una copia di
+@code{strftime()} dalla libreria C di GNU.
+Sono disponibili tutte le specifiche di formato sopra elencate.
+Se la detta versione @`e
+usata per compilare @command{gawk} (@pxref{Installazione}),
+sono disponibili anche le seguenti ulteriori specifiche di formato:
+
+@table @code
+@item %k
+L'ora (in un orologio a 24 ore) come numero decimale (0--23).
+I numeri di una sola cifra sono preceduti da uno spazio bianco.
+
+@item %l
+L'ora (in un orologio a 12 ore) come numero decimale (1--12).
+I numeri di una sola cifra sono preceduti da uno spazio bianco.
+
+@ignore
+@item %N
+Il nome dell'``Imperatore/Era''.
+Equivalente a @samp{%C}.
+
+@item %o
+L'anno dell'``Imperatore/Era''.
+Equivalente a @samp{%y}.
+@end ignore
+
+@item %s
+L'ora espressa in numero di secondi a partire dall'Epoca.
+
+@ignore
+@item %v
+La data in formato VMS (p.es., @samp{20-JUN-1991}).
+@end ignore
+@end table
+
+In aggiunta a ci@`o, le notazioni alternative sono riconosciute, ma al
+loro posto sono usate quelle normali.
+
+@cindex @code{date}, programma di utilit@`a POSIX
+@cindex programma di utilit@`a POSIX @code{date}
+@cindex POSIX @command{awk}, programma di utilit@`a @code{date} e
+Il seguente esempio @`e un'implementazione @command{awk} del
+programma di utilit@`a POSIX @command{date}.
+Normalmente, il programma di utilit@`a @command{date} stampa la
+data e l'ora corrente nel formato ben noto. Tuttavia, se si
+specifica al comando un argomento che inizia con un @samp{+}, @command{date}
+copia i caratteri che non sono specifiche di formato nello standard output
+e interpreta l'ora corrente secondo gli specificatori di formato
+contenuti nella stringa. Per esempio:
+
+@example
+$ @kbd{date '+Oggi @`e %A, %d %B %Y.'}
+@print{} Oggi @`e luned@`{@dotless{i}}, 22 settembre 2014.
+@end example
+
+Ecco la versione @command{gawk} del programma di utilit@`a @command{date}.
+@`E all'interno di uno script di shell per gestire l'opzione @option{-u},
+che richiede che @command{date} sia eseguito come se il fuso orario
+fosse impostato a UTC:
+
+@example
+#! /bin/sh
+#
+# date --- simula il comando POSIX 'date'
+
+case $1 in
+-u) TZ=UTC0 # usare UTC
+ export TZ
+ shift ;;
+esac
+
+gawk 'BEGIN @{
+ formato = PROCINFO["strftime"]
+ codice_di_ritorno = 0
+
+ if (ARGC > 2)
+ codice_di_ritorno = 1
+ else if (ARGC == 2) @{
+ formato = ARGV[1]
+ if (formato ~ /^\+/)
+ formato = substr(formato, 2) # togli il + iniziale
+ @}
+ print strftime(formato)
+ exit codice_di_ritorno
+@}' "$@@"
+@end example
+
+@node Funzioni a livello di bit
+@subsection Funzioni per operazioni di manipolazione bit
+@cindex bit, funzioni per la manipolazione di
+@cindex manipolazione di bit, funzioni per la
+@cindex funzioni per la manipolazione di bit
+@cindex bit, operazioni sui
+@cindex AND, operazione sui bit
+@cindex OR, operazione sui bit
+@cindex XOR, operazione sui bit
+@cindex operazioni sui bit
+@quotation
+@i{Io posso spiegarlo per te, ma non posso capirlo per te.}
+@author Anonimo
+@end quotation
+
+Molti linguaggi consentono di eseguire operazioni @dfn{bit a bit}
+su due numeri interi. In altre parole, l'operazione @`e eseguita
+su ogni successiva coppia di bit presi da ognuno dei due operandi.
+Tre operazioni comuni sono AND, OR e XOR bit a bit.
+Queste operazioni sono descritte nella @ref{table-bitwise-ops}.
+
+@c 11/2014: Postprocessing turns the docbook informaltable
+@c into a table. Hurray for scripting!
+@float Tabella,table-bitwise-ops
+@caption{Operazioni a livello di bit}
+@ifnottex
+@ifnotdocbook
+@display
+@verbatim
+ Operatore booleano
+ | AND | OR | XOR
+ |---+---+---+---+---+---
+Operandi | 0 | 1 | 0 | 1 | 0 | 1
+----------+---+---+---+---+---+---
+ 0 | 0 0 | 0 1 | 0 1
+ 1 | 0 1 | 1 1 | 1 0
+@end verbatim
+@end display
+@end ifnotdocbook
+@end ifnottex
+@tex
+\centerline{
+\vbox{\bigskip % space above the table (about 1 linespace)
+% Because we have vertical rules, we can't let TeX insert interline space
+% in its usual way.
+\offinterlineskip
+\halign{\strut\hfil#\quad\hfil % operands
+ &\vrule#&\quad#\quad % rule, 0 (of and)
+ &\vrule#&\quad#\quad % rule, 1 (of and)
+ &\vrule# % rule between and and or
+ &\quad#\quad % 0 (of or)
+ &\vrule#&\quad#\quad % rule, 1 (of of)
+ &\vrule# % rule between or and xor
+ &\quad#\quad % 0 of xor
+ &\vrule#&\quad#\quad % rule, 1 of xor
+ \cr
+&\omit&\multispan{11}\hfil\bf Operatore booleano\hfil\cr
+\noalign{\smallskip}
+& &\multispan3\hfil AND\hfil&&\multispan3\hfil OR\hfil
+ &&\multispan3\hfil XOR\hfil\cr
+\bf Operandi&&0&&1&&0&&1&&0&&1\cr
+\noalign{\hrule}
+\omit&height 2pt&&\omit&&&&\omit&&&&\omit\cr
+\noalign{\hrule height0pt}% without this the rule does not extend; why?
+0&&0&\omit&0&&0&\omit&1&&0&\omit&1\cr
+1&&0&\omit&1&&1&\omit&1&&1&\omit&0\cr
+}}}
+@end tex
+
+@docbook
+<informaltable>
+
+<tgroup cols="7" colsep="1">
+<colspec colname="c1"/>
+<colspec colname="c2"/>
+<colspec colname="c3"/>
+<colspec colname="c4"/>
+<colspec colname="c5"/>
+<colspec colname="c6"/>
+<colspec colname="c7"/>
+<spanspec spanname="optitle" namest="c2" nameend="c7" align="center"/>
+<spanspec spanname="andspan" namest="c2" nameend="c3" align="center"/>
+<spanspec spanname="orspan" namest="c4" nameend="c5" align="center"/>
+<spanspec spanname="xorspan" namest="c6" nameend="c7" align="center"/>
+
+<tbody>
+<row>
+<entry colsep="0"></entry>
+<entry spanname="optitle"><emphasis role="bold">Operatore booleano</emphasis></entry>
+</row>
+
+<row rowsep="1">
+<entry rowsep="0"></entry>
+<entry spanname="andspan">AND</entry>
+<entry spanname="orspan">OR</entry>
+<entry spanname="xorspan">XOR</entry>
+</row>
+
+<row rowsep="1">
+<entry ><emphasis role="bold">Operandi</emphasis></entry>
+<entry colsep="0">0</entry>
+<entry colsep="1">1</entry>
+<entry colsep="0">0</entry>
+<entry colsep="1">1</entry>
+<entry colsep="0">0</entry>
+<entry colsep="1">1</entry>
+</row>
+
+<row>
+<entry align="center">0</entry>
+<entry colsep="0">0</entry>
+<entry>0</entry>
+<entry colsep="0">0</entry>
+<entry>1</entry>
+<entry colsep="0">0</entry>
+<entry>1</entry>
+</row>
+
+<row>
+<entry align="center">1</entry>
+<entry colsep="0">0</entry>
+<entry>1</entry>
+<entry colsep="0">1</entry>
+<entry>1</entry>
+<entry colsep="0">1</entry>
+<entry>0</entry>
+</row>
+
+</tbody>
+</tgroup>
+</informaltable>
+@end docbook
+@end float
+
+@cindex bit, complemento a livello di
+@cindex complemento a livello di bit
+Come si vede, il risultato di un'operazione di AND @`e 1 solo quando
+@emph{entrambi} i bit sono 1.
+Il risultato di un'operazione di OR @`e 1 se @emph{almeno un} bit @`e 1.
+Il risultato di un'operazione di XOR @`e 1 se l'uno o l'altro
+bit @`e 1, ma non tutti e due.
+La successiva operazione @`e il @dfn{complemento}; il complemento di 1 @`e 0 e
+il complemento di 0 @`e 1. Quindi, quest'operazione ``inverte'' tutti i bit
+di un dato valore.
+
+@cindex bit, spostamento di
+@cindex spostamento a sinistra, bit a bit
+@cindex spostamento a destra, bit a bit
+@cindex spostamento, bit a bit
+Infine, due altre operazioni comuni consistono nello spostare i bit
+a sinistra o a destra.
+Per esempio, se si ha una stringa di bit @samp{10111001} e la si sposta
+a destra di tre bit, si ottiene @samp{00010111}.@footnote{Questo esempio
+presuppone che degli zeri riempiano le posizioni a sinistra.
+Per @command{gawk}, @`e sempre
+cos@`{@dotless{i}}, ma in alcuni linguaggi @`e possibile che le posizioni a sinistra
+siano riempite con degli uno.}
+Partendo nuovamente da @samp{10111001} e spostandolo a sinistra di tre
+bit, si ottiene @samp{11001000}. La lista seguente descrive
+le funzioni predefinite di @command{gawk} che rendono disponibili
+le operazioni a livello di bit.
+I parametri facoltativi sono racchiusi tra parentesi quadre ([ ]):
+
+@cindex @command{gawk}, operazioni a livello di bit in
+@table @code
+@cindexgawkfunc{and}
+@cindex AND, operazione sui bit
+@item @code{and(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)}
+Restituisce l'AND bit a bit degli argomenti.
+Gli argomenti devono essere almeno due.
+
+@cindexgawkfunc{compl}
+@cindex complemento a livello di bit
+@item @code{compl(@var{val})}
+Restituisce il complemento bit a bit di @var{val}.
+
+@cindexgawkfunc{lshift}
+@cindex spostamento a sinistra
+@item @code{lshift(@var{val}, @var{contatore})}
+Restituisce il valore di @var{val}, spostato a sinistra di
+@var{contatore} bit.
+
+@cindexgawkfunc{or}
+@cindex OR, operazione sui bit
+@item @code{or(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)}
+Restituisce l'OR bit a bit degli argomenti.
+Gli argomenti devono essere almeno due.
+
+@cindexgawkfunc{rshift}
+@cindex spostamento a destra
+@item @code{rshift(@var{val}, @var{contatore})}
+Restituisce il valore di @var{val}, spostato a destra
+di @var{contatore} bit.
+
+@cindexgawkfunc{xor}
+@cindex XOR, operazione sui bit
+@item @code{xor(}@var{v1}@code{,} @var{v2} [@code{,} @dots{}]@code{)}
+Restituisce il XOR bit a bit degli argomenti.
+Gli argomenti devono essere almeno due.
+@end table
+
+@quotation ATTENZIONE
+A partire dalla versione di @command{gawk} @value{PVERSION} 4.2, gli operandi
+negativi non sono consentiti per nessuna di queste funzioni. Un operando
+negativo produce un errore fatale. Si veda la nota a lato
+``Attenzione. Non @`e tutto oro quel che luccica!'' per maggiori informazioni sul perch@'e.
+@end quotation
+
+Ecco una funzione definita dall'utente (@pxref{Funzioni definite dall'utente})
+che illustra l'uso di queste funzioni:
+
+@cindex @code{bits2str()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{bits2str()}
+@cindex @code{testbits.awk}, programma
+@cindex programma @code{testbits.awk}
+@example
+@group
+@c file eg/lib/bits2str.awk
+# bits2str --- decodifica un byte in una serie di 0/1 leggibili
+
+function bits2str(byte, dati, maschera)
+@{
+ if (byte == 0)
+ return "0"
+
+ maschera = 1
+ for (; byte != 0; stringa = rshift(stringa, 1))
+ dati = (and(byte, maschera) ? "1" : "0") dati
+
+ while ((length(dati) % 8) != 0)
+ dati = "0" dati
+
+ return dati
+@}
+@c endfile
+@end group
+
+@c this is a hack to make testbits.awk self-contained
+@ignore
+@c file eg/prog/testbits.awk
+# bits2str --- turn a byte into readable 1's and 0's
+
+function bits2str(bits, data, mask)
+@{
+ if (bits == 0)
+ return "0"
+
+ mask = 1
+ for (; bits != 0; bits = rshift(bits, 1))
+ data = (and(bits, mask) ? "1" : "0") data
+
+ while ((length(data) % 8) != 0)
+ data = "0" data
+
+ return data
+@}
+@c endfile
+@end ignore
+@c file eg/prog/testbits.awk
+BEGIN @{
+ printf "123 = %s\n", bits2str(123)
+ printf "0123 = %s\n", bits2str(0123)
+ printf "0x99 = %s\n", bits2str(0x99)
+ comp = compl(0x99)
+ printf "compl(0x99) = %#x = %s\n", comp, bits2str(comp)
+ shift = lshift(0x99, 2)
+ printf "lshift(0x99, 2) = %#x = %s\n", shift, bits2str(shift)
+ shift = rshift(0x99, 2)
+ printf "rshift(0x99, 2) = %#x = %s\n", shift, bits2str(shift)
+@}
+@c endfile
+@end example
+
+@noindent
+Questo programma produce il seguente output quando viene eseguito:
+
+@example
+$ @kbd{gawk -f testbits.awk}
+@print{} 123 = 01111011
+@print{} 0123 = 01010011
+@print{} 0x99 = 10011001
+@print{} compl(0x99) = 0x3fffffffffff66 = 001111111111111111111111111111111
+@print{} 11111111111111101100110
+@print{} lshift(0x99, 2) = 0x264 = 0000001001100100
+@print{} rshift(0x99, 2) = 0x26 = 00100110
+@end example
+
+@cindex conversione da stringhe a numeri
+@cindex stringhe, conversione
+@cindex numeri, conversione in stringhe
+@cindex conversione da numeri a stringhe
+@cindex numero visto come stringa di bit
+La funzione @code{bits2str()} trasforma un numero binario in una stringa.
+Inizializzando @code{maschera} a uno otteniamo
+un valore binario in cui il bit pi@`u a destra @`e impostato a
+uno. Usando questa maschera,
+la funzione continua a controllare il bit pi@`u a destra.
+l'operazione di AND tra la maschera e il valore indica se il
+bit pi@`u a destra @`e uno oppure no. Se questo @`e il caso, un @code{"1"}
+@`e concatenato all'inizio della stringa.
+Altrimenti, @`e concatenato uno @code{"0"}.
+Il valore @`e quindi spostato a destra di un bit e il ciclo continua
+finch@'e non ci sono pi@`u bit.
+
+Se il valore iniziale @`e zero, viene restituito semplicemente uno @code{"0"}.
+Altrimenti, alla fine, al valore ottenuto vengono aggiunti degli zeri a
+sinistra, per arrivare a stringhe
+di lunghezza multipla di 8, ossia contenenti un numero intero di byte.
+Questo @`e tipico dei computer moderni.
+
+Il codice principale nella regola @code{BEGIN} mostra la differenza tra
+i valori decimale e ottale dello stesso numero.
+(@pxref{Numeri non-decimali}),
+e poi mostra i risultati delle funzioni
+@code{compl()}, @code{lshift()} e @code{rshift()}.
+
+@sidebar Attenzione. Non @`e tutto oro quel che luccica!
+
+In altri linguaggi, le operazioni "bit a bit" sono eseguite su valori interi,
+non su valori a virgola mobile. Come regola generale, tali operazioni
+funzionano meglio se eseguite su interi senza segno.
+
+@command{gawk} tenta di trattare gli argomenti delle funzioni
+"bit a bit" come interi senza segno. Per questo motivo, gli argomenti negativi
+provocano un errore fatale.
+
+In una normale operazione, per tutte queste funzioni, prima il valore a virgola
+mobile a doppia precisione viene convertito nel tipo intero senza segno di C
+pi@`u ampio, poi viene eseguita l'operazione "bit a bit". Se il risultato non
+pu@`o essere rappresentato esattamente come un tipo @code{double} di C,
+vengono rimossi i bit iniziali diversi da zero uno alla volta finch@'e
+non sono rappresentati esattamente. Il risultato @`e poi nuovamente convertito
+in un tipo @code{double} di C.@footnote{Per essere pi@`u chiari,
+la conseguenza @`e che @command{gawk} pu@`o memorizzare solo un determinato
+intervallo di valori interi; i numeri al di fuori di questo intervallo vengono
+ridotti per rientrare all'interno dell'intervallo.}
+
+Comunque, quando si usa il calcolo con precisione arbitraria con l'opzione
+@option{-M} (@pxref{Calcolo con precisione arbitraria}), il risultato pu@`o
+essere diverso. Questo @`e particolarmente evidente con la funzione @code{compl()}:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print compl(42) @}'}
+@print{} 9007199254740949
+$ @kbd{gawk -M 'BEGIN @{ print compl(42) @}'}
+@print{} -43
+@end example
+
+Quel che avviene diventa chiaro quando si stampano i risultati
+in notazione esadecimale:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0x1fffffffffffd5
+$ @kbd{gawk -M 'BEGIN @{ printf "%#x\n", compl(42) @}'}
+@print{} 0xffffffffffffffd5
+@end example
+
+Quando si usa l'opzione @option{-M}, nel dettaglio, @command{gawk} usa
+gli interi a precisione arbitraria di GNU MP che hanno almeno 64 bit di precisione.
+Quando non si usa l'opzione @option{-M}, @command{gawk} memorizza i valori
+interi come regolari valori a virgola mobile con doppia precisione, che
+mantengono solo 53 bit di precisione. Inoltre, la libreria GNU MP tratta
+(o almeno sembra che tratti) il bit iniziale come un bit con segno; cos@`i il
+risultato con @option{-M} in questo caso @`e un numero negativo.
+
+In breve, usare @command{gawk} per qualsiasi tipo di operazione "bit a bit",
+tranne le pi@`u semplici, probabilmente @`e una cattiva idea; caveat emptor!
+
+@end sidebar
+
+@node Funzioni per i tipi
+@subsection Funzioni per conoscere il tipo di una variabile
+
+@command{gawk} prevede due funzioni che permettono di conoscere
+il tipo di una variabile.
+Questo @`e necessario per scrivere del codice che visiti ogni elemento di un
+vettore di vettori
+(@pxref{Vettori di vettori}) e in altri contesti.
+
+@table @code
+@cindexgawkfunc{isarray}
+@cindex scalare o vettore
+@item isarray(@var{x})
+Restituisce il valore 'vero' se @var{x} @`e un vettore. Altrimenti, restituisce
+'falso'.
+
+@cindexgawkfunc{typeof}
+@cindex variabile, tipo di una
+@cindex tipo di una variabile
+@item typeof(@var{x})
+Restituisce una delle stringhe seguenti, a seconda del tipo di @var{x}:
+
+@c nested table
+@table @code
+@item "array"
+@var{x} @`e un vettore.
+
+@item "regexp"
+@var{x} @`e una @dfn{regexp} fortemente tipizzata
+(@pxref{Costanti @dfn{regexp} forti}).
+
+@item "number"
+@var{x} @`e un numero.
+
+@item "string"
+@var{x} @`e una stringa.
+
+@item "strnum"
+@var{x} @`e un numero che ha avuto origine da un input dell'utente,
+come un campo o il risultato di una chiamata a @code{split()}.
+(Cio@`e, @var{x} ha l'attributo @dfn{strnum};
+@pxref{Tipi di variabile}.)
+
+@item "unassigned"
+@var{x} @`e una variabile scalare a cui non @`e ancora stato assegnato un valore.
+Per esempio:
+
+@example
+BEGIN @{
+ # crea a[1] ma non gli attribuisce alcun valore
+ a[1]
+ print typeof(a[1]) # unassigned
+@}
+@end example
+
+@item "untyped"
+@var{x} non @`e stata usata per nulla; pu@`o diventare uno scalare o un
+vettore.
+Per esempio:
+
+@example
+BEGIN @{
+ print typeof(x) # x non @`e mai stato usato --> untyped
+ mk_arr(x)
+ print typeof(x) # x ora @`e un vettore --> array
+@}
+
+function mk_arr(a) @{ a[1] = 1 @}
+@end example
+
+@end table
+@end table
+
+@code{isarray()} torna utile in due occasioni. La prima @`e quando
+si visita un vettore multidimensionale: si pu@`o stabilire se un elemento @`e
+un vettore oppure no. La seconda @`e all'interno del corpo di una funzione
+definita dall'utente (argomento non ancora trattato;
+@pxref{Funzioni definite dall'utente}), per determinare se un parametro
+@`e un vettore oppure no.
+
+@quotation NOTA
+Usare @code{isarray()} a livello globale per controllare le variabili
+non ha alcun senso. Si suppone infatti che chi scrive il programma
+sappia se una variabile @`e un vettore oppure no. E in
+effetti, per come funziona @command{gawk}, se si passa una variabile
+che non sia stata usata in precedenza a @code{isarray()}, @command{gawk}
+la crea al volo, assegnandole il tipo scalare.
+@end quotation
+
+La funzione @code{typeof()} @`e generale; consente di determinare
+se una variabile o un parametro di funzione @`e uno scalare, un vettore,
+o una @dfn{regexp} fortemente tipizzata.
+
+L'uso di @code{isarray()} @`e deprecato; si dovrebbe usare @code{typeof()}
+al suo posto. Si dovrebbe sostituire ogni uso esistente di
+@samp{isarray(var)} nei programmi esistenti con
+@samp{typeof(var) == "array"}.
+
+@node Funzioni di internazionalizzazione
+@subsection Funzioni per tradurre stringhe
+@cindex @command{gawk}, funzioni di traduzione di stringhe
+@cindex funzioni di traduzione di stringhe
+@cindex traduzione di stringhe, funzioni di
+@cindex internazionalizzazione
+@cindex programmi @command{awk}, internazionalizzare
+
+@command{gawk} prevede strumenti per internazionalizzare i programmi
+@command{awk}.
+Questi sono costituiti dalle funzioni descritte nella lista seguente.
+Le descrizioni sono volutamente concise.
+@xref{Internazionalizzazione},
+per un'esposizione completa.
+I parametri facoltativi sono racchiusi tra parentesi quadre ([ ]):
+
+@table @asis
+@cindexgawkfunc{bindtextdomain}
+@cindex impostare directory con catalogo messaggi tradotti
+@cindex messaggi tradotti, impostare directory con catalogo
+@item @code{bindtextdomain(@var{directory}} [@code{,} @var{dominio}]@code{)}
+Imposta la directory in cui
+@command{gawk} trova i file di traduzione dei messaggi, nel caso in cui
+non siano o non possano essere messi nelle directory ``standard''
+(p.es., durante la fase di test di un programma).
+Restituisce la directory alla quale @var{dominio} @`e ``connesso.''
+
+Il default per @var{dominio} @`e il valore di @code{TEXTDOMAIN}.
+Se @var{directory} @`e la stringa nulla (@code{""}),
+@code{bindtextdomain()} restituisce la connessione corrente per il
+@var{dominio} dato.
+
+@cindexgawkfunc{dcgettext}
+@cindex traduzione di stringhe
+@item @code{dcgettext(@var{stringa}} [@code{,} @var{dominio} [@code{,} @var{categoria}] ]@code{)}
+Restituisce la traduzione di @var{stringa} nel
+dominio linguistico @var{dominio} per la categoria di localizzazione
+@var{categoria}.
+Il valore di default per @var{dominio} @`e il valore corrente di @code{TEXTDOMAIN}.
+Il valore di default per @var{categoria} @`e @code{"LC_MESSAGES"}.
+
+@cindexgawkfunc{dcngettext}
+@item @code{dcngettext(@var{stringa1}, @var{stringa2}, @var{numero}} [@code{,} @var{dominio} [@code{,} @var{categoria}] ]@code{)}
+Restituisce la forma plurale usata per @var{numero} nella
+traduzione di @var{stringa1} e @var{stringa2} nel dominio di testo
+@var{dominio} per la categoria di localizzazione @var{categoria}.
+@var{stringa1} @`e la variante al singolare in inglese di un messaggio e
+@var{stringa2} @`e la variante al plurare in inglese dello stesso messaggio.
+Il valore di default per @var{dominio} @`e il valore corrente di @code{TEXTDOMAIN}.
+Il valore di default per @var{categoria} @`e @code{"LC_MESSAGES"}.
+@end table
+
+@node Funzioni definite dall'utente
+@section Funzioni definite dall'utente
+
+@cindex funzioni definite dall'utente
+@cindex utente, funzioni definite dall'
+Programmi @command{awk} complessi spesso possono essere semplificati
+definendo delle apposite funzioni personali.
+Le funzioni definite dall'utente sono richiamate allo stesso modo di quelle
+predefinite
+(@pxref{Chiamate di funzione}),
+ma dipende dall'utente la loro definizione
+(cio@`e, dire ad @command{awk} cosa dovrebbero fare queste funzioni).
+
+@menu
+* Sintassi delle definizioni:: Come scrivere definizioni e cosa
+ significano.
+* Esempio di funzione:: Un esempio di definizione di
+ funzione e spiegazione della stessa.
+* Precisazioni sulle funzioni:: Cose a cui prestare attenzione.
+* Istruzione return:: Specificare il valore che una
+ funzione restituisce.
+* Variabili di tipo dinamico:: Come cambiare tipo a una variabile in
+ fase di esecuzione del programma.
+@end menu
+
+@node Sintassi delle definizioni
+@subsection Come scrivere definizioni e cosa significano
+
+@quotation
+@i{Risponde al vero affermare che la sintassi di awk per la definizione
+di variabili locali @`e semplicemente atroce.}
+@author Brian Kernighan
+@end quotation
+
+@cindex funzioni, definizione di
+@cindex definizione di funzioni
+Definizioni di funzioni possono stare in una posizione qualsiasi tra le regole
+di un programma @command{awk}. Quindi, la forma generale di un
+programma @command{awk} @`e estesa per
+permettere l'inclusione di regole @emph{e} la definizione di funzioni
+create dall'utente.
+Non @`e necessario che la definizione di una funzione sia posta prima
+del richiamo della stessa. Questo dipende dal fatto che @command{awk}
+legge l'intero programma, prima di iniziare ad eseguirlo.
+
+La definizione di una funzione chiamata @var{nome} @`e simile a questa:
+
+@display
+@code{function} @var{nome}@code{(}[@var{lista-parametri}]@code{)}
+@code{@{}
+ @var{corpo-della-funzione}
+@code{@}}
+@end display
+
+@cindex nomi di funzione
+@cindex funzioni, nomi di
+@cindex limitazioni nei nomi di funzione
+@cindex nomi di funzione, limitazioni nei
+@noindent
+Qui, @var{nome} @`e il nome della funzione da definire. Un nome di funzione
+valido @`e come un nome di variabile valido: una sequenza di
+lettere, cifre e trattini bassi che non inizia con una cifra.
+Anche qui, solo le 52 lettere inglesi maiuscole e minuscole possono
+essere usate in un nome di funzione.
+All'interno di un singolo programma @command{awk}, un dato nome pu@`o essere
+usato una sola volta: per una variabile, o per un vettore,
+o per una funzione.
+
+@var{lista-parametri} @`e una lista opzionale degli argomenti della funzione
+e dei nomi delle variabili locali,
+separati da virgole. Quando la funzione viene chiamata,
+i nomi degli argomenti sono usati per contenere il valore degli argomenti
+passati con la chiamata.
+
+Una funzione non pu@`o avere due parametri con lo stesso nome, e neanche un
+parametro con lo stesso nome della funzione stessa.
+
+@quotation ATTENZIONE
+Secondo lo standard POSIX, i parametri di funzione
+non possono avere lo stesso nome di una delle speciali variabili predefinite
+(@pxref{Variabili predefinite}), e un parametro di funzione non pu@`o avere
+lo stesso nome di un'altra funzione.
+Non tutte le versioni di @command{awk} applicano queste limitazioni.
+@command{gawk} applica solo la prima di queste restrizioni.
+Se viene specificata l'opzione @option{--posix} (@pxref{Opzioni}),
+anche la seconda restrizione viene applicata.
+@end quotation
+
+Le variabili locali si comportano come la stringa vuota
+se vengono utilizzate dove @`e richiesto il valore di una stringa,
+e valgono zero se utilizzate dove @`e richiesto un valore numerico.
+Questo @`e lo stesso comportamento delle variabili regolari a cui non sia
+stato ancora assegnato un valore. (Ci sono ulteriori informazioni riguardo
+alle variabili locali;
+@pxref{Variabili di tipo dinamico}.)
+
+Il @var{corpo-della-funzione} @`e composto da istruzioni @command{awk}.
+Questa @`e la parte pi@`u importante della definizione, perch@'e dice quello che
+la funzione dovrebbe realmente
+@emph{fare}. I nomi di argomento esistono per consentire al corpo della
+funzione di gestire gli argomenti;
+le variabili locali esistono per consentire al corpo della funzione di
+memorizzare dei valori temporanei.
+
+I nomi di argomento non sono sintatticamente distinti da quelli delle
+variabili locali. Invece, il numero di argomenti forniti quando la
+funzione viene chiamata determina quanti degli argomenti passati sono delle
+variabili. Quindi, se tre valori di argomento sono specificati, i primi
+tre nomi in @var{lista-parametri}
+sono degli argomenti e i rimanenti sono delle variabili locali.
+
+Ne consegue che se il numero di argomenti richiesto non @`e lo stesso in
+tutte le chiamate alla funzione, alcuni dei nomi in @var{lista-parametri}
+possono essere in alcuni casi degli argomenti e in altri casi
+delle variabili locali. Un'altra angolatura da cui guardare questo fatto
+@`e che gli argomenti omessi assumono come valore di default la stringa nulla.
+
+@cindex convenzioni di programmazione, nella scrittura di funzioni
+@cindex funzioni, convenzioni di programmazione, nella scrittura di
+Solitamente, quando si scrive una funzione, si sa quanti nomi si intendono
+usare per gli argomenti e quanti si vogliono usare come variabili locali.
+@`E una convenzione in uso quella di aggiungere alcuni spazi extra tra gli
+argomenti e le variabili locali, per documentare come va utilizzata quella
+funzione.
+
+@cindex variabili nascoste
+@cindex nascondere valori di variabile
+Durante l'esecuzione del corpo della funzione, gli argomenti e i valori
+delle variabili locali
+nascondono, o @dfn{oscurano}, qualsiasi variabile dello stesso nome usata
+nel resto del programma. Le variabili oscurate non sono accessibili
+nel corpo della funzione, perch@'e non c'@`e modo di accedere a esse
+mentre i loro nomi sono stati "occupati" dagli argomenti e dalla variabili
+locali. Tutte le altre variabili usate nel programma @command{awk}
+possono essere accedute o impostate normalmente nel corpo della funzione.
+
+Gli argomenti e le variabili locali esistono solo finch@'e il corpo della
+funzione @`e in esecuzione. Una volta che l'esecuzione @`e terminata,
+ritornano accessibili le variabili che erano oscurate
+durante l'esecuzione della funzione.
+
+@cindex ricorsive, funzioni
+@cindex funzioni ricorsive
+Il corpo della funzione pu@`o contenere espressioni che chiamano altre
+funzioni. Tali espressioni possono perfino chiamare direttamente, o
+indirettamente tramite un'altra funzione, la funzione stessa.
+Quando questo succede, la funzione @`e detta @dfn{ricorsiva}.
+Il fatto che una funzione richiami se stessa @`e detto @dfn{ricorsione}.
+
+Tutte le funzioni predefinite restituiscono un valore al loro chiamante.
+Anche le funzioni definite dall'utente possono farlo, usando
+l'istruzione @code{return},
+che @`e descritta in dettaglio nella @ref{Istruzione return}.
+Molti dei successivi esempi in questa @value{SECTION} usano
+l'istruzione @code{return}.
+
+@cindex estensioni comuni, parola chiave @code{func}
+@c @cindex @command{awk} language, POSIX version
+@c @cindex POSIX @command{awk}
+@cindex POSIX @command{awk}, parola chiave @code{function} in
+In molte implementazioni di @command{awk}, compreso @command{gawk},
+la parola chiave @code{function} pu@`o essere
+abbreviata come @code{func}. @value{COMMONEXT}
+Tuttavia, POSIX specifica solo l'uso della parola chiave
+@code{function}. Questo ha alcune implicazioni di carattere pratico.
+Se @command{gawk} @`e in modalit@`a POSIX-compatibile
+(@pxref{Opzioni}), la seguente
+istruzione @emph{non} definisce una funzione:
+
+@example
+func foo() @{ a = sqrt($1) ; print a @}
+@end example
+
+@noindent
+Invece, definisce una regola che, per ogni record, concatena il valore
+della variabile @samp{func} con il valore restituito dalla funzione @samp{foo}.
+Se la stringa risultante @`e diversa dalla stringa nulla, l'azione viene eseguita.
+Questo non @`e con ogni probabilit@`a quello che si desidera.
+(@command{awk} accetta questo input come
+sintatticamente valido, perch@'e le funzioni, nei programmi @command{awk}
+possono essere usate prima che siano state definite.@footnote{Questo
+programma in realt@`a non verr@`a eseguito, perch@'e @code{foo()} risulter@`a
+essere una funzione non definita.})
+
+@cindex portabilit@`a, nella definizione di funzioni
+Per essere certi che un programma @command{awk} sia portabile,
+va sempre usata la parola chiave
+@code{function} per definire una funzione.
+
+@node Esempio di funzione
+@subsection Un esempio di definizione di funzione
+@cindex esempio di definizione di funzione
+@cindex funzione, esempio di definizione di
+
+
+Ecco un esempio di funzione definita dall'utente, di nome
+@code{stampa_num()}, che
+ha come input un numero e lo stampa in un formato specifico:
+
+@example
+function stampa_num(numero)
+@{
+ printf "%6.3g\n", numero
+@}
+@end example
+
+@noindent
+Per comprenderne il funzionamento, ecco una regola @command{awk} che usa
+la funzione @code{stampa_num()}:
+
+@example
+$3 > 0 @{ stampa_num($3) @}
+@end example
+
+@noindent
+Questo programma stampa, nel nostro formato speciale, tutti i terzi campi
+nei record in input che
+contengono un numero positivo. Quindi, dato il seguente input:
+
+@example
+ 1.2 3.4 5.6 7.8
+ 9.10 11.12 -13.14 15.16
+17.18 19.20 21.22 23.24
+@end example
+
+@noindent
+questo programma, usando la nostra funzione per formattare i risultati, stampa:
+
+@example
+ 5.6
+ 21.2
+@end example
+
+La funzione seguente cancella tutti gli elementi in un vettore
+(si ricordi che gli spazi bianchi in soprannumero stanno a indicare
+l'inizio della lista delle variabili locali):
+
+@example
+function cancella_vettore(a, i)
+@{
+ for (i in a)
+ delete a[i]
+@}
+@end example
+
+Quando si lavora con vettori, @`e spesso necessario cancellare
+tutti gli elementi in un vettore e ripartire con una nuova lista di elementi
+(@pxref{Cancellazione}).
+Invece di dover ripetere
+questo ciclo ogni volta che si deve cancellare
+un vettore, un programma pu@`o limitarsi a effettuare una chiamata
+a @code{cancella_vettore()}.
+(Questo garantisce la portabilit@`a. L'uso di @samp{delete @var{vettore}}
+per cancellare
+il contenuto di un intero vettore @`e un'aggiunta relativamente
+recente@footnote{Verso la fine del 2012.}
+allo standard POSIX.)
+
+Quello che segue @`e un esempio di una funzione ricorsiva. Prende come
+parametro di input una stringa e restituisce la stringa in ordine inverso.
+Le funzioni ricorsive devono sempre avere un test che interrompa la
+ricorsione.
+In questo caso, la ricorsione termina quando la stringa in input @`e
+gi@`a vuota:
+
+@c 8/2014: Thanks to Mike Brennan for the improved formulation
+@cindex @code{rev()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{rev()}
+@example
+function rev(stringa)
+@{
+ if (stringa == "")
+ return ""
+
+ return (rev(substr(stringa, 2)) substr(stringa, 1, 1))
+@}
+@end example
+
+Se questa funzione @`e in un file di nome @file{rev.awk}, si pu@`o provare
+cos@`{@dotless{i}}:
+
+@example
+$ @kbd{echo "Non v'allarmate!" |}
+> @kbd{gawk -e '@{ print rev($0) @}' -f rev.awk}
+@print{} !etamralla'v noN
+@end example
+
+La funzione C @code{ctime()} prende una marcatura temporale e la restituisce
+come una stringa,
+formattata come gi@`a sappiamo.
+Il seguente esempio usa la funzione predefinita @code{strftime()}
+(@pxref{Funzioni di tempo})
+per creare una versione @command{awk} di @code{ctime()}:
+
+@cindex @code{ctime()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{ctime()}
+@example
+@c file eg/lib/ctime.awk
+# ctime.awk
+#
+# versione awk della funzione C ctime(3)
+
+function ctime(ts, format)
+@{
+ format = "%a %e %b %Y, %H.%M.%S, %Z"
+
+ if (ts == 0)
+ ts = systime() # usare data e ora correnti per default
+ return strftime(format, ts)
+@}
+@c endfile
+@end example
+
+Si potrebbe pensare che la funzione @code{ctime()} possa usare
+@code{PROCINFO["strftime"]}
+come stringa di formato. Sarebbe un errore, perch@'e si suppone che
+@code{ctime()} restituisca data e ora formattati in maniera standard,
+e qualche codice a livello utente potrebbe aver modificato in precedenza
+@code{PROCINFO["strftime"]}.
+
+@node Precisazioni sulle funzioni
+@subsection Chiamare funzioni definite dall'utente
+
+@cindex funzioni definite dall'utente, chiamare
+@cindex chiamare funzioni definite dall'utente
+@dfn{Chiamare una funzione} significa richiedere l'esecuzione di una
+funzione, la quale svolge il compito per cui @`e stata scritta.
+La chiamata di una funzione @`e un'espressione e il suo valore @`e quello
+restituito dalla funzione.
+
+@menu
+* Chiamare una funzione:: Non usare spazi.
+* Campo di validit@`a variabili:: Variabili locali e globali.
+* Parametri per valore/riferimento:: Passaggio parametri.
+@end menu
+
+@node Chiamare una funzione
+@subsubsection Scrivere una chiamata di funzione
+
+Una chiamata di funzione consiste nel nome della funzione seguito dagli
+argomenti racchiusi tra parentesi. Gli argomenti specificati nella chiamata
+sono costituiti da espressioni @command{awk}. Ogni volta che si esegue una
+chiamata queste espressioni vengono ricalcolate, e i loro valori diventano gli
+argomenti passati alla funzione. Per esempio, ecco una chiamata a
+@code{pippo()} con tre argomenti (il primo dei quali @`e una concatenazione di
+stringhe):
+
+@example
+pippo(x y, "perdere", 4 * z)
+@end example
+
+@quotation ATTENZIONE
+Caratteri bianchi (spazi e TAB) non sono permessi tra il nome della funzione e
+la parentesi aperta che apre la lista degli argomenti. Se per errore si
+lasciano dei caratteri bianchi, @command{awk} li interpreterebbe come se
+s'intendesse concatenare una variabile con un'espressione tra parentesi.
+Tuttavia, poich@'e si @`e usato un nome di funzione e non un nome di variabile,
+verrebbe emesso un messaggio di errore.
+@end quotation
+
+@node Campo di validit@`a variabili
+@subsubsection Variabili locali e globali.
+
+@cindex variabili locali, in una funzione
+@cindex locali, variabili, per una funzione
+Diversamente da molti altri linguaggi, non c'@`e modo di
+rendere locale una variabile in un blocco @code{@{} @dots{} @code{@}} di
+@command{awk}, ma si pu@`o rendere locale una variabile di una funzione. @`E
+buona norma farlo quando una variabile serve solo all'interno di quella
+particolare funzione.
+
+Per rendere locale una variabile per una funzione, basta dichiarare la
+variabile come argomento della funzione dopo gli argomenti richiesti dalla
+funzione (@pxref{Sintassi delle definizioni}). Si consideri il seguente
+esempio, dove la variabile @code{i} @`e una variabile globale usata sia dalla
+funzione @code{pippo()} che dalla funzione @code{pluto()}:
+
+@example
+function pluto()
+@{
+ for (i = 0; i < 3; i++)
+ print "in pluto i=" i
+@}
+
+function pippo(j)
+@{
+ i = j + 1
+ print "in pippo i=" i
+ pluto()
+ print "in pippo i=" i
+@}
+
+BEGIN @{
+ i = 10
+ print "in BEGIN i=" i
+ pippo(0)
+ print "in BEGIN i=" i
+@}
+@end example
+
+L'esecuzione di questo script produce quanto segue, perch@'e la stessa
+variabile @code{i} @`e usata sia nelle
+funzioni @code{pippo()} e @code{pluto()} sia a livello della
+regola @code{BEGIN}:
+
+@example
+in BEGIN i=10
+in pippo i=1
+in pluto i=0
+in pluto i=1
+in pluto i=2
+in pippo i=3
+in BEGIN i=3
+@end example
+
+Se si vuole che @code{i} sia una variabile locale sia per
+@code{pippo()} che per @code{pluto()}, occorre procedere in questo modo
+(gli spazi extra prima della @code{i} sono una convenzione di codifica
+che serve a ricordare che @code{i} @`e una variabile locale, non
+un argomento):
+
+@example
+function pluto( i)
+@{
+ for (i = 0; i < 3; i++)
+ print "in pluto i=" i
+@}
+
+function pippo(j, i)
+@{
+ i = j + 1
+ print "in pippo i=" i
+ pluto()
+ print "in pippo i=" i
+@}
+
+BEGIN @{
+ i = 10
+ print "in BEGIN i=" i
+ pippo(0)
+ print "in BEGIN i=" i
+@}
+@end example
+
+L'esecuzione della versione corretta dello script produce il seguente
+output:
+
+@example
+in BEGIN i=10
+in pippo i=1
+in pluto i=0
+in pluto i=1
+in pluto i=2
+in pippo i=1
+in BEGIN i=10
+@end example
+
+Oltre a valori scalari (stringhe e numeri), si possono usare anche
+vettori locali. Usando come parametro il nome di un vettore, @command{awk}
+lo considera come tale, e lo tratta come locale alla funzione.
+Inoltre, chiamate ricorsive creano nuovi vettori.
+Si consideri questo esempio:
+
+@example
+function qualche_funz(p1, a)
+@{
+ if (p1++ > 3)
+ return
+
+ a[p1] = p1
+
+ qualche_funz(p1)
+
+ printf("Al livello %d, indice %d %s trova in a\n",
+ p1, (p1 - 1), (p1 - 1) in a ? "si" : "non si")
+ printf("Al livello %d, indice %d %s trova in a\n",
+ p1, p1, p1 in a ? "si" : "non si")
+ print ""
+@}
+
+BEGIN @{
+ qualche_funz(1)
+@}
+@end example
+
+Quando viene eseguito, questo programma produce il seguente output:
+
+@example
+Al livello 4, indice 3 non si trova in a
+Al livello 4, indice 4 si trova in a
+
+Al livello 3, indice 2 non si trova in a
+Al livello 3, indice 3 si trova in a
+
+Al livello 2, indice 1 non si trova in a
+Al livello 2, indice 2 si trova in a
+@end example
+
+@node Parametri per valore/riferimento
+@subsubsection Passare parametri di funzione per valore o per riferimento
+
+In @command{awk}, quando si definisce una funzione, non c'@`e modo di
+dichiarare esplicitamente se gli argomenti sono passati @dfn{per valore}
+o @dfn{per riferimento}.
+
+Invece, il modo con cui i parametri sono passati @`e determinato
+durante l'esecuzione del programma,
+quando la funzione @`e chiamata, nel rispetto della regola seguente:
+se l'argomento @`e una variabile di tipo vettoriale, questa @`e passata
+per riferimento. Altrimenti, l'argomento @`e passato per valore.
+
+@cindex chiamare per valore
+Passare un argomento per valore significa che quando una funzione @`e chiamata,
+le viene fornita una @emph{copia} del valore di quell'argomento. Il chiamante
+pu@`o usare una variabile il cui valore calcolato viene passato come argomento, ma la
+funzione chiamata non la riconosce come variabile; riconosce solo il valore
+assunto dall'argomento. Per esempio, scrivendo il seguente codice:
+
+@example
+pippo = "pluto"
+z = mia_funzione(pippo)
+@end example
+
+@noindent
+non si deve pensare che l'argomento passato a @code{mia_funzione()} sia ``la
+variabile @code{pippo}.'' Invece, @`e corretto considerare l'argomento come la
+stringa il cui valore @`e @code{"pluto"}.
+Se la funzione @code{mia_funzione()} altera i valori delle sue variabili
+locali, ci@`o non influisce su nessun'altra variabile. Quindi, se
+@code{mia_funzione()} fa questo:
+
+@example
+function mia_funzione(stringa)
+@{
+ print stringa
+ stringa = "zzz"
+ print stringa
+@}
+@end example
+
+@noindent
+cambiando cos@`{@dotless{i}} il valore della variabile che @`e il suo primo argomento, ossia
+@code{stringa}, il valore di @code{pippo} per il chiamante @emph{non} viene
+modificato. Il ruolo svolto da @code{pippo} nella chiamata di
+@code{mia_funzione()} termina quando il suo valore (@code{"pluto"}) viene
+calcolato. Se la variabile @code{stringa} esiste anche al di fuori di
+@code{mia_funzione()}, il corpo della funzione non pu@`o modificare questo valore
+esterno, perch@'e esso rimane oscurato durante l'esecuzione di
+@code{mia_funzione()} e non pu@`o quindi essere visto o modificato.
+
+@cindex chiamare per riferimento
+@cindex vettori, come parametri di funzione
+@cindex funzioni, vettori come parametri di
+Tuttavia, quando sono dei vettori a fungere da parametri alle funzioni, questi
+@emph{non} vengono copiati. Invece, il vettore stesso @`e reso disponibile per
+essere manipolato direttamente dalla funzione. Questo @`e quel che si dice
+solitamente una @dfn{chiamata per riferimento}. Le modifiche effettuate su un
+vettore passato come parametro all'interno del corpo di una funzione
+@emph{sono} visibili all'esterno della funzione.
+
+@quotation NOTA
+Modificare un vettore passato come parametro all'interno di una funzione
+pu@`o essere molto pericoloso se non si sta attenti a quel che si sta facendo.
+Per esempio:
+
+@example
+function cambialo(vettore, ind, nvalore)
+@{
+ vettore[ind] = nvalore
+@}
+
+BEGIN @{
+ a[1] = 1; a[2] = 2; a[3] = 3
+ cambialo(a, 2, "due")
+ printf "a[1] = %s, a[2] = %s, a[3] = %s\n",
+ a[1], a[2], a[3]
+@}
+@end example
+
+@noindent
+stampa @samp{a[1] = 1, a[2] = due, a[3] = 3}, perch@'e
+@code{cambialo()} memorizza @code{"due"} nel secondo elemento di @code{a}.
+@end quotation
+
+@cindex indefinite, funzioni
+@cindex funzioni indefinite
+Alcune implementazioni di @command{awk} consentono di chiamare una
+funzione che non @`e stata definita.
+Viene solo emesso un messaggio che descrive il problema al momento
+dell'esecuzione, se il programma tenta di chiamare quella funzione.
+Per esempio:
+
+@example
+BEGIN @{
+ if (0)
+ pippo()
+ else
+ pluto()
+@}
+function pluto() @{ @dots{} @}
+# si noti che `pippo' non @`e definito
+@end example
+
+@noindent
+Poich@'e la condizione dell'istruzione @samp{if} non risulter@`a mai verificata
+in questo caso,
+non @`e un problema reale il fatto che
+che @code{pippo()} non sia stato definito. Solitamente, tuttavia,
+@`e un problema se un programma chiama una funzione indefinita.
+
+@cindex @dfn{lint}, controlli, funzione indefinita
+@cindex controlli @dfn{lint} per funzione indefinita
+@cindex funzione indefinita, controlli @dfn{lint} per
+
+Se si specifica l'opzione @option{--lint}
+(@pxref{Opzioni}),
+@command{gawk} elenca le chiamate a funzioni indefinite.
+
+@cindex portabilit@`a, istruzione @code{next} in funzioni definite dall'utente
+@cindex @code{next}, istruzione, in funzioni definite dall'utente
+Alcune implementazione di @command{awk} emettono un messaggio di errore
+se si usa l'istruzione @code{next}
+o @code{nextfile}
+(@pxref{Istruzione next}, e
+@ifdocbook
+@ref{Istruzione nextfile})
+@end ifdocbook
+@ifnotdocbook
+@pxref{Istruzione nextfile})
+@end ifnotdocbook
+all'interno di una funzione definita dall'utente.
+@command{gawk} non ha questa limitazione.
+
+@node Istruzione return
+@subsection L'istruzione @code{return}
+@cindex @code{return}, istruzione@comma{} in funzioni definite dall'utente
+@cindex istruzione @code{return}@comma{} in funzioni definite dall'utente
+
+Come visto in parecchi esempi precedenti,
+il corpo di una funzione definita dall'utente pu@`o contenere un'istruzione
+@code{return}.
+Quest'istruzione restituisce il controllo a quella parte del
+del programma @command{awk} che ha effettuato la chiamata.
+Pu@`o anche essere usata per restituire un valore da usare nel resto del
+programma @command{awk}.
+Questo @`e un esempio:
+
+@display
+@code{return} [@var{espressione}]
+@end display
+
+La parte @var{espressione} @`e facoltativa.
+Probabilmente per una svista, POSIX non definisce qual @`e il valore
+restituito, se si omette @var{espressione}. Tecnicamente parlando, questo
+rende il valore restituito indefinito, e quindi, indeterminato.
+In pratica, tuttavia, tutte le versioni di @command{awk} restituiscono
+semplicemente la stringa nulla, che vale zero se usata
+in un contesto che richiede un numero.
+
+Un'istruzione @code{return} senza una @var{espressione} @`e considerata presente
+alla fine di ogni definizione di funzione.
+Quindi, se il flusso di esecuzione raggiunge la fine del corpo della
+funzione, tecnicamente la funzione
+restituisce un valore indeterminato.
+In pratica, restituisce la stringa nulla. @command{awk}
+@emph{non} emette alcun messaggio di avvertimento se si usa
+il valore restituito di una tale funzione.
+
+Talvolta pu@`o capitare di scrivere una funzione per quello che fa, non per
+quello che restituisce. Una tale funzione corrisponde a una funzione
+@code{void} in C, C++, o Java, o a una @code{procedure} in Ada.
+Quindi, pu@`o essere corretto non
+restituire alcun valore; basta fare attenzione a non usare poi il
+valore restituito da una tale funzione.
+
+Quello che segue @`e un esempio di una funzione definita dall'utente
+che restituisce un valore che @`e
+il numero pi@`u alto presente tra gli elementi di un vettore:
+
+@example
+function massimo(vettore, i, max)
+@{
+ for (i in vettore) @{
+ if (max == "" || vettore[i] > max)
+ max = vettore[i]
+ @}
+ return max
+@}
+@end example
+
+@cindex programmazione, convenzioni di, parametri di funzione
+@cindex convenzioni di programmazione, parametri di funzione
+@noindent
+La chiamata a @code{massimo()} ha un solo argomento, che @`e il nome di
+un vettore. Le variabili locali @code{i} e @code{max} non vanno intese
+come argomenti; nulla vieta di passare pi@`u di un argomento
+a @code{massimo()} ma i risultati sarebbero strani. Gli spazi extra prima
+di @code{i} nella lista dei parametri della funzione indicano che @code{i} e
+@code{max} sono variabili locali.
+@`E consigliabile seguire questa convenzione quando si definiscono delle funzioni.
+
+Il programma seguente usa la funzione @code{massimo()}. Carica un vettore,
+richiama @code{massimo()}, e quindi elenca il numero massimo contenuto in
+quel vettore:
+
+@example
+function massimo(vettore, i, max)
+@{
+ for (i in vettore) @{
+ if (max == "" || vettore[i] > max)
+ max = vettore[i]
+ @}
+ return max
+@}
+
+# Carica tutti i campi di ogni record in numeri.
+@{
+ for (i = 1; i <= NF; i++)
+ numeri[NR, i] = $i
+@}
+
+END @{
+ print massimo(numeri)
+@}
+@end example
+
+Dato il seguente input:
+
+@example
+ 1 5 23 8 16
+44 3 5 2 8 26
+256 291 1396 2962 100
+-6 467 998 1101
+99385 11 0 225
+@end example
+
+@noindent
+il programma trova (come si pu@`o immaginare) che 99.385 @`e il
+valore pi@`u alto contenuto nel vettore.
+
+@node Variabili di tipo dinamico
+@subsection Funzioni e loro effetti sul tipo di una variabile
+
+@command{awk} @`e un linguaggio molto fluido.
+@`E possible che @command{awk} non sia in grado di stabilire se un
+identificativo rappresenta una variabile scalare o un vettore,
+prima dell'effettiva esecuzione di un programma.
+Ecco un esempio di programma commentato:
+
+@example
+function pippo(a)
+@{
+ a[1] = 1 # il parametro @`e un vettore
+@}
+
+BEGIN @{
+ b = 1
+ pippo(b) # non valido: errore fatale, tipi variabile in conflitto
+
+ pippo(x) # x non inizializzato, diventa un vettore dinamicamente
+ x = 1 # a questo punto, non permesso: errore in esecuzione
+@}
+@end example
+
+In questo esempio, la prima chiamata a @code{pippo()} genera
+un errore fatale, quindi @command{awk} non arriver@`a a segnalare il secondo
+errore. Se si commenta la prima chiamata e si riesegue il
+programma, a quel punto @command{awk} terminer@`a con un messaggio
+relativo al secondo errore.
+Solitamente queste cose non causano grossi problemi, ma @`e bene
+esserne a conoscenza.
+
+@node Chiamate indirette
+@section Chiamate indirette di funzione
+
+@cindex indiretta, chiamata di funzione
+@cindex chiamata indiretta di funzione
+@cindex funzione, puntatori a
+@cindex puntatori a funzioni
+@cindex differenze tra @command{awk} e @command{gawk}, chiamata indiretta di funzione
+
+Questa sezione descrive un'estensione avanzata, specifica di @command{gawk}.
+
+Spesso pu@`o essere utile ritardare la scelta della funzione da chiamare
+fino al momento in cui il programma viene eseguito.
+Per esempio, potrebbero esserci diversi tipi di record in input, ciascuno
+dei quali dovrebbe essere elaborato in maniera differente.
+
+Solitamente, si userebbe una serie di istruzioni @code{if}-@code{else}
+per decidere quale funzione chiamare. Usando la chiamata @dfn{indiretta}
+a una funzione, si pu@`o assegnare il nome della funzione da chiamare a
+una variabile di tipo stringa, e usarla per chiamare la funzione.
+Vediamo un esempio.
+
+Si supponga di avere un file con i punteggi ottenuti negli esami per i
+corsi che si stanno seguendo, e che si desideri ottenere la somma e la
+media dei punteggi ottenuti.
+Il primo campo @`e il nome del corso. I campi seguenti sono i nomi delle
+funzioni da chiamare per elaborare i dati, fino a un campo ``separatore''
+@samp{dati:}. Dopo il separatore, fino alla fine del record,
+ci sono i vari risultati numerici di ogni test.
+
+Ecco il file iniziale:
+
+@example
+@c file eg/data/class_data1
+Biologia_101 somma media dati: 87.0 92.4 78.5 94.9
+Chimica_305 somma media dati: 75.2 98.3 94.7 88.2
+Inglese_401 somma media dati: 100.0 95.6 87.1 93.4
+@c endfile
+@end example
+
+Per elaborare i dati, si potrebbe iniziare a scrivere:
+
+@example
+@{
+ corso = $1
+ for (i = 2; $i != "dati:"; i++) @{
+ if ($i == "somma")
+ somma() # elabora l'intero record
+ else if ($i == "media")
+ media()
+ @dots{} # e cos@`{@dotless{i}} via
+ @}
+@}
+@end example
+
+@noindent
+Questo stile di programmazione funziona, ma pu@`o essere scomodo.
+Con la chiamata @dfn{indiretta} di funzione, si pu@`o richiedere a @command{gawk}
+di usare il @emph{valore} di una variabile come @emph{nome} della funzione da
+chiamare.
+
+@cindex @code{@@}, notazione per la chiamata indiretta di funzioni
+@cindex chiamata indiretta di funzioni, notazione @code{@@}
+La sintassi @`e simile a quella di una normale chiamata di funzione:
+un identificativo, seguito immediatamente da una parentesi aperta,
+qualche argomento, e una parentesi chiusa, con l'aggiunta di un carattere
+@samp{@@} all'inizio:
+
+@example
+quale_funzione = "somma"
+risultato = @@quale_funzione() # chiamata della funzione somma()
+@end example
+
+Ecco un intero programma che elabora i dati mostrati sopra,
+usando la chiamata indiretta di funzioni:
+
+@example
+@c file eg/prog/indirectcall.awk
+# chiamataindiretta.awk --- esempio di chiamata indiretta di funzioni
+@c endfile
+@ignore
+@c file eg/prog/indirectcall.awk
+#
+# Arnold Robbins, arnold@skeeve.com, Public Domain
+# January 2009
+@c endfile
+@end ignore
+
+@c file eg/prog/indirectcall.awk
+# media --- calcola la media dei valori dei campi $primo - $ultimo
+
+function media(primo, ultimo, somma, i)
+@{
+ somma = 0;
+ for (i = primo; i <= ultimo; i++)
+ somma += $i
+
+ return somma / (ultimo - primo + 1)
+@}
+
+# somma --- restituisce la somma dei valori dei campi $primo - $ultimo
+
+function somma(primo, ultimo, totale, i)
+@{
+ max = 0;
+ for (i = primo; i <= ultimo; i++)
+ totale += $i
+
+ return totale
+@}
+@c endfile
+@end example
+
+Queste due funzioni presuppongono che si lavori con dei campi; quindi,
+i parametri @code{primo} e @code{ultimo} indicano da quale campo iniziare
+e fino a quale arrivare.
+Per il resto, eseguono i calcoli richiesti, che sono i soliti:
+
+@example
+@c file eg/prog/indirectcall.awk
+# Per ogni record,
+# stampa il nome del corso e le statistiche richieste
+@{
+ nome_corso = $1
+ gsub(/_/, " ", nome_corso) # Rimpiazza _ con spazi
+
+ # trova campo da cui iniziare
+ for (i = 1; i <= NF; i++) @{
+ if ($i == "dati:") @{
+ inizio = i + 1
+ break
+ @}
+ @}
+
+ printf("%s:\n", nome_corso)
+ for (i = 2; $i != "dati:"; i++) @{
+ quale_funzione = $i
+ printf("\t%s: <%s>\n", $i, @@quale_funzione(inizio, NF) "")
+ @}
+ print ""
+@}
+@c endfile
+@end example
+
+Questo @`e il ciclo principale eseguito per ogni record.
+Stampa il nome del corso (con le
+lineette basse sostituite da spazi). Trova poi l'inizio dei dati veri
+e propri, salvandolo in @code{inizio}.
+L'ultima parte del codice esegue un ciclo per ogni nome di funzione
+(da @code{$2} fino al separatore, @samp{dati:}), chiamando la funzione
+il cui nome @`e specificato nel campo. La chiamata di funzione indiretta
+compare come parametro nella chiamata a @code{printf}.
+(La stringa di formattazione di @code{printf} usa @samp{%s} come
+specificatore di formato, affinch@'e sia possibile usare funzioni
+che restituiscano sia stringhe che numeri. Si noti che il risultato
+della chiamata indiretta @`e concatenato con la stringa nulla, in modo da
+farlo considerare un valore di tipo stringa).
+
+Ecco il risultato dell'esecuzione del programma:
+
+@example
+$ @kbd{gawk -f chiamataindiretta.awk dati_dei_corsi}
+@print{} Biologia 101:
+@print{} somma: <352.8>
+@print{} media: <88.2>
+@print{}
+@print{} Chimica 305:
+@print{} somma: <356.4>
+@print{} media: <89.1>
+@print{}
+@print{} Inglese 401:
+@print{} somma: <376.1>
+@print{} media: <94.025>
+@end example
+
+La possibilit@`a di usare la chiamata indiretta di funzioni @`e pi@`u potente
+di quel che si possa pensare inizialmente.
+I linguaggi C e C++ forniscono ``puntatori di funzione'' che
+sono un metodo per chiamare una funzione scelta al momento dell'esecuzione.
+Uno dei pi@`u noti usi di questa funzionalit@`a @`e
+la funzione C @code{qsort()}, che ordina un vettore usando il famoso
+algoritmo noto come ``quicksort''
+(si veda @uref{http://en.wikipedia.org/wiki/Quicksort, l'articolo di Wikipedia}
+per ulteriori informazioni). Per usare questa funzione, si specifica un
+puntatore a una funzione di confronto. Questo meccanismo consente
+di ordinare dei dati arbitrari in una maniera arbitraria.
+
+Si pu@`o fare qualcosa di simile usando @command{gawk}, cos@`{@dotless{i}}:
+
+@example
+@c file eg/lib/quicksort.awk
+# quicksort.awk --- Algoritmo di quicksort, con funzione di confronto
+# fornita dall'utente
+@c endfile
+@ignore
+@c file eg/lib/quicksort.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# January 2009
+
+@c endfile
+@end ignore
+@c file eg/lib/quicksort.awk
+
+# quicksort --- Algoritmo di quicksort di C.A.R. Hoare.
+# Si veda Wikipedia o quasi ogni libro
+# che tratta di algoritmi o di informatica.
+@c endfile
+@ignore
+@c file eg/lib/quicksort.awk
+#
+# Adattato da B.W. Kernighan & D.M. Ritchie
+# The C Programming Language
+# (Englewood Cliffs, NJ: Prentice Hall, 1988)
+# Seconda Edizione, pagina 110
+@c endfile
+@end ignore
+@c file eg/lib/quicksort.awk
+
+function quicksort(dati, sinistra, destra, minore_di, i, ultimo)
+@{
+ if (sinistra >= destra) # non fa nulla se il vettore contiene
+ return # meno di due elementi
+
+ quicksort_scambia(dati, sinistra, int((sinistra + destra) / 2))
+ ultimo = sinistra
+ for (i = sinistra + 1; i <= destra; i++)
+ if (@@minore_di(dati[i], dati[sinistra]))
+ quicksort_scambia(dati, ++ultimo, i)
+ quicksort_scambia(dati, sinistra, ultimo)
+ quicksort(dati, sinistra, ultimo - 1, minore_di)
+ quicksort(dati, ultimo + 1, destra, minore_di)
+@}
+
+# quicksort_scambia --- funzione ausiliaria per quicksort,
+# sarebbe meglio fosse nel programma principale
+
+function quicksort_scambia(dati, i, j, salva)
+@{
+ salva = dati[i]
+ dati[i] = dati[j]
+ dati[j] = salva
+@}
+@c endfile
+@end example
+
+La funzione @code{quicksort()} riceve il vettore @code{dati}, gli
+indici iniziali e finali da ordinare
+(@code{sinistra} e @code{destra}), e il nome di una funzione che
+esegue un confronto ``minore di''. Viene quindi eseguito
+l'algoritmo di quicksort.
+
+Per fare uso della funzione di ordinamento, torniamo all'esempio
+precedente. La prima cosa da fare @`e di scrivere qualche funzione
+di confronto:
+
+@example
+@c file eg/prog/indirectcall.awk
+# num_min --- confronto numerico per minore di
+
+function num_min(sinistra, destra)
+@{
+ return ((sinistra + 0) < (destra + 0))
+@}
+
+# num_magg_o_ug --- confronto numerico per maggiore o uguale
+
+function num_magg_o_ug(sinistra, destra)
+@{
+ return ((sinistra + 0) >= (destra + 0))
+@}
+@c endfile
+@end example
+
+La funzione @code{num_magg_o_ug()} serve per ottenere un ordinamento
+decrescente (dal numero pi@`u alto al pi@`u basso); quando @`e usato
+per eseguire un test per ``minore di'', in realt@`a fa l'opposto
+(maggiore o uguale a), il che conduce a ottenere dati ordinati
+in ordine decrescente.
+
+Poi serve una funzione di ordinamento.
+Come parametri ha i numeri del campo iniziale e di quello finale,
+e il nome della funzione di confronto.
+Costruisce un vettore con
+i dati e richiama appropriatamente @code{quicksort()}; quindi formatta i
+risultati mettendoli in un'unica stringa:
+
+@example
+@c file eg/prog/indirectcall.awk
+# ordina --- ordina i dati a seconda di `confronta'
+# e li restituisce come un'unica stringa
+
+function ordina(primo, ultimo, confronta, dati, i, risultato)
+@{
+ delete dati
+ for (i = 1; primo <= ultimo; primo++) @{
+ dati[i] = $primo
+ i++
+ @}
+
+ quicksort(dati, 1, i-1, confronta)
+
+ risultato = dati[1]
+ for (i = 2; i in dati; i++)
+ risultato = risultato " " dati[i]
+
+ return risultato
+@}
+@c endfile
+@end example
+
+Per finire, le due funzioni di ordinamento chiamano la funzione
+@code{ordina()}, passandole i nomi delle due funzioni di confronto:
+
+@example
+@c file eg/prog/indirectcall.awk
+# ascendente --- ordina i dati in ordine crescente
+# e li restituisce sotto forma di stringa
+
+function ascendente(primo, ultimo)
+@{
+ return ordina(primo, ultimo, "num_min")
+@}
+
+# discendente --- ordina i dati in ordine decrescente
+# e li restituisce sotto forma di stringa
+
+function discendente(primo, ultimo)
+@{
+ return ordina(primo, ultimo, "num_magg_o_ug")
+@}
+@c endfile
+@end example
+
+Ecco una versione estesa del @value{DF}:
+
+@example
+@c file eg/data/class_data2
+Biologia_101 somma media ordina discendente dati: 87.0 92.4 78.5 94.9
+Chimica_305 somma media ordina discendente dati: 75.2 98.3 94.7 88.2
+Inglese_401 somma media ordina discendente dati: 100.0 95.6 87.1 93.4
+@c endfile
+@end example
+
+Per finire, questi sono i risultati quando si esegue il programma
+in questa versione migliorata:
+
+@example
+$ @kbd{gawk -f quicksort.awk -f indirettacall.awk class_data2}
+@print{} Biologia 101:
+@print{} somma: <352.8>
+@print{} media: <88.2>
+@print{} ascendente: <78.5 87.0 92.4 94.9>
+@print{} discendente: <94.9 92.4 87.0 78.5>
+@print{}
+@print{} Chimica 305:
+@print{} somma: <356.4>
+@print{} media: <89.1>
+@print{} ascendente: <75.2 88.2 94.7 98.3>
+@print{} discendente: <98.3 94.7 88.2 75.2>
+@print{}
+@print{} Inglese 401:
+@print{} somma: <376.1>
+@print{} media: <94.025>
+@print{} ascendente: <87.1 93.4 95.6 100.0>
+@print{} discendente: <100.0 95.6 93.4 87.1>
+@end example
+
+Un altro esempio in cui le chiamate indirette di funzione sono utili
+@`e costituito dall'elaborazione di vettori. La descrizione si pu@`o trovare
+@ref{Visitare vettori}.
+
+Occorre ricordarsi di anteporre il carattere @samp{@@} prima di una
+chiamata indiretta di funzione.
+
+A partire dalla @value{PVERSION} 4.1.2 di @command{gawk}, le chiamate
+indirette di funzione
+possono anche essere usate per chiamare funzioni predefinite e con
+funzioni di estensione
+(@pxref{Estensioni dinamiche}). Ci sono alcune limitazioni nel richiamare
+in maniera indiretta delle funzioni predefinite, come qui dettagliato:
+
+@itemize @value{BULLET}
+@item
+Non si pu@`o passare una costante @dfn{regexp} a una funzione predefinita
+effettuando una chiamata di funzione indiretta.@footnote{Questa
+limitazione potrebbe cambiare in una futura versione;
+per appurarlo, si controlli la documentazione che accompagna
+la versione in uso di @command{gawk}.}
+Quanto sopra vale per le funzioni
+@code{sub()}, @code{gsub()}, @code{gensub()}, @code{match()},
+@code{split()} e @code{patsplit()}.
+
+@item
+Nel chiamare @code{sub()} o @code{gsub()}, sono accettati solo due argomenti,
+poich@'e queste funzioni sono atipiche, in quanto aggiornano il loro terzo
+argomento. Questo significa che verr@`a sempre aggiornato l'argomento di
+default, @code{$0}.
+@end itemize
+
+@command{gawk} fa del suo meglio per rendere efficiente la chiamata indiretta
+di funzioni. Per esempio, nel ciclo seguente:
+
+@example
+for (i = 1; i <= n; i++)
+ @@quale_funzione()
+@end example
+
+@noindent
+@command{gawk} ricerca solo una volta quale funzione chiamare.
+
+@node Sommario delle funzioni
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+@command{awk} include delle funzioni predefinite e consente all'utente
+di definire le sue proprie funzioni.
+
+@item
+POSIX @command{awk} include tre tipi di funzioni predefinite: numeriche, di
+stringa, e di I/O. @command{gawk} prevede funzioni per ordinare vettori, per
+lavorare con valori che rappresentano marcature temporali,
+per la manipolazione di bit,
+per determinare il tipo di una variabile (vettoriale piuttosto che scalare), e
+programmi per l'internazionalizzazione e la localizzazione. @command{gawk}
+prevede anche parecchie estensioni ad alcune funzioni standard, tipicamente
+nella forma di ulteriori argomenti.
+
+@item
+Le funzioni accettano zero o pi@`u argomenti e restituiscono un valore. Le
+espressioni che specificano il valore di ogni argomento sono valutate
+completamente prima della chiamata
+a una funzione. L'ordine di valutazione di questi argomenti non @`e definito.
+Il valore restituito dalla funzione pu@`o essere ignorato.
+
+@item
+La gestione delle barre inverse in @code{sub()} e @code{gsub()} non @`e
+semplice.
+@`E pi@`u semplice nella funzione di @command{gawk} @code{gensub()},
+ma anche questa funzione richiede attenzione quando la si usa.
+
+@item
+Le funzioni definite dall'utente consentono importanti funzionalit@`a ma hanno
+anche alcune ineleganze sintattiche. In una chiamata di funzione non si pu@`o
+inserire alcuno spazio tra il nome della funzione e la parentesi sinistra
+aperta che inizia la lista degli argomenti. Inoltre, non c'@`e nessuna
+prescrizione per le variabili locali, e per questo la
+convenzione in uso @`e di aggiungere parametri extra, e di separarli visivamente
+dai parametri veri e propri inserendo degli spazi bianchi prima di essi.
+
+@item
+Le funzioni definite dall'utente possono chiamare altre
+funzioni definite dall'utente (oltre a quelle predefinite)
+e possono chiamare se stesse ricorsivamente. I parametri di funzione
+``nascondono'' qualsiasi variabile globale che abbia lo stesso nome.
+Non si pu@`o usare il nome di una variabile riservata (p.es. @code{ARGC})
+come nome di un parametro in funzioni definite dall'utente.
+
+@item
+I valori scalari sono passati alle funzioni definite dall'utente
+per valore. I parametri che sono dei vettori sono passati alle funzioni
+per riferimento; ogni modifica fatta dalla funzione a un parametro che
+sia un vettore @`e quindi visibile dopo aver eseguito quella funzione.
+
+@item
+L'istruzione @code{return} serve per tornare indietro da una funzione definita
+dall'utente. Un'espressione opzionale diviene il valore restituito dalla
+funzione. Una funzione pu@`o solo restituire valori di tipo scalare.
+
+@item
+Se una variabile che non @`e stata mai usata @`e passata a una funzione
+definita dall'utente, il modo con cui quella funzione elabora la variabile
+ne pu@`o determinare il tipo: o scalare o vettoriale.
+
+@item
+@command{gawk} consente la chiamata indiretta di funzioni usando una sintassi
+speciale. Impostando una variabile al nome di una funzione, si pu@`o
+determinare al momento dell'esecuzione che funzione sar@`a chiamata in un certo
+punto del programma. Questo equivale a usare un puntatore a una funzione nei
+linguaggi C e C++.
+
+@end itemize
+
+
+@ifnotinfo
+@part @value{PART2}Risoluzione di problemi con @command{awk}
+@end ifnotinfo
+
+@ifdocbook
+La Parte II mostra come usare @command{awk} e @command{gawk} per risolvere
+problemi. Qui c'@`e il codice di molti programmi, da leggere e da cui si pu@`o
+imparare. @`E composta dai seguenti capitoli:
+
+@itemize @value{BULLET}
+@item
+@ref{Funzioni di libreria}
+
+@item
+@ref{Programmi di esempio}
+@end itemize
+@end ifdocbook
+
+@node Funzioni di libreria
+@chapter Una libreria di funzioni @command{awk}
+@cindex libreria di funzioni @command{awk}
+@cindex funzioni di libreria
+@cindex funzioni definite dall'utente, libreria di
+
+@iftex
+La
+@end iftex
+@ref{Funzioni definite dall'utente} descrive come scrivere le proprie
+funzioni @command{awk} personali. Scrivere funzioni @`e importante, perch@'e
+consente di incapsulare in un unico contenitore algoritmi e azioni di
+programma. Semplifica la programmazione, rendendo lo sviluppo di un programma
+pi@`u gestibile, e rendendo i programmi pi@`u leggibili.
+
+@cindex Kernighan, Brian
+@cindex Plauger, P.J.@:
+Nel loro autorevole libro del 1976,
+@cite{Software Tools},@footnote{Purtroppo, a distanza di oltre 35 anni,
+molte delle
+lezioni impartite da questo libro devono ancora essere apprese da un gran
+numero di programmatori professionisti.}
+Brian Kernighan e P.J.@: Plauger hanno scritto:
+
+@quotation
+A programmare bene non s'impara dai concetti generali, ma vedendo come
+programmi complessi possono essere resi puliti, facili da leggere,
+facili da manutenere e modificare,
+strutturati in modo comprensibile, efficienti e affidabili,
+applicando il buon senso e delle buone pratiche di programmazione.
+Lo studio attento e l'imitazione di buoni programmi conduce a una migliore
+scrittura.
+@end quotation
+
+In effetti, loro reputavano quest'idea tanto importante da mettere questa
+frase sulla copertina del libro. Poich@'e credo fermamente che la loro
+affermazione sia corretta, questo @value{CHAPTER} e
+@iftex
+il
+@end iftex
+@ref{Programmi di esempio}
+forniscono una corposa raccolta di codice da leggere e, si spera, da cui
+imparare.
+
+Questo @value{CHAPTER} illustra una libreria di utili funzioni @command{awk}.
+Molti dei programmi descritti nel seguito di questo @value{DOCUMENT}
+usano queste funzioni.
+Le funzioni sono illustrate progressivamente, dalla pi@`u semplice alla pi@`u
+complessa.
+
+@cindex Texinfo
+@iftex
+La
+@end iftex
+@ref{Programma extract}
+illustra un programma che si pu@`o usare per estrarre il codice sorgente
+degli esempi di funzioni di libreria e di programmi dal sorgente Texinfo
+di questo @value{DOCUMENT}.
+(Questo @`e gi@`a stato fatto durante la preparazione della distribuzione
+di @command{gawk}.)
+
+@ifclear FOR_PRINT
+Chi avesse scritto una o pi@`u funzioni @command{awk} utili e di uso
+generale, e volesse metterle a disposizione della comunit@`a degli utenti di
+@command{awk}, pu@`o leggere le informazioni contenute in
+@ref{Come contribuire}.
+@end ifclear
+
+@cindex portabilit@`a, programmi di esempio
+I programmi contenuti in questo @value{CHAPTER} e in
+@ref{Programmi di esempio},
+utilizzano anche le funzionalit@`a specifiche di @command{gawk}.
+Riscrivere questi programmi per implementazioni di @command{awk} diverse
+@`e piuttosto semplice:
+
+@itemize @value{BULLET}
+@item
+I messaggi di errore diagnostici sono inviati a @file{/dev/stderr}.
+Usare @samp{| "cat 1>&2"} al posto di @samp{> "/dev/stderr"} se il sistema
+in uso non ha un @file{/dev/stderr}, o se non @`e possibile usare
+@command{gawk}.
+
+@item
+Alcuni programmi usano @code{nextfile}
+(@pxref{Istruzione nextfile})
+per evitare di leggere gli input ancora non letti dal file in input corrente.
+
+@item
+@c 12/2000: Thanks to Nelson Beebe for pointing out the output issue.
+@cindex distinzione maiuscolo/minuscolo, programmi di esempio
+@cindex @code{IGNORECASE}, variabile, nei programmi di esempio
+@cindex variabile @code{IGNORECASE}, nei programmi di esempio
+Infine, alcuni dei programmi scelgono di ignorare la distinzione tra maiuscolo e
+minuscolo nei loro input, assegnando il valore uno a @code{IGNORECASE}.
+Si pu@`o ottenere quasi lo stesso effetto@footnote{I risultati non sono identici.
+L'output del record trasformato sar@`a tutto in minuscolo, mentre
+@code{IGNORECASE} preserva il contenuto originale del record in input.}
+aggiungendo la seguente regola
+all'inizio del programma:
+
+@example
+# ignora maiuscolo/minuscolo
+@{ $0 = tolower($0) @}
+@end example
+
+@noindent
+Inoltre, si verifichi che tutte le @dfn{regexp} e le costanti
+di tipo stringa usate nei confronti utilizzano solo lettere minuscole.
+@end itemize
+
+@menu
+* Nomi di variabili di libreria:: Che nomi @`e meglio dare alle variabili
+ private globali nelle funzioni di libreria.
+* Funzioni di tipo generale:: Funzioni di uso generale.
+* Gestione File Dati:: Funzioni per gestire file-dati specificati
+ sulla riga di comando.
+* Funzione getopt:: Una funzione per trattare argomenti presenti
+ sulla riga di comando.
+* Funzioni Passwd:: Funzioni per ottenete informazioni
+ sull'utente [da /etc/passwd].
+* Funzioni Group:: Funzioni per ottenete informazioni
+ sul gruppo [da /etc/group].
+* Visitare vettori:: Una funzione per visitare vettori di vettori.
+* Sommario funzioni di libreria:: Sommario funzioni di libreria
+* Esercizi con le librerie:: Esercizi.
+@end menu
+
+@node Nomi di variabili di libreria
+@section Dare un nome a variabili globali in funzioni di libreria
+
+@cindex nomi di vettore/variabile
+@cindex nomi di funzione
+@cindex questioni sui nomi permessi
+@cindex nomi permessi, questioni sui
+@cindex programmi @command{awk}, documentazione
+@cindex documentazione, di programmi @command{awk}
+Per come si @`e sviluppato il linguaggio @command{awk}, le variabili sono
+o @dfn{globali} (usabili dall'intero programma) o @dfn{locali} (usabili solo
+in una specifica funzione). Non c'@`e uno stato intermedio analogo alle
+variabili @code{statiche} in C.
+
+@cindex variabili globali, per funzioni di libreria
+@cindex globali, variabili, per funzioni di libreria
+@cindex private, variabili
+@cindex variabili private
+Le funzioni di libreria hanno spesso necessit@`a di avere variabili globali da
+usare per conservare informazioni di stato tra successive chiamate alla
+funzione; per esempio, la variabile di @code{getopt()} @code{_opti}
+(@pxref{Funzione getopt}).
+Tali variabili vengono dette @dfn{private}, poich@'e le sole funzioni che
+devono usarle sono quelle della libreria.
+
+Quando si scrive una funzione di libreria, si dovrebbe cercare di scegliere per
+le variabili private dei nomi che non entrano in conflitto con nessuna delle
+variabili usate da un'altra funzione di libreria o dal programma principale di
+un utente. Per esempio, un nome come @code{i} o @code{j} non @`e una buona
+scelta, perch@'e i programmi a livello utente usano spesso nomi di variabile come
+questi per le proprie elaborazioni.
+
+@cindex convenzioni di programmazione, nomi di variabili private
+@cindex programmazione, convenzioni di, nomi di variabili private
+I programmi di esempio mostrati in questo @value{CHAPTER} usano per le
+loro variabili private nomi che iniziano con un trattino basso(@samp{_}).
+Generalmente gli utenti
+non usano trattini bassi iniziali nei nomi di variabile, cos@`{@dotless{i}} questa convenzione
+riduce le possibilit@`a che il nome di variabile coincida con un nome usato
+nel programma dell'utente.
+
+@cindex @code{_} (trattino basso), nei nomi di variabili private
+@cindex trattino basso (@code{_}), nei nomi di variabili private
+Inoltre, parecchie funzioni di libreria usano un prefisso che suggerisce
+quale funzione o gruppo di funzioni usa quelle variabili; per esempio,
+@code{_pw_byname()} nelle routine che consultano la lista degli utenti
+(@pxref{Funzioni Passwd}).
+L'uso di questa convenzione viene raccomandata, poich@'e riduce ulteriormente la
+possibilit@`a di conflitti accidentali tra nomi di variabile. Si noti che questa
+convenzione pu@`o anche essere usata per i nomi di variabile e per i nomi delle
+funzioni private.@footnote{Sebbene tutte le routine di libreria si sarebbero
+potute riscrivere usando questa convenzione, ci@`o non @`e stato fatto, per far
+vedere come lo stile di programmazione in @command{awk} si @`e evoluto e
+per fornire alcuni spunti per questa spiegazione.}
+
+Come nota finale sui nomi delle variabili, se una funzione rende
+disponibile una variabile globale per essere usata da un programma principale,
+@`e una buona convenzione quella di far iniziare i nomi di queste variabili con
+una lettera maiuscola; per esempio, @code{Opterr} e @code{Optind} di
+@code{getopt()}
+(@pxref{Funzione getopt}).
+La lettera maiuscola iniziale indica che la variabile @`e globale,
+mentre il fatto che
+il nome della variabile non @`e tutto in lettere maiuscole indica che la variabile
+non @`e una delle variabili predefinite di @command{awk}, come @code{FS}.
+
+@cindex @option{--dump-variables}, opzione, uso per funzioni di libreria
+@cindex opzione @option{--dump-variables}, uso per funzioni di libreria
+@`E importante anche che @emph{tutte} le variabili nelle funzioni di libreria
+che non abbiano la necessit@`a di essere
+conservate per tutta la durata del
+programma siano, di fatto, dichiarate
+come locali.@footnote{L'opzione da riga di comando di @command{gawk}
+@option{--dump-variables} @`e utile per verificare questo.} Se ci@`o non viene
+fatto, la variabile potrebbe essere usata accidentalmente nel programma
+dell'utente, conducendo a errori che sono molto difficili da scoprire:
+
+@example
+function lib_func(x, y, l1, l2)
+@{
+ @dots{}
+ # qualche_var dovrebbe essere locale ma per una svista non lo @`e
+ @var{uso della variabile} qualche_var
+ @dots{}
+@}
+@end example
+
+@cindex vettori associativi, funzioni di libreria e
+@cindex libreria di funzioni @command{awk}, vettori associativi e
+@cindex funzioni, libreria di, vettori associativi e
+@cindex Tcl
+Una differente convenzione, comune nella comunit@`a Tcl, @`e quella di usare un
+solo vettore associativo che contiene i valori necessari alle funzioni di
+libreria, o ``package.'' Questo riduce significativamente il numero degli
+effettivi nomi globali in uso. Per esempio, le funzioni descritte in
+@ref{Funzioni Passwd}
+potrebbero aver usato gli elementi di vettore
+@code{@w{PW_data["inizializzato"]}},
+@code{@w{PW_data["totale"]}}, @code{@w{PW_data["contatore"]}}, e
+@code{@w{PW_data["awklib"]}}, al posto di @code{@w{_pw_inizializzato}},
+@code{@w{_pw_totale}},
+@code{@w{_pw_awklib}} e
+@code{@w{_pw_contatore}}.
+
+Le convenzioni illustrate in questa @value{SECTION} sono esattamente
+quello che indica il termine: convenzioni. Non si @`e obbligati a scrivere
+i propri programmi in questo modo: @`e solo auspicabile che lo si faccia.
+
+@node Funzioni di tipo generale
+@section Programmazione di tipo generale
+
+Questa @value{SECTION} illustra diverse funzioni che sono di uso generale nella
+programmazione.
+
+@menu
+* Funzione strtonum:: Da usare se non @`e disponibile la funzione
+ predefinita @code{strtonum()}.
+* Funzione assert:: Una funzione per controllare affermazioni
+ in programmi @command{awk}.
+* Funzione round:: Una funzione per eseguire arrotondamenti
+ se @code{sprintf()} non lo fa correttamente.
+* Funzione random Cliff:: Il generatore Cliff di numeri casuali.
+* Funzioni ordinali:: Funzioni per usare caratteri come numeri
+ e viceversa.
+* Funzione join:: Una funzione per fondere un vettore
+ in una stringa.
+* Funzione getlocaltime:: Una funzione per ottenere data e ora nel
+ formato desiderato.
+* Funzione readfile:: Una funzione per leggere un file intero in
+ un colpo solo.
+* Apici alla shell:: Una funzione per passare stringhe
+ con apici alla shell.
+@end menu
+
+@node Funzione strtonum
+@subsection Conversione di stringhe in numeri
+
+La funzione @code{strtonum()} (@pxref{Funzioni per stringhe})
+@`e un'estensione @command{gawk}. La seguente funzione
+fornisce un'implementazione per altre versioni di @command{awk}:
+
+@example
+@c file eg/lib/strtonum.awk
+# mystrtonum --- converte stringhe in numeri
+
+@c endfile
+@ignore
+@c file eg/lib/strtonum.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# February, 2004
+# Revised June, 2014
+
+@c endfile
+@end ignore
+@c file eg/lib/strtonum.awk
+function mystrtonum(str, ret, n, i, k, c)
+@{
+ if (str ~ /^0[0-7]*$/) @{
+ # ottale
+ n = length(str)
+ ret = 0
+ for (i = 1; i <= n; i++) @{
+ c = substr(str, i, 1)
+ # index() restituisce 0 se c non @`e nella stringa,
+ # e anche se c == "0"
+ k = index("1234567", c)
+
+ ret = ret * 8 + k
+ @}
+ @} else if (str ~ /^0[xX][[:xdigit:]]+$/) @{
+ # esadecimale
+ str = substr(str, 3) # via 0x iniziale
+ n = length(str)
+ ret = 0
+ for (i = 1; i <= n; i++) @{
+ c = substr(str, i, 1)
+ c = tolower(c)
+ # index() restituisce 0 se c non @`e nella stringa,
+ # e anche se c == "0"
+ k = index("123456789abcdef", c)
+
+ ret = ret * 16 + k
+ @}
+ @} else if (str ~ \
+ /^[-+]?([0-9]+([.][0-9]*([Ee][0-9]+)?)?|([.][0-9]+([Ee][-+]?[0-9]+)?))$/) @{
+ # numero decimale, eventualmente in virgola mobile
+ ret = str + 0
+ @} else
+ ret = "NON-UN-NUMERO"
+
+ return ret
+@}
+
+# BEGIN @{ # dati per un test
+# a[1] = "25"
+# a[2] = ".31"
+# a[3] = "0123"
+# a[4] = "0xdeadBEEF"
+# a[5] = "123.45"
+# a[6] = "1.e3"
+# a[7] = "1.32"
+# a[8] = "1.32E2"
+#
+# for (i = 1; i in a; i++)
+# print a[i], strtonum(a[i]), mystrtonum(a[i])
+# @}
+@c endfile
+@end example
+
+La funzione cerca dapprima numeri ottali in stile C (base 8).
+Se la stringa in input corrisponde all'espressione regolare che descrive i
+numeri ottali, @code{mystrtonum()} esegue il ciclo per ogni carattere presente
+nella stringa. Imposta @code{k} all'indice in @code{"1234567"} della cifra
+ottale corrente.
+Il valore di ritorno sar@`a lo stesso numero della cifra, o zero
+se il carattere non c'@`e, il che succeder@`a per ogni cifra @samp{0}.
+Questo si pu@`o fare, perch@'e il test di @dfn{regexp} nell'istruzione @code{if}
+assicura che vengano scelti per
+essere convertiti solo dei numeri ottali.
+
+Una logica simile si applica al codice che ricerca e converte un
+valore esadecimale, che inizia con @samp{0x} o @samp{0X}.
+L'uso di @code{tolower()} semplifica il calcolo per trovare
+il valore numerico corretto per ogni cifra esadecimale.
+
+Infine, se la stringa corrisponde alla (piuttosto complicata) @dfn{regexp} per
+un intero decimale regolare o per un numero in virgola mobile, il calcolo
+@samp{ret = str + 0} fa s@`{@dotless{i}} che @command{awk} converta il valore in un
+numero.
+
+@`E incluso un programma di verifica commentato, in modo che la funzione possa
+essere verificata con @command{gawk} e il risultato confrontato con la funzione
+predefinita @code{strtonum()}.
+
+@node Funzione assert
+@subsection Asserzioni
+
+@cindex asserzioni
+@cindex @code{assert()}, funzione (libreria C)
+@cindex funzione @code{assert()} (libreria C)
+@cindex libreria di funzioni @command{awk}, asserzioni
+@cindex funzioni, libreria di, asserzioni
+@cindex @command{awk}, asserzioni in programmi lunghi
+Quando si scrivono grossi programmi, spesso @`e utile sapere se
+una condizione o una serie di condizioni @`e verificata oppure no.
+Prima di procedere
+con un determinato calcolo, si fa un'affermazione su cosa si crede sia
+vero. Tale affermazione @`e nota come
+@dfn{asserzione}. Il linguaggio C fornisce un file di intestazione
+@code{<assert.h>} e una corrispondente macro @code{assert()} che un
+programmatore pu@`o utilizzare per fare asserzioni.
+Se l'asserzione risulta falsa, la macro @code{assert()} predispone la
+stampa di un messaggio diagnostico che descrive la condizione che
+sarebbe dovuta essere vera ma che non lo era, e poi fa terminare
+il programma.
+In C, l'uso di @code{assert()} @`e simile a questo:
+
+@example
+#include <assert.h>
+
+int myfunc(int a, double b)
+@{
+ assert(a <= 5 && b >= 17.1);
+ @dots{}
+@}
+@end example
+
+Se l'asserzione @`e falsa, il programma stampa un messaggio simile a questo:
+
+@example
+prog.c:5: asserzione falsa: `a <= 5 && b >= 17.1'
+@end example
+
+@cindex @code{assert()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{assert()}
+Il linguaggio C rende possibile trasformare questa condizione in una stringa
+da
+usare per stampare il messaggio di diagnosi. Ci@`o in @command{awk} non @`e
+possibile, per cui la funzione @code{assert()} scritta in @command{awk}
+richiede anche una descrizione
+della condizione da verificare, in formato stringa.
+La funzione @`e la seguente:
+
+@example
+@c file eg/lib/assert.awk
+# assert --- Verifica una condizione. Se questa @`e falsa esce.
+
+@c endfile
+@ignore
+@c file eg/lib/assert.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May, 1993
+
+@c endfile
+@end ignore
+@c file eg/lib/assert.awk
+function assert(condizione, stringa)
+@{
+ if (! condizione) @{
+ printf("%s:%d: asserzione falsa: %s\n",
+ FILENAME, FNR, stringa) > "/dev/stderr"
+ _assert_exit = 1
+ exit 1
+ @}
+@}
+
+@group
+END @{
+ if (_assert_exit)
+ exit 1
+@}
+@end group
+@c endfile
+@end example
+
+La funzione @code{assert()} verifica il parametro @code{condizione}. Se
+@`e falso, stampa un messaggio sullo standard error, usando il parametro
+@code{stringa} per descrivere la condizione non verificata. Poi imposta la
+variabile @code{_assert_exit} a uno ed esegue l'istruzione @code{exit}.
+L'istruzione @code{exit} salta alla regola @code{END}. Se la regola @code{END}
+trova vera la variabile @code{_assert_exit}, esce immediatamente.
+
+Lo scopo della verifica nella regola @code{END} @`e quello di evitare che venga
+eseguita qualsiasi altra eventuale regola @code{END}.
+Quando un'asserzione non @`e
+verificata, il programma dovrebbe uscire immediatamente.
+Se nessuna asserzione
+fallisce, @code{_assert_exit} @`e ancora falso quando la regola @code{END} @`e
+eseguita normalmente, e le eventuali altre regole @code{END} del programma
+vengono eseguite.
+Affinch@'e tutto questo funzioni correttamente, @file{assert.awk} dev'essere il
+primo file sorgente che viene letto da @command{awk}.
+La funzione pu@`o essere usata in un programma nel seguente modo:
+
+@example
+function miafunz(a, b)
+@{
+ assert(a <= 5 && b >= 17.1, "a <= 5 && b >= 17.1")
+ @dots{}
+@}
+@end example
+
+@noindent
+Se l'asserzione non @`e verificata, si vedr@`a un messaggio simile a questo:
+
+@example
+mydata:1357: asserzione falsa: a <= 5 && b >= 17.1
+@end example
+
+@cindex @code{END}, criterio di ricerca, funzione definita dall'utente @code{assert()} e
+@cindex criterio di ricerca @code{END}, funzione definita dall'utente @code{assert()} e
+C'@`e un piccolo problema con questa versione di @code{assert()}.
+Come visto, una regola @code{END} viene automaticamente aggiunta al programma
+che chiama @code{assert()}. Normalmente, se un programma consiste
+solo di una regola @code{BEGIN}, i file in input e/o lo standard input non
+vengono letti. Tuttavia, ora che il programma ha una regola @code{END},
+@command{awk} tenta di leggere i @value{DF} in input o lo standard input
+(@pxref{Usare BEGIN/END}), provocando molto probabilmente la sospensione del
+programma come se rimanesse in attesa di input.
+
+@cindex @code{BEGIN}, criterio di ricerca, funzione definita dall'utente @code{assert()} e
+@cindex criterio di ricerca @code{BEGIN}, funzione definita dall'utente @code{assert()} e
+C'@`e un modo per aggirare questo problema:
+assicurarsi che la regola @code{BEGIN} termini sempre
+con un'istruzione @code{exit}.
+
+@node Funzione round
+@subsection Arrotondamento di numeri
+
+@cindex arrotondare numeri
+@cindex numeri, arrotondamento di
+@cindex libreria di funzioni @command{awk}, arrotondamento di numeri
+@cindex funzioni, libreria di, arrotondamento di numeri
+@cindex @code{print}, istruzione, funzione @code{sprintf()} e
+@cindex istruzione @code{print}, funzione @code{sprintf()} e
+@cindex @code{printf}, istruzione, funzione @code{sprintf()} e
+@cindex istruzione @code{printf}, funzione @code{sprintf()} e
+@cindex @code{sprintf()}, funzione, istruzioni @code{print}/@code{printf} e
+@cindex funzione @code{sprintf()}, istruzioni @code{print}/@code{printf} e
+Il modo in cui @code{printf} e @code{sprintf()}
+(@pxref{Printf})
+effettuano l'arrotondamento spesso dipende dalla subroutine C @code{sprintf()}
+del sistema. Su molte macchine, l'arrotondamento di @code{sprintf()} @`e
+@dfn{statistico}, il che significa che non sempre arrotonda un .5 finale per
+eccesso, contrariamente alle normali aspettative. Nell'arrotondamento
+statistico, .5 arrotonda alla cifra pari, anzich@'e sempre per eccesso, cos@`{@dotless{i}}
+1.5 arrotonda a 2 e 4.5 arrotonda a 4. Ci@`o significa che se si sta usando un
+formato che fa arrotondamenti (p.es. @code{"%.0f"}), si dovrebbe controllare
+quello che fa il sistema che si sta usando. La seguente funzione esegue un
+arrotondamento tradizionale; potrebbe essere utile nel caso in cui
+l'istruzione @code{printf}
+di @command{awk} che si sta usando faccia degli arrotondamenti statistici:
+
+@cindex @code{round()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{round()}
+@example
+@c file eg/lib/round.awk
+# round.awk --- effettua arrotondamento tradizionale
+@c endfile
+@ignore
+@c file eg/lib/round.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# August, 1996
+@c endfile
+@end ignore
+@c file eg/lib/round.awk
+
+function round(x, ival, aval, frazione)
+@{
+ ival = int(x) # parte intera, int() fa un troncamento
+
+ # vedere se c'@`e la parte frazionale
+ if (ival == x) # nessuna parte frazionale
+ return ival # nessun decimale
+
+ if (x < 0) @{
+ aval = -x # valore assoluto
+ ival = int(aval)
+ frazione = aval - ival
+ if (frazione >= .5)
+ return int(x) - 1 # -2.5 --> -3
+ else
+ return int(x) # -2.3 --> -2
+ @} else @{
+ frazione = x - ival
+ if (frazione >= .5)
+ return ival + 1
+ else
+ return ival
+ @}
+@}
+@c endfile
+@c don't include test harness in the file that gets installed
+
+# codice per testare, commentato
+# @{ print $0, round($0) @}
+@end example
+
+@node Funzione random Cliff
+@subsection Il generatore di numeri casuali Cliff
+@cindex numeri casuali, generatore Cliff
+@cindex Cliff, generatore di numeri casuali
+@cindex casuali, numeri, generatore Cliff di
+@cindex funzioni, libreria di, numeri casuali Cliff
+
+Il
+@uref{http://mathworld.wolfram.com/CliffRandomNumberGenerator.html, generatore di numeri casuali Cliff}
+@`e un generatore di numeri casuali molto semplice che ``passa il test della sfera
+del rumore per la casualit@`a non mostrando di avere alcuna struttura.''
+@`E programmato in modo molto semplice, in meno di 10 righe di codice
+@command{awk}:
+
+@cindex @code{cliff_rand()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{cliff_rand()}
+@example
+@c file eg/lib/cliff_rand.awk
+# cliff_rand.awk --- generare numeri casuali con algoritmo di Cliff
+@c endfile
+@ignore
+@c file eg/lib/cliff_rand.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# December 2000
+@c endfile
+@end ignore
+@c file eg/lib/cliff_rand.awk
+
+BEGIN @{ _cliff_seme = 0.1 @}
+
+function cliff_rand()
+@{
+ _cliff_seme = (100 * log(_cliff_seme)) % 1
+ if (_cliff_seme < 0)
+ _cliff_seme = - _cliff_seme
+ return _cliff_seme
+@}
+@c endfile
+@end example
+
+Questo algoritmo richiede un ``seme'' iniziale di 0,1. Ogni nuovo valore
+usa il seme corrente come input per il calcolo.
+Se la funzione predefinita @code{rand()}
+(@pxref{Funzioni numeriche})
+non @`e abbastanza casuale, si pu@`o tentare di usare al suo posto questa funzione.
+
+@node Funzioni ordinali
+@subsection Tradurre tra caratteri e numeri
+
+@cindex libreria di funzioni @command{awk}, valori di carattere come numeri
+@cindex funzioni, libreria di, valori di carattere come numeri
+@cindex carattere, valore come numero
+@cindex numeri, come valori di carattere
+Un'implementazione commerciale di @command{awk} fornisce una funzione
+predefinita @code{ord()}, che prende un carattere e restituisce il valore
+numerico per quel carattere nella rappresentazione dei caratteri
+di quella particolare macchina. Se la
+stringa passata a @code{ord()} ha pi@`u di un carattere, viene usato solo il
+primo.
+
+L'inverso di questa funzione @`e @code{chr()} (dalla funzione con lo stesso nome
+in Pascal), che, dato un numero, restituisce il corrispondente carattere.
+Entrambe le funzioni si possono scrivere molto bene usando @command{awk};
+non vi @`e nessun reale motivo per inglobarle come funzioni predefinite
+@command{awk}:
+
+@cindex @code{ord()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{ord()}
+@cindex @code{chr()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{chr()}
+@cindex @code{_ord_init()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{_ord_init()}
+@example
+@c file eg/lib/ord.awk
+# ord.awk --- implementa ord e chr
+
+# Identificatori globali:
+# _ord_: valori numerici indicizzati da caratteri
+# _ord_init: funzione per inizializzare _ord_
+@c endfile
+@ignore
+@c file eg/lib/ord.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# 16 January, 1992
+# 20 July, 1992, revised
+@c endfile
+@end ignore
+@c file eg/lib/ord.awk
+
+BEGIN @{ _ord_init() @}
+
+function _ord_init( basso, alto, i, t)
+@{
+ basso = sprintf("%c", 7) # BEL @`e ascii 7
+ if (basso == "\a") @{ # ascii regolare
+ basso = 0
+ alto = 127
+ @} else if (sprintf("%c", 128 + 7) == "\a") @{
+ # ascii, con il primo bit a 1 (mark)
+ basso = 128
+ alto = 255
+ @} else @{ # ebcdic(!)
+ basso = 0
+ alto = 255
+ @}
+
+ for (i = basso; i <= alto; i++) @{
+ t = sprintf("%c", i)
+ _ord_[t] = i
+ @}
+@}
+@c endfile
+@end example
+
+@cindex serie di caratteri (codifiche dei caratteri da parte della macchina)
+@cindex ASCII
+@cindex EBCDIC
+@cindex Unicode
+@cindex bit di parit@`a (in ASCII)
+@cindex @dfn{mark}, bit di parit@`a (in ASCII)
+Alcune spiegazioni riguardo ai numeri usati da @code{_ord_init()}
+non guastano.
+La serie di caratteri pi@`u importante oggi in uso @`e nota come
+ASCII.@footnote{La situazione sta per@`o
+cambiando: molti sistemi usano Unicode, una serie di caratteri molto ampia
+che comprende ASCII al suo interno.
+Nei sistemi che supportano interamente Unicode,
+un carattere pu@`o occupare fino a 32 bit, facendo diventare
+i semplici test usati qui eccessivamente complessi.}
+Sebbene un byte a
+8 bit possa contenere 256 valori distinti (da 0 a 255), ASCII definisce solo i
+caratteri che usano i valori da 0 a 127.@footnote{ASCII
+@`e stato esteso in molti paesi per usare i valori da 128 a 255 includendo
+i caratteri specifici del paese. Se il sistema in uso si avvale di queste
+estensioni, si pu@`o semplificare @code{_ord_init()} per eseguire un ciclo da
+0 a 255.} Nel lontano passato,
+almeno un produttore di microcomputer
+@c Pr1me, blech
+ha usato ASCII, ma con una parit@`a di tipo @dfn{mark}, cio@`e con il bit pi@`u a
+sinistra sempre a 1. Questo significa che su questi sistemi i caratteri
+ASCII hanno valori numerici da 128 a 255.
+Infine, i grandi elaboratori centrali usano la serie di caratteri EBCDIC, che
+prevede tutti i 256 valori.
+Ci sono altre serie di caratteri in uso su alcuni sistemi pi@`u vecchi, ma non
+vale la pena di considerarli:
+
+@example
+@c file eg/lib/ord.awk
+function ord(str, c)
+@{
+ # solo il primo carattere @`e d'interesse
+ c = substr(str, 1, 1)
+ return _ord_[c]
+@}
+
+function chr(c)
+@{
+ # trasforma c in un numero aggiungendo uno 0
+ return sprintf("%c", c + 0)
+@}
+@c endfile
+
+#### programma di verifica ####
+# BEGIN @{
+# for (;;) @{
+# printf("immetti un carattere: ")
+# if (getline var <= 0)
+# break
+# printf("ord(%s) = %d\n", var, ord(var))
+# @}
+# @}
+@c endfile
+@end example
+
+Un ovvio miglioramento a queste funzioni @`e quello di spostare il codice per la
+funzione @code{@w{_ord_init}} nel corpo della regola @code{BEGIN}.
+Il programma @`e
+stato scritto inizialmente in questo modo per comodit@`a di sviluppo.
+C'@`e un ``programma di verifica'' in una regola @code{BEGIN}, per verificare
+la funzione. @`E commentato, per poter essere eventualmente usato in produzione.
+
+@node Funzione join
+@subsection Trasformare un vettore in una sola stringa
+
+@cindex libreria di funzioni @command{awk}, trasformare vettori in stringhe
+@cindex funzioni, libreria di, trasformare vettori in stringhe
+@cindex stringhe, trasformare vettori in
+@cindex vettori, trasformare in stringhe
+Quando si fanno elaborazioni su stringhe, spesso @`e utile poter unire
+tutte le stringhe di un vettore in una lunga stringa. La funzione seguente,
+@code{join()}, svolge questo compito. Verr@`a utilizzata nel seguito in diversi
+programmi applicativi
+@iftex
+(@pxrefil{Programmi di esempio}).
+@end iftex
+@ifnottex
+(@pxref{Programmi di esempio}).
+@end ifnottex
+
+La buona progettazione di una funzione @`e importante; la funzione dev'essere
+generale, ma potrebbe anche avere un ragionevole comportamento di default.
+Viene chiamata con un vettore e anche con gli indici iniziale e finale degli
+elementi del vettore da riunire.
+Questo presuppone che gli indici del vettore
+siano numerici---una supposizione logica, dato che il vettore probabilmente @`e
+stato creato con @code{split()}
+(@pxref{Funzioni per stringhe}):
+
+@cindex @code{join()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{join()}
+@example
+@c file eg/lib/join.awk
+# join.awk --- trasforma un vettore in una stringa
+@c endfile
+@ignore
+@c file eg/lib/join.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+@c endfile
+@end ignore
+@c file eg/lib/join.awk
+
+function join(vettore, iniz, fine, separ, risultato, i)
+@{
+ if (separ == "")
+ separ = " "
+ else if (separ == SUBSEP) # valore magico
+ separ = ""
+ risultato = vettore[iniz]
+ for (i = iniz + 1; i <= fine; i++)
+ risultato = risultato separ vettore[i]
+ return risultato
+@}
+@c endfile
+@end example
+
+Un ulteriore argomento opzionale @`e il separatore da usare quando si uniscono
+nuovamente le stringhe. Se il chiamante fornisce un valore non nullo,
+@code{join()} usa quello; se non viene fornito,
+per default ha un valore nullo.
+In questo caso, @code{join()} usa uno spazio singolo come separatore
+di default
+per le stringhe. Se il valore @`e uguale a @code{SUBSEP},
+@code{join()} unisce le stringhe senza un separatore tra di esse.
+@code{SUBSEP} serve come valore ``magico'' per indicare che potrebbe non esserci
+un separatore tra le stringhe componenti.@footnote{Sarebbe bello
+se @command{awk} avesse un operatore di assegnamento per la concatenazione.
+La mancanza di un esplicito operatore per la concatenazione rende le operazioni
+sulle stringhe pi@`u difficili di quanto potrebbero essere.}
+
+@node Funzione getlocaltime
+@subsection Gestione dell'ora del giorno
+
+@cindex libreria di funzioni @command{awk}, gestire ora del giorno (marcature temporali)
+@cindex funzioni, libreria di, gestione delle ore del giorno
+@cindex data e ora, formattate
+@cindex marcature temporali, formattate
+@cindex ora del giorno, gestire
+Le funzioni @code{systime()} e @code{strftime()} descritte nella
+@ref{Funzioni di tempo}
+forniscono la funzionalit@`a minima necessaria per visualizzare l'ora del giorno
+in una forma intelligibile. Sebbene @code{strftime()} offra un'ampia gamma di
+formattazioni, i formati di controllo non sono facili da ricordare o
+intuitivamente ovvii quando si legge un programma.
+
+La seguente funzione, @code{getlocaltime()}, riempie un vettore fornito
+dall'utente con informazioni sul tempo preformattate. Restituisce una stringa
+con data e ora corrente formattata come nel programma di utilit@`a @command{date}:
+
+@cindex @code{getlocaltime()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getlocaltime()}
+@example
+@c file eg/lib/gettime.awk
+# getlocaltime.awk --- ottiene l'ora del giorno in un formato usabile
+@c endfile
+@ignore
+@c file eg/lib/gettime.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain, May 1993
+#
+@c endfile
+@end ignore
+@c file eg/lib/gettime.awk
+
+# Restituisce una stringa nel formato dell'output di date(1)
+# Riempie l'argomento del vettore time con valori individuali:
+# time["second"] -- secondi (0 - 59)
+# time["minute"] -- minuti (0 - 59)
+# time["hour"] -- ore (0 - 23)
+# time["althour"] -- ore (0 - 12)
+# time["monthday"] -- giorno del mese (1 - 31)
+# time["month"] -- mese dell'anno (1 - 12)
+# time["monthname"] -- nome del mese
+# time["shortmonth"] -- nome breve del mese
+# time["year"] -- anno modulo 100 (0 - 99)
+# time["fullyear"] -- anno completo
+# time["weekday"] -- giorno della settimana (domenica = 0)
+# time["altweekday"] -- giorno della settimana (luned@`{@dotless{i}} = 0)
+# time["dayname"] -- nome del giorno della settimana
+# time["shortdayname"] -- nome breve del giorno della settimana
+# time["yearday"] -- giorno dell'anno (0 - 365)
+# time["timezone"] -- abbreviazione del nome della zona di fuso orario
+# time["ampm"] -- designazione di AM o PM
+# time["weeknum"] -- numero della settimana, domenica primo giorno
+# time["altweeknum"] -- numero della settimana, luned@`{@dotless{i}} primmo giorno
+
+function getlocaltime(ora, ret, adesso, i)
+@{
+ # ottiene data e ora una volta sola,
+ # evitando chiamate di sistema non necessarie
+ adesso = systime()
+
+ # restituisce l'output in stile date(1)
+@c lun 8 giu 2015, 20.39.38, CEST
+@c "%a %e %b %Y , %H.%M.%S, %Z"
+ ret = strftime("%a %e %b %Y, %H.%M.%S, %Z", adesso)
+
+ # clear out target array
+ delete time
+
+ # immette i valori, forzando i valori numerici
+ # a essere numerici aggiungendo uno 0
+ time["second"] = strftime("%S", adesso) + 0
+ time["minute"] = strftime("%M", adesso) + 0
+ time["hour"] = strftime("%H", adesso) + 0
+ time["althour"] = strftime("%I", adesso) + 0
+ time["monthday"] = strftime("%d", adesso) + 0
+ time["month"] = strftime("%m", adesso) + 0
+ time["monthname"] = strftime("%B", adesso)
+ time["shortmonth"] = strftime("%b", adesso)
+ time["year"] = strftime("%y", adesso) + 0
+ time["fullyear"] = strftime("%Y", adesso) + 0
+ time["weekday"] = strftime("%w", adesso) + 0
+ time["altweekday"] = strftime("%u", adesso) + 0
+ time["dayname"] = strftime("%A", adesso)
+ time["shortdayname"] = strftime("%a", adesso)
+ time["yearday"] = strftime("%j", adesso) + 0
+ time["timezone"] = strftime("%Z", adesso)
+ time["ampm"] = strftime("%p", adesso)
+ time["weeknum"] = strftime("%U", adesso) + 0
+ time["altweeknum"] = strftime("%W", adesso) + 0
+
+ return ret
+@}
+@c endfile
+@end example
+
+Gli indici di stringa sono pi@`u facili da usare e leggere rispetto ai
+vari formati
+richiesti da @code{strftime()}. Il programma @code{alarm} illustrato in
+@ref{Programma alarm}
+usa questa funzione.
+Una progettazione pi@`u generica della funzione @code{getlocaltime()}
+avrebbe permesso all'utente di fornire un valore di data e ora
+opzionale da usare al posto della data/ora corrente.
+
+@node Funzione readfile
+@subsection Leggere un intero file in una sola volta
+
+Spesso @`e conveniente avere il contenuto di un intero file disponibile
+in memoria, visto
+come un'unica stringa. Un modo chiaro e semplice per far ci@`o potrebbe essere
+questo:
+
+@example
+function readfile(file, temp, contenuto)
+@{
+ if ((getline temp < file) < 0)
+ return
+
+ contenuto = temp
+ while (getline temp < file) > 0)
+ contenuto = contenuto RT tmp
+
+ close(file)
+ return contenuto
+@}
+@end example
+
+Questa funzione legge da @code{file} un record alla volta, ricostruendo
+l'intero contenuto del file nella variabile locale @code{contenuto}.
+Funziona, ma non @`e detto che sia efficiente.
+
+La funzione seguente, basata su un suggerimento di Denis Shirokov,
+legge l'intero contenuto del file in un colpo solo:
+
+@cindex @code{readfile()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{readfile()}
+@example
+@c file eg/lib/readfile.awk
+# readfile.awk --- legge un intero file in un colpo solo
+@c endfile
+@ignore
+@c file eg/lib/readfile.awk
+#
+# Idea originale di Denis Shirokov, cosmogen@@gmail.com, aprile 2013
+#
+@c endfile
+@end ignore
+@c file eg/lib/readfile.awk
+
+function readfile(file, temp, salva_rs)
+@{
+ salva_rs = RS
+ RS = "^$"
+ getline temp < file
+ close(file)
+ RS = salva_rs
+
+ return temp
+@}
+@c endfile
+@end example
+
+Funziona impostando @code{RS} a @samp{^$}, un'espressione regolare che
+non trova nessuna corrispondenza se il file ha un contenuto.
+@command{gawk}
+legge i dati dal file contenuto in @code{temp}, tentando di trovare una
+corrispondenza con @code{RS}.
+La ricerca dopo ogni lettura non ha mai successo, ma termina
+rapidamente, e quindi @command{gawk} inserisce in
+@code{temp} l'intero contenuto del file.
+(@xref{Record} per informazioni su @code{RT} e @code{RS}.)
+
+Se @code{file} @`e vuoto, il valore di ritorno @`e la stringa vuota.
+Quindi, il codice chiamante pu@`o usare qualcosa simile a questo:
+
+@example
+contenuto = readfile("/qualche/percorso")
+if (length(contenuto) == 0)
+ # file vuoto @dots{}
+@end example
+
+La verifica serve a determinare se il file @`e vuoto o no. Una verifica
+equivalente potrebbe essere @samp{contenuto == ""}.
+
+@xref{Esempio di estensione Readfile} per una funzione di estensione
+anch'essa finalizzata a leggere un intero file in memoria.
+
+@node Apici alla shell
+@subsection Stringhe con apici da passare alla shell
+
+@c included by permission
+@ignore
+Date: Sun, 27 Jul 2014 17:16:16 -0700
+Message-ID: <CAKuGj+iCF_obaCLDUX60aSAgbfocFVtguG39GyeoNxTFby5sqQ@mail.gmail.com>
+Subject: Useful awk function
+From: Mike Brennan <mike@madronabluff.com>
+To: Arnold Robbins <arnold@skeeve.com>
+@end ignore
+
+Michael Brennan propone il seguente modello di programma,
+da lui usato spesso:
+
+@example
+#! /bin/sh
+
+awkp='
+ @dots{}
+ '
+
+@var{specifica_programma_da_eseguire} | awk "$awkp" | /bin/sh
+@end example
+
+Per esempio, un suo programma chiamato @command{flac-edit}@footnote{I
+file con suffisso @dfn{flac} contengono normalmente dei brani musicali.
+@command{metaflac} @`e un programma che permette di modificare
+le informazioni [@dfn{metadati}] contenute all'inizio di un file di tipo
+@dfn{flac}.} ha questa forma:
+
+@example
+$ @kbd{flac-edit -song="Whoope! That's Great" file.flac}
+@end example
+
+@command{flac-edit} genera in output il seguente script, da passare alla
+shell (@file{/bin/sh}) per essere eseguito:
+
+@example
+chmod +w file.flac
+metaflac --remove-tag=TITLE file.flac
+LANG=en_US.88591 metaflac --set-tag=TITLE='Whoope! That'"'"'s Great' file.flac
+chmod -w file.flac
+@end example
+
+Si noti la necessit@`a di gestire gli apici nello script da passare alla shell.
+La funzione
+@code{shell_quote()} li prepara nel formato richiesto.
+@code{SINGLE} @`e la stringa di un solo
+carattere @code{"'"} e @code{QSINGLE} @`e la stringa di tre caratteri
+@code{"\"'\""}:
+
+@example
+@c file eg/lib/shellquote.awk
+# shell_quote --- pone tra apici un argomento da passare alla shell
+@c endfile
+@ignore
+@c file eg/lib/shellquote.awk
+#
+# Michael Brennan
+# brennan@@madronabluff.com
+# September 2014
+@c endfile
+@end ignore
+@c file eg/lib/shellquote.awk
+
+function shell_quote(s, # parametro
+ SINGLE, QSINGLE, i, X, n, ret) # variabili locali
+@{
+ if (s == "")
+ return "\"\""
+
+ SINGLE = "\x27" # apice singolo
+ QSINGLE = "\"\x27\"" # apice singolo incapsulato
+ n = split(s, X, SINGLE)
+
+ ret = SINGLE X[1] SINGLE
+ for (i = 2; i <= n; i++)
+ ret = ret QSINGLE SINGLE X[i] SINGLE
+
+ return ret
+@}
+@c endfile
+@end example
+
+@node Gestione File Dati
+@section Gestione di @value{DF}
+
+@cindex file, gestione di
+@cindex gestione di file
+@cindex libreria di funzioni @command{awk}, gestire file di dati
+@cindex funzioni, libreria di, gestire file di dati
+Questa @value{SECTION} presenta funzioni utili per gestire
+@value{DF} da riga di comando.
+
+@menu
+* Funzione filetrans:: Una funzione per gestire il passaggio da un
+ file in input al successivo.
+* Funzione rewind:: Una funzione per rileggere il file in input.
+* Controllo di file:: Controllare che i file in input siano
+ accessibili.
+* File vuoti:: Controllare se i file in input sono vuoti.
+* Ignorare assegnamenti di variabili:: Trattare assegnamenti di variabili.
+ come nomi di file.
+@end menu
+
+@node Funzione filetrans
+@subsection Trovare i limiti dei @value{DF}
+
+@cindex file, gestione di, limiti dei file-dati
+@cindex file, inizializzazione e pulizia
+Ognuna delle regole @code{BEGIN} ed @code{END} viene eseguita esattamente
+solo una volta, rispettivamente all'inizio e alla fine del programma
+@command{awk} (@pxref{BEGIN/END}).
+Una volta noi (gli autori di @command{gawk}) siamo venuti in contatto
+con un utente che
+erroneamemnte pensava che le regole @code{BEGIN} venissero eseguite all'inizio
+di ogni @value{DF} e le regole @code{END} alla fine di ogni @value{DF}.
+
+Quando lo abbiamo informato che
+non era cos@`{@dotless{i}}, ci ha chiesto di aggiungere un nuovo criterio di ricerca speciale
+a @command{gawk}, chiamato @code{BEGIN_FILE} e @code{END_FILE}, che avesse il
+comportamento desiderato. Ci ha fornito anche il codice per far questo.
+
+Non @`e stato necessario aggiungere a @command{gawk} questi criteri di ricerca
+speciali; il lavoro si pu@`o fare tranquillamente usando @command{awk}, come
+illustrato nel seguente programma di libreria. @`E strutturato in modo da
+chiamare due funzioni fornite dall'utente, @code{a_inizio_file()} e
+@code{a_fine_file()}, all'inizio e alla fine di ogni @value{DF}. Oltre a risolvere
+il problema in sole nove(!) righe di codice,
+questa soluzione @`e @emph{portabile}; il
+programma funziona con qualsiasi implementazione di @command{awk}:
+
+@example
+# transfile.awk
+#
+# Dare all'utente un aggancio per il passaggio
+# da un file in input a quello successivo
+#
+# L'utente deve fornire le funzioni a_inizio_file() ed a_fine_file()
+# ciascuna delle quali @`e invocata
+# quando il file, rispettivamente,
+# inizia e finisce.
+@c #
+@c # Arnold Robbins, arnold@@skeeve.com, Public Domain
+@c # January 1992
+
+FILENAME != _nome_file_vecchio @{
+ if (_nome_file_vecchio != "")
+ a_fine_file(_nome_file_vecchio)
+ _nome_file_vecchio = FILENAME
+ a_inizio_file(FILENAME)
+@}
+
+END @{ a_fine_file(FILENAME) @}
+@end example
+
+Questo file [transfile.awk] dev'essere caricato prima del programma
+``principale'' dell'utente,
+in modo che la regola ivi contenuta venga eseguita per prima.
+
+Questa regola dipende dalla variabile di @command{awk} @code{FILENAME}, che
+cambia automaticamente per ogni nuovo @value{DF}. Il @value{FN} corrente viene
+salvato in una variabile privata, @code{_nome_file_vecchio}. Se @code{FILENAME} non @`e
+uguale a @code{_nome_file_vecchio}, inizia l'elaborazioone di un nuovo @value{DF} ed
+@`e necessario chiamare @code{a_fine_file()} per il vecchio file. Poich@'e
+@code{a_fine_file()} dovrebbe essere chiamato solo se un file @`e stato elaborato, il
+programma esegue prima un controllo per assicurarsi che @code{_nome_file_vecchio} non
+sia la stringa nulla. Il programma assegna poi il valore corrente di
+@value{FN} a @code{_nome_file_vecchio} e chiama @code{a_inizio_file()} per il file.
+Poich@'e, come tutte le variabili di @command{awk}, @code{_nome_file_vecchio} @`e
+inizializzato alla stringa nulla, questa regola viene eseguita correttamente
+anche per il primo @value{DF}.
+
+Il programma contiene anche una regola @code{END} per completare l'elaborazione
+per l'ultimo file. Poich@'e questa regola @code{END} viene prima di qualsiasi
+regola @code{END} contenuta nel programma ``principale'',
+@code{a_fine_file()} viene
+chiamata per prima. Ancora una volta, l'utilit@`a di poter avere pi@`u regole
+@code{BEGIN} ed @code{END} dovrebbe risultare chiara.
+
+@cindex @code{a_inizio_file()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{a_inizio_file()}
+@cindex @code{a_fine_file()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{a_fine_file()}
+Se lo stesso @value{DF} compare due volte di fila sulla riga di comando,
+@code{a_fine_file()} e @code{a_inizio_file()} non vengono eseguite alla fine del primo
+passaggio e all'inizio del secondo passaggio.
+La versione seguente risolve il problema:
+
+@example
+@c file eg/lib/ftrans.awk
+# ftrans.awk --- gestisce il passaggio da un file dati al successivo
+#
+# L'utente deve fornire le funzioni a_inizio_file() ed a_fine_file()
+@c endfile
+@ignore
+@c file eg/lib/ftrans.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# November 1992
+@c endfile
+@end ignore
+@c file eg/lib/ftrans.awk
+
+FNR == 1 @{
+ if (_filename_ != "")
+ a_fine_file(_filename_)
+ _filename_ = FILENAME
+ a_inizio_file(FILENAME)
+@}
+
+END @{ a_fine_file(_filename_) @}
+@c endfile
+@end example
+
+@iftex
+La
+@end iftex
+@ref{Programma wc}
+mostra come utilizzare questa funzione di libreria e come ci@`o
+semplifichi la scrittura del programma principale.
+
+@sidebar Allora perch@'e @command{gawk} ha @code{BEGINFILE} e @code{ENDFILE}?
+
+Ci si chieder@`a, probabilmente: perch@'e, se le funzioni @code{a_inizio_file()} e
+@code{a_fine_file()} possono eseguire il compito, @command{gawk} prevede i
+criteri di
+ricerca @code{BEGINFILE} e @code{ENDFILE}?
+
+Buona domanda. Normalmente, se @command{awk} non riesce ad aprire un file,
+questo fatto
+provoca un errore fatale immediato. In tal caso, per una funzione definita
+dall'utente non vi @`e alcun modo di affrontare il problema, giacch@'e la
+chiamata verrebbe effettuata
+solo dopo aver aperto il file e letto il primo record.
+Quindi, la ragione principale di @code{BEGINFILE} @`e quella di dare un
+``aggancio'' per gestire i file che non posso essere elaborati.
+@code{ENDFILE} esiste per simmetria, e perch@'e consente facilmente
+una pulizia "file per file". Per maggiori informazioni si faccia
+riferimento alla @ref{BEGINFILE/ENDFILE}.
+@end sidebar
+
+@node Funzione rewind
+@subsection Rileggere il file corrente
+
+@cindex file, leggere un
+@cindex file, rileggere un
+Un'altra richiesta per una nuova funzione predefinita @`e stata per
+una funzione per rileggere il file corrente.
+L'utente che l'ha richiesta non voleva dover usare @code{getline}
+(@pxref{Getline})
+all'interno di un ciclo.
+
+Comunque, se non si @`e nella regola @code{END}, @`e piuttosto facile
+fare in modo di chiudere il corrente file in input immediatamente
+e ricominciare a leggerlo dall'inizio.
+In mancanza di un nome migliore, chiameremo la funzione @code{rewind()}:
+
+@cindex @code{rewind()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{rewind()}
+@example
+@c file eg/lib/rewind.awk
+# rewind.awk --- ricarica il file corrente e ricomincia a leggerlo
+@c endfile
+@ignore
+@c file eg/lib/rewind.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# September 2000
+@c endfile
+@end ignore
+@c file eg/lib/rewind.awk
+
+function rewind( i)
+@{
+ # sposta in alto i rimanenti argomenti
+ for (i = ARGC; i > ARGIND; i--)
+ ARGV[i] = ARGV[i-1]
+
+ # assicurarsi che gawk sappia raggiungerli
+ ARGC++
+
+ # fa s@`{@dotless{i}} che il file corrente sia il prossimo a essere letto
+ ARGV[ARGIND+1] = FILENAME
+
+ # do it
+ nextfile
+@}
+@c endfile
+@end example
+
+La funzione @code{rewind()} dipende dalla variabile @code{ARGIND}
+(@pxref{Variabili auto-assegnate}), che @`e specifica di @command{gawk}. Dipende anche
+dalla parola chiave @code{nextfile} (@pxref{Istruzione nextfile}).
+Perci@`o, non si dovrebbe chiamarla da una regola @code{ENDFILE}.
+(Non sarebbe peraltro necessario, perch@'e @command{gawk} legge il file
+successivo non appena la regola @code{ENDFILE} finisce!)
+
+Occorre prestare attenzione quando si chiama @code{rewind()}. Si pu@`o
+provocare una ricorsione infinita se non si sta attenti. Ecco un
+esempio di uso:
+
+@example
+$ @kbd{cat dati}
+@print{} a
+@print{} b
+@print{} c
+@print{} d
+@print{} e
+
+$ cat @kbd{test.awk}
+@print{} FNR == 3 && ! riavvolto @{
+@print{} riavvolto = 1
+@print{} rewind()
+@print{} @}
+@print{}
+@print{} @{ print FILENAME, FNR, $0 @}
+
+$ @kbd{gawk -f rewind.awk -f test.awk dati }
+@print{} data 1 a
+@print{} data 2 b
+@print{} data 1 a
+@print{} data 2 b
+@print{} data 3 c
+@print{} data 4 d
+@print{} data 5 e
+@end example
+
+@node Controllo di file
+@subsection Controllare che i @value{DF} siano leggibili
+
+@cindex risoluzione di problemi, leggibilit@`a file-dati
+@cindex leggibilit@`a, file-dati@comma{} controllare la
+@cindex file, non elaborare
+Normalmente, se si fornisce ad @command{awk} un @value{DF} che non @`e leggibile,
+il programma
+si arresta con un errore fatale. Ci sono casi in cui sarebbe preferibile
+ignorare semplicemente questi file e proseguire.@footnote{Il criterio di
+ricerca speciale @code{BEGINFILE} (@pxref{BEGINFILE/ENDFILE}) fornisce un
+meccanismo alternativo per trattare i file che non sono leggibili.
+Tuttavia, il codice qui proposto fornisce una soluzione portabile.}
+Si pu@`o far questo facendo precedere il proprio programma @command{awk} dal
+seguente programma:
+
+@cindex @code{readable.awk}, programma
+@example
+@c file eg/lib/readable.awk
+# readable.awk --- file di libreria per saltare file non leggibili
+@c endfile
+@ignore
+@c file eg/lib/readable.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# October 2000
+# December 2010
+@c endfile
+@end ignore
+@c file eg/lib/readable.awk
+
+BEGIN @{
+ for (i = 1; i < ARGC; i++) @{
+ if (ARGV[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \
+ || ARGV[i] == "-" || ARGV[i] == "/dev/stdin")
+ continue # assegnamento di variabile o standard input
+ else if ((getline aperdere < ARGV[i]) < 0) # file non leggibile
+ delete ARGV[i]
+ else
+ close(ARGV[i])
+ @}
+@}
+@c endfile
+@end example
+
+@cindex risoluzione di problemi, funzione @code{getline}
+@cindex comando @code{getline}, risoluzione di problemi
+@cindex @code{getline}, comando, risoluzione di problemi
+Questo codice funziona, perch@'e l'errore di @code{getline} non @`e fatale.
+Rimuovendo l'elemento da @code{ARGV} con @code{delete}
+si tralascia il file (perch@'e non @`e pi@`u nella lista).
+Si veda anche @ref{ARGC e ARGV}.
+
+Poich@'e per i nomi delle variabili @command{awk} si possono usare solo lettere
+dell'alfabeto inglese, di proposito il controllo con espressioni regolari
+non usa classi di
+carattere come @samp{[:alpha:]} e @samp{[:alnum:]}
+(@pxref{Espressioni tra parentesi quadre}).
+
+@node File vuoti
+@subsection Ricerca di file di lunghezza zero
+
+Tutte le implementazioni note di @command{awk} ignorano senza
+mandare alcun messaggio i file di
+lunghezza zero. Questo @`e un effetto collaterale del ciclo implicito di
+@command{awk} "leggi un record e confrontalo con le regole": quando
+@command{awk} cerca di leggere un record da un file vuoto, riceve immediatamente
+un'indicazione di fine-file [@dfn{end-of-file}], chiude il file,
+e prosegue con il
+successivo @value{DF} presente nella riga di comando, @emph{senza}
+eseguire alcun codice
+di programma @command{awk} a livello di utente.
+
+Usando la variabile @code{ARGIND} di @command{gawk}
+(@pxref{Variabili predefinite}), @`e possibile accorgersi quando un @value{DF}
+@`e stato saltato. Simile al file di libreria illustrato in
+@ref{Funzione filetrans}, il seguente file di libreria chiama una funzione
+di nome @code{zerofile()} che l'utente deve fornire. Gli argomenti passati
+sono il @value{FN} e la posizione del file in @code{ARGV}:
+
+@cindex @code{zerofile.awk}, programma
+@example
+@c file eg/lib/zerofile.awk
+# zerofile.awk --- file di libreria per elaborare file in input vuoti
+@c endfile
+@ignore
+@c file eg/lib/zerofile.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# June 2003
+@c endfile
+@end ignore
+@c file eg/lib/zerofile.awk
+
+BEGIN @{ Argind = 0 @}
+
+ARGIND > Argind + 1 @{
+ for (Argind++; Argind < ARGIND; Argind++)
+ zerofile(ARGV[Argind], Argind)
+@}
+
+ARGIND != Argind @{ Argind = ARGIND @}
+
+END @{
+ if (ARGIND > Argind)
+ for (Argind++; Argind <= ARGIND; Argind++)
+ zerofile(ARGV[Argind], Argind)
+@}
+@c endfile
+@end example
+
+La variabile definita dall'utente @code{Argind} permette al programma
+@command{awk}
+di tracciare il suo percorso all'interno di @code{ARGV}. Ogniqualvolta il
+programma rileva che @code{ARGIND} @`e maggiore di @samp{Argind + 1}, vuol dire
+che uno o pi@`u file vuoti sono stati tralasciati. L'azione chiama poi
+@code{zerofile()} per ogni file che @`e stato saltato, incrementando
+ogni volta @code{Argind}.
+
+La regola @samp{Argind != ARGIND} tiene semplicemente aggiornato @code{Argind}
+nel caso che non ci siano file vuoti.
+
+Infine, la regola @code{END} prende in considerazione il caso di un qualsiasi
+file vuoto alla fine degli argomenti nella riga di comando. Si noti che nella
+condizione del ciclo @code{for}, la verifica usa l'operatore @samp{<=}, non
+@samp{<}.
+
+@node Ignorare assegnamenti di variabili
+@subsection Trattare assegnamenti di variabile come @value{FNS}
+
+@cindex assegnamenti di variabile, visti come nomi di file
+@cindex file, nomi di, assegnamenti di variabile visti come
+@cindex nomi di file, assegnamenti di variabile visti come
+Occasionalmente, potrebbe essere pi@`u opportuno che @command{awk} non elabori gli
+assegnamenti di variabile presenti sulla riga di comando
+(@pxref{Opzioni di assegnamento}).
+In particolare, se si ha un @value{FN} che contiene un carattere @samp{=},
+@command{awk} tratta il @value{FN} come un assegnamento e non lo elabora.
+
+Alcuni utenti hanno suggerito un'opzione aggiuntiva da riga di comando per
+@command{gawk} per disabilitare gli assegnamenti dati sulla riga di comando.
+Comunque, poche righe di codice di programmazione in un file di libreria
+hanno lo stesso effetto:
+
+@cindex @code{noassign.awk}, programma
+@cindex programma @code{noassign.awk}
+@example
+@c file eg/lib/noassign.awk
+# noassign.awk --- file di libreria per evitare la necessit@`a
+# di una speciale opzione per disabilitare gli assegnamenti da
+# riga di comando
+@c endfile
+@ignore
+@c file eg/lib/noassign.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# October 1999
+@c endfile
+@end ignore
+@c file eg/lib/noassign.awk
+
+function disable_assigns(argc, argv, i)
+@{
+ for (i = 1; i < argc; i++)
+ if (argv[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/)
+ argv[i] = ("./" argv[i])
+@}
+
+BEGIN @{
+ if (Disabilita_variabili)
+ disable_assigns(ARGC, ARGV)
+@}
+@c endfile
+@end example
+
+Il programma va poi eseguito in questo modo:
+
+@example
+awk -v Disabilita_variabili=1 -f noassign.awk -f vostro_programma.awk *
+@end example
+
+La funzione esegue un ciclo che esamina ogni argomento.
+Antepone @samp{./} a
+qualsiasi argomento che abbia la forma di un assegnamento
+di variabile, trasformando cos@`{@dotless{i}} quell'argomento in un @value{FN}.
+
+L'uso di @code{Disabilita_variabili} consente di disabilitare assegnamenti di
+variabile dati sulla riga di comando al momento dell'invocazione,
+assegnando alla variabile un valore @dfn{vero}.
+Se non viene impostata la variabile @`e inizializzata a zero (cio@`e
+@dfn{falso}), e gli argomenti sulla riga di comando
+non vengono modificati.
+
+@node Funzione getopt
+@section Elaborare opzioni specificate sulla riga di comando
+
+@cindex libreria di funzioni @command{awk}, opzioni sulla riga di comando
+@cindex funzioni, libreria di, opzioni sulla riga di comando
+@cindex riga di comando, opzioni, elaborazione di
+@cindex opzioni sulla riga di comando, elaborazione di
+@cindex funzioni, libreria di, libreria C
+@cindex argomenti, elaborazione di
+La maggior parte dei programmi di utilit@`a su sistemi compatibili con POSIX
+prevedono opzioni presenti sulla riga di comando che possono essere usate per
+cambiare il modo in cui un programma si comporta. @command{awk} @`e un esempio di
+tali programmi (@pxref{Opzioni}).
+Spesso le opzioni hanno degli @dfn{argomenti} (cio@`e, dati che servono al
+programma per eseguire correttamente le opzioni specificate
+sulla riga di comando).
+Per esempio, l'opzione @option{-F} di @command{awk} richiede di usare la stringa
+specificata
+come separatore di campo. La prima occorrenza, sulla riga di comando, di
+@option{--} o di una stringa che non inizia con @samp{-} segnala la fine
+delle opzioni.
+
+@cindex @code{getopt()}, funzione (libreria C)
+@cindex funzione @code{getopt()} (libreria C)
+I moderni sistemi Unix hanno una funzione C chiamata @code{getopt()} per
+elaborare gli argomenti presenti
+sulla riga di comando. Il programmatore fornisce una
+stringa che descrive le opzioni, ognuna delle quali consiste di
+una sola lettera. Se un'opzione richiede un
+argomento, nella stringa l'opzione @`e seguita da due punti.
+A @code{getopt()} vengono anche
+passati il numero e i valori degli argomenti presenti sulla riga di comando
+e viene chiamata in un ciclo.
+@code{getopt()} scandisce gli argomenti della riga di comando cercando
+le lettere delle opzioni.
+A ogni passaggio del ciclo restituisce un carattere
+singolo che rappresenta la successiva lettera di opzione trovata, o @samp{?}
+se viene trovata un'opzione non prevista.
+Quando restituisce @minus{}1, non ci sono ulteriori
+opzioni da trattare sulla riga di comando.
+
+Quando si usa @code{getopt()}, le opzioni che non prevedono argomenti
+possono essere raggruppate.
+Inoltre, le opzioni che hanno argomenti richiedono obbligatoriamente che
+l'argomento sia specificato.
+L'argomento pu@`o seguire immediatamente la lettera
+dell'opzione, o pu@`o costituire un argomento separato sulla riga di comando.
+
+Dato un ipotetico programma che ha tre opzioni sulla riga di comando,
+@option{-a}, @option{-b} e @option{-c}, dove
+@option{-b} richiede un argomento, tutti i seguenti sono modi validi per
+invocare il programma:
+
+@example
+programma -a -b pippo -c dati1 dati2 dati3
+programma -ac -bpippo -- dati1 dati2 dati3
+programma -acbpippo dati1 dati2 dati3
+@end example
+
+Si noti che quando l'argomento @`e raggruppato con la sua opzione,
+la parte rimanente
+dell'argomento @`e considerato come argomento dell'opzione.
+In quest'esempio, @option{-acbpippo} indica che tutte le opzioni
+@option{-a}, @option{-b} e @option{-c} sono presenti,
+e che @samp{pippo} @`e l'argomento dell'opzione @option{-b}.
+
+@code{getopt()} fornisce quattro variabili esterne a disposizione del
+programmatore:
+
+@table @code
+@item optind
+L'indice nel vettore dei valori degli argomenti (@code{argv}) dove si pu@`o
+trovare il primo argomento sulla riga di comando che non sia un'opzione.
+
+@item optarg
+Il valore (di tipo stringa) dell'argomento di un'opzione.
+
+@item opterr
+Solitamente @code{getopt()} stampa un messaggio di errore quando trova un'opzione
+non valida. Impostando @code{opterr} a zero si disabilita questa funzionalit@`a.
+(un'applicazione potrebbe voler stampare un proprio messaggio di errore.)
+
+@item optopt
+La lettera che rappresenta l'opzione sulla riga di comando.
+@end table
+
+Il seguente frammento di codice C mostra come @code{getopt()} potrebbe
+elaborare gli argomenti della riga di comando per @command{awk}:
+
+@example
+int
+main(int argc, char *argv[])
+@{
+ @dots{}
+ /* stampa un appropriato messaggio */
+ opterr = 0;
+ while ((c = getopt(argc, argv, "v:f:F:W:")) != -1) @{
+ switch (c) @{
+ case 'f': /* file */
+ @dots{}
+ break;
+ case 'F': /* separatore di campo */
+ @dots{}
+ break;
+ case 'v': /* assegnamento di variabile */
+ @dots{}
+ break;
+ case 'W': /* estensione */
+ @dots{}
+ break;
+ case '?':
+ default:
+ messaggio_di_aiuto();
+ break;
+ @}
+ @}
+ @dots{}
+@}
+@end example
+
+Incidentalmente, @command{gawk} al suo interno usa la funzione GNU
+@code{getopt_long()} per elaborare sia le normali opzioni che quelle lunghe
+in stile GNU
+(@pxref{Opzioni}).
+
+L'astrazione fornita da @code{getopt()} @`e molto utile ed @`e piuttosto comoda
+anche nei programmi @command{awk}. Di seguito si riporta una versione
+@command{awk} di @code{getopt()}. Questa funzione mette in evidenza uno dei
+maggiori punti deboli di @command{awk}, che @`e quello di essere molto carente
+nella manipolazione di caratteri singoli. Sono necessarie ripetute chiamate a
+@code{substr()} per accedere a caratteri singoli.
+(@pxref{Funzioni per stringhe}).@footnote{Questa funzione
+@`e stata scritta prima che @command{gawk} acquisisse la capacit@`a di
+dividere le stringhe in caratteri singoli usando @code{""} come separatore.
+@`E stata lasciata cos@`{@dotless{i}}, poich@'e l'uso di @code{substr()} @`e pi@`u portabile.}
+
+La spiegazione della funzione viene data
+man mano che si elencano i pezzi di codice che la compongono:
+
+@cindex @code{getopt()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getopt()}
+@example
+@c file eg/lib/getopt.awk
+# getopt.awk --- imita in awk la funzione di libreria C getopt(3)
+@c endfile
+@ignore
+@c file eg/lib/getopt.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+#
+# Initial version: March, 1991
+# Revised: May, 1993
+@c endfile
+@end ignore
+@c file eg/lib/getopt.awk
+
+# Variabili esterne:
+# Optind -- indice in ARGV del primo argomento che non @`e un'opzione
+# Optarg -- valore di tipo stringa dell'argomento dell'opzione corrente
+# Opterr -- se diverso da zero, viene stampato un messaggio diagnostico
+# Optopt -- lettera dell'opzione corrente
+
+# Restituisce:
+# -1 alla fine delle opzioni
+# "?" per un'opzione non riconosciuta
+# <c> un carattere che rappresenta l'opzione corrente
+
+# Dati privati:
+# _opti -- indice in un'opzione multipla, p.es., -abc
+@c endfile
+@end example
+
+La funzione inizia con commenti che elencano e descrivono le variabili globali
+utilizzate, spiegano quali sono i valori di ritorno, il loro significato, e
+ogni altra variabile che @`e
+``esclusiva'' a questa funzione di libreria. Tale
+documentazione @`e essenziale per qualsiasi programma, e in modo particolare per
+le funzioni di libreria.
+
+La funzione @code{getopt()} dapprima controlla che sia stata effettivamente
+chiamata con una stringa di opzioni (il parametro @code{opzioni}). Se
+@code{opzioni} ha lunghezza zero, @code{getopt()} restituisce immediatamente
+@minus{}1:
+
+@cindex @code{getopt()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getopt()}
+@example
+@c file eg/lib/getopt.awk
+function getopt(argc, argv, opzioni, unaopz, i)
+@{
+ if (length(opzioni) == 0) # nessuna opzione specificata
+ return -1
+
+@group
+ if (argv[Optind] == "--") @{ # fatto tutto
+ Optind++
+ _opti = 0
+ return -1
+@end group
+ @} else if (argv[Optind] !~ /^-[^:[:space:]]/) @{
+ _opti = 0
+ return -1
+ @}
+@c endfile
+@end example
+
+Il successivo controllo cerca la fine delle opzioni. Due trattini
+(@option{--}) marcano la fine delle opzioni da riga di comando, e lo stesso
+fa qualsiasi
+argomento sulla riga di comando che non inizi con @samp{-}. @code{Optind} @`e
+usato per scorrere il vettore degli argomenti presenti sulla riga di comando;
+mantiene il suo valore attraverso chiamate successive a @code{getopt()}, perch@'e
+@`e una variabile globale.
+
+L'espressione regolare che viene usata, @code{@w{/^-[^:[:space:]/}},
+chiede di cercare un
+@samp{-} seguito da qualsiasi cosa che non sia uno spazio vuoto o un carattere
+di due punti. Se l'argomento corrente sulla riga di comando non corrisponde a
+quest'espressione regolare, vuol dire che non si tratta di un'opzione, e
+quindi viene terminata l'elaborazione delle opzioni. Continuando:
+
+@example
+@c file eg/lib/getopt.awk
+ if (_opti == 0)
+ _opti = 2
+ unaopz = substr(argv[Optind], _opti, 1)
+ Optopt = unaopz
+ i = index(opzioni, unaopz)
+ if (i == 0) @{
+ if (Opterr)
+ printf("%c -- opzione non ammessa\n", unaopz) > "/dev/stderr"
+ if (_opti >= length(argv[Optind])) @{
+ Optind++
+ _opti = 0
+ @} else
+ _opti++
+ return "?"
+ @}
+@c endfile
+@end example
+
+La variabile @code{_opti} tiene traccia della posizione nell'argomento
+della riga di comando correntemente in esame
+(@code{argv[Optind]}). Se opzioni multiple sono
+raggruppate con un @samp{-} (p.es., @option{-abx}), @`e necessario
+restituirle all'utente una per volta.
+
+Se @code{_opti} @`e uguale a zero, viene impostato a due, ossia all'indice
+nella
+stringa del successivo carattere da esaminare (@samp{-}, che @`e alla
+posizione uno viene ignorato).
+La variabile @code{unaopz} contiene il carattere,
+ottenuto con @code{substr()}. Questo @`e salvato in @code{Optopt} per essere
+usato dal programma principale.
+
+Se @code{unaopz} non @`e nella stringa delle opzioni @code{opzioni},
+si tratta di un'opzione
+non valida. Se @code{Opterr} @`e diverso da zero, @code{getopt()} stampa un
+messaggio di errore sullo @dfn{standard error} che @`e simile al messaggio
+emesso dalla versione C di @code{getopt()}.
+
+Poich@'e l'opzione non @`e valida, @`e necessario tralasciarla e passare al successivo
+carattere di opzione. Se @code{_opti} @`e maggiore o uguale alla lunghezza
+dell'argomento corrente della riga di comando, @`e necessario passare al
+successivo argomento, in modo che @code{Optind} venga incrementato e
+@code{_opti} sia reimpostato a zero. In caso contrario, @code{Optind} viene
+lasciato com'@`e e @code{_opti} viene soltanto incrementato.
+
+In ogni caso, poich@'e l'opzione non @`e valida, @code{getopt()} restituisce
+@code{"?"}. Il programma principale pu@`o esaminare @code{Optopt} se serve
+conoscere quale lettera di opzione @`e quella non valida. Proseguendo:
+
+@example
+@c file eg/lib/getopt.awk
+ if (substr(opzioni, i + 1, 1) == ":") @{
+ # ottiene un argomento di opzione
+ if (length(substr(argv[Optind], _opti + 1)) > 0)
+ Optarg = substr(argv[Optind], _opti + 1)
+ else
+ Optarg = argv[++Optind]
+ _opti = 0
+ @} else
+ Optarg = ""
+@c endfile
+@end example
+
+Se l'opzione richiede un argomento, la lettera di opzione @`e seguita da due punti
+nella stringa @code{opzioni}. Se rimangono altri caratteri nell'argomento
+corrente sulla riga di comando (@code{argv[Optind]}), il resto di quella stringa
+viene assegnato a @code{Optarg}. Altrimenti, viene usato il successivo
+argomento sulla riga di comando (@samp{-xFOO} piuttosto che
+@samp{@w{-x FOO}}). In
+entrambi i casi, @code{_opti} viene reimpostato a zero, perch@'e non ci sono altri
+caratteri da esaminare nell'argomento corrente sulla riga di comando.
+Continuando:
+
+@example
+@c file eg/lib/getopt.awk
+ if (_opti == 0 || _opti >= length(argv[Optind])) @{
+ Optind++
+ _opti = 0
+ @} else
+ _opti++
+ return unaopz
+@}
+@c endfile
+@end example
+
+Infine, se @code{_opti} @`e zero o maggiore della lunghezza dell'argomento
+corrente sulla riga di comando, significa che l'elaborazione di
+quest'elemento in @code{argv} @`e
+terminata, quindi @code{Optind} @`e incrementato per
+puntare al successivo elemento in @code{argv}. Se nessuna delle condizioni @`e
+vera, viene incrementato solo @code{_opti}, cosicch@'e la successiva lettera di
+opzione pu@`o essere elaborata con la successiva chiamata a @code{getopt()}.
+
+La regola @code{BEGIN} inizializza sia @code{Opterr} che @code{Optind} a uno.
+@code{Opterr} viene impostato a uno, perch@'e il comportamento di default per
+@code{getopt()} @`e quello di stampare un messaggio diagnostico dopo aver visto
+un'opzione non valida. @code{Optind} @`e impostato a uno, perch@'e non
+c'@`e alcun motivo
+per considerare il nome del programma, che @`e in @code{ARGV[0]}:
+
+@example
+@c file eg/lib/getopt.awk
+BEGIN @{
+ Opterr = 1 # il default @`e eseguire una diagnosi
+ Optind = 1 # salta ARGV[0]
+
+ # programma di controllo
+ if (_getopt_test) @{
+ while ((_go_c = getopt(ARGC, ARGV, "ab:cd")) != -1)
+ printf("c = <%c>, Optarg = <%s>\n",
+ _go_c, Optarg)
+ printf("argomenti che non sono opzioni:\n")
+ for (; Optind < ARGC; Optind++)
+ printf("\tARGV[%d] = <%s>\n",
+ Optind, ARGV[Optind])
+ @}
+@}
+@c endfile
+@end example
+
+Il resto della regola @code{BEGIN} @`e un semplice programma di controllo. Qui
+sotto si riportano i risultati di
+due esecuzioni di prova
+del programma di controllo:
+
+@example
+$ @kbd{awk -f getopt.awk -v _getopt_test=1 -- -a -cbARG bax -x}
+@print{} c = <a>, Optarg = <>
+@print{} c = <c>, Optarg = <>
+@print{} c = <b>, Optarg = <ARG>
+@print{} argomenti che non sono opzioni:
+@print{} ARGV[3] = <bax>
+@print{} ARGV[4] = <-x>
+
+$ @kbd{awk -f getopt.awk -v _getopt_test=1 -- -a -x -- xyz abc}
+@print{} c = <a>, Optarg = <>
+@error{} x -- opzione non ammessa
+@print{} c = <?>, Optarg = <>
+@print{} argomenti che non sono opzioni:
+@print{} ARGV[4] = <xyz>
+@print{} ARGV[5] = <abc>
+@end example
+
+In entrambe le esecuzioni, il primo @option{--} fa terminare gli argomenti dati
+ad @command{awk}, in modo che @command{awk} non tenti di interpretare le opzioni
+@option{-a}, etc. come sue opzioni.
+
+@quotation NOTA
+Dopo che @code{getopt()} @`e terminato,
+il codice a livello utente deve eliminare tutti gli elementi
+di @code{ARGV} da
+1 a @code{Optind}, in modo che @command{awk} non tenti di elaborare le opzioni
+sulla riga di comando come @value{FNS}.
+@end quotation
+
+Usare @samp{#!} con l'opzione @option{-E} pu@`o essere d'aiuto per evitare
+conflitti tra le opzioni del proprio programma e quelle di @command{gawk},
+poich@'e l'opzione @option{-E} fa s@`{@dotless{i}} che @command{gawk} abbandoni
+l'elaborazione di ulteriori opzioni.
+(@pxref{@dfn{Script} eseguibili} e
+@ifnotdocbook
+@pxref{Opzioni}).
+@end ifnotdocbook
+@ifdocbook
+@ref{Opzioni}).
+@end ifdocbook
+
+Molti degli esempi presentati in
+@ref{Programmi di esempio},
+usano @code{getopt()} per elaborare i propri argomenti.
+
+@node Funzioni Passwd
+@section Leggere la lista degli utenti
+
+@cindex libreria di funzioni @command{awk}, leggere la lista degli utenti
+@cindex funzioni, libreria di, leggera la lista degli utenti
+@cindex utenti, leggere la lista degli
+@cindex lista degli utenti@comma{} leggere la
+@cindex @code{PROCINFO}, vettore
+@cindex vettore @code{PROCINFO}
+Il vettore @code{PROCINFO}
+(@pxref{Variabili predefinite})
+d@`a accesso ai numeri ID reale ed effettivo dell'utente e del gruppo e, se
+disponibili, alla serie di gruppi ulteriori a cui l'utente appartiene.
+Comunque, poich@'e questi sono numeri, non forniscono informazioni molto utili per
+l'utente medio. Bisogna trovare un modo per reperire informazioni
+sull'utente associate con i numeri ID dell'utente e del gruppo. Questa
+@value{SECTION} illustra una raccolta di funzioni per ottenere le informazioni
+dalla lista gli utenti. @xref{Funzioni Group} per una raccolta di
+funzioni simili per ottenere informazioni dalla lista dei gruppi.
+
+@cindex @code{getpwent()}, funzione (libreria C)
+@cindex funzione @code{getpwent()} (libreria C)
+@cindex @code{getpwent()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getpwent()}
+@cindex utenti, informazioni riguardo agli, ottenere
+@cindex login, informazioni
+@cindex account, informazioni sugli
+@cindex password, file delle
+@cindex file delle password
+Lo standard POSIX non definisce il file dove sono mantenute le informazioni
+degli utenti. Invece, fornisce il file d'intestazione @code{<pwd.h>}
+e diverse @dfn{subroutine} del linguaggio C per ottenere informazioni sugli
+utenti. La funzione primaria @`e @code{getpwent()}, che sta per ``get password
+entry''. La ``password'' proviene dal file originale della lista
+degli utenti, @file{/etc/passwd}, che contiene le informazioni sugli utenti
+assieme alle password criptate (da cui il nome).@footnote{Questo @`e
+vero per le versioni pi@`u antiche di Unix. In quelle pi@`u recenti,
+la @dfn{password} di ogni utente @`e stata trasferita nel file @file{/etc/shadow},
+un file non accessibile dall'utente normale. La struttura del file
+@file{/etc/passwd} @`e rimasta la stessa, ma al posto del campo @dfn{password}
+c'@`e una @code{x}.}
+
+@cindex @command{pwcat}, programma
+Sebbene un programma @command{awk} possa semplicemente leggere
+@file{/etc/passwd} direttamente, questo file pu@`o non contenere tutte le
+informazioni su tutti gli utenti del sistema.@footnote{Capita spesso che le
+informazioni sulla password siano memorizzate in una lista in rete.} Per
+essere sicuri di poter produrre una versione leggibile e completa della banca
+dati degli utenti, @`e necessario scrivere un piccolo programma in C che chiama
+@code{getpwent()}. @code{getpwent()} viene definita in modo da restituire un
+puntatore a una @code{struct passwd}. Ogni volta che viene chiamata,
+restituisce l'elemento successivo della lista. Quando non ci sono pi@`u
+elementi, restituisce @code{NULL}, il puntatore nullo. Quando accade ci@`o, il
+programma C dovrebbe chiamare @code{endpwent()} per chiudere la lista..
+Quel che segue @`e @command{pwcat}, un programma in C che ``concatena'' la
+lista delle password:
+
+@example
+@c file eg/lib/pwcat.c
+/*
+ * pwcat.c
+ *
+ * Genera una versione stampabile della lista delle password.
+ */
+@c endfile
+@ignore
+@c file eg/lib/pwcat.c
+/*
+ * Arnold Robbins, arnold@@skeeve.com, May 1993
+ * Public Domain
+ * December 2010, move to ANSI C definition for main().
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+@c endfile
+@end ignore
+@c file eg/lib/pwcat.c
+#include <stdio.h>
+#include <pwd.h>
+
+@c endfile
+@ignore
+@c file eg/lib/pwcat.c
+#if defined (STDC_HEADERS)
+#include <stdlib.h>
+#endif
+
+@c endfile
+@end ignore
+@c file eg/lib/pwcat.c
+int
+main(int argc, char **argv)
+@{
+ struct passwd *p;
+
+ while ((p = getpwent()) != NULL)
+@c endfile
+@ignore
+@c file eg/lib/pwcat.c
+#ifdef ZOS_USS
+ printf("%s:%ld:%ld:%s:%s\n",
+ p->pw_name, (long) p->pw_uid,
+ (long) p->pw_gid, p->pw_dir, p->pw_shell);
+#else
+@c endfile
+@end ignore
+@c file eg/lib/pwcat.c
+ printf("%s:%s:%ld:%ld:%s:%s:%s\n",
+ p->pw_name, p->pw_passwd, (long) p->pw_uid,
+ (long) p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
+@c endfile
+@ignore
+@c file eg/lib/pwcat.c
+#endif
+@c endfile
+@end ignore
+@c file eg/lib/pwcat.c
+
+ endpwent();
+ return 0;
+@}
+@c endfile
+@end example
+
+Se non si conosce il linguaggio C, non @`e il caso di preoccuparsi.
+L'output di @command{pwcat} @`e la lista degli utenti, nel formato
+tradizionale del file @file{/etc/passwd} con campi separati da due punti.
+I campi sono:
+
+@table @asis
+@item Login name
+Il nome di login dell'utente.
+
+@item Encrypted password
+La password criptata dell'utente. Pu@`o non essere disponibile su alcuni sistemi.
+
+@item User-ID
+L'ID numerico dell'utente.
+(Su alcuni sistemi, @`e un numero di formato @code{long} [32bit]
+del linguaggio C, e non nel formato @code{int} [16bit].
+Quindi, lo cambieremo in @code{long} per sicurezza.)
+
+@item Group-ID
+L'ID di gruppo numerico dell'utente.
+(Valgono le stesse considerazioni su @code{long} al posto di @code{int}.)
+
+@item Full name
+Il nome completo dell'utente, e talora altre informazioni associate
+all'utente.
+
+@item Home directory
+La directory di login (o ``home'') (nota ai programmatori di shell come
+@code{$HOME}).
+
+@item Login shell
+Il programma che viene eseguito quando l'utente effettua l'accesso. Questo @`e
+comunemente una shell, come Bash.
+@end table
+
+Di seguito si riportano alcune righe di un possibile output di @command{pwcat}:
+
+@cindex Jacobs, Andrew
+@cindex Robbins, Arnold
+@cindex Robbins, Miriam
+@example
+$ @kbd{pwcat}
+@print{} root:x:0:1:Operator:/:/bin/sh
+@print{} nobody:x:65534:65534::/:
+@print{} daemon:x:1:1::/:
+@print{} sys:x:2:2::/:/bin/csh
+@print{} bin:x:3:3::/bin:
+@print{} arnold:x:2076:10:Arnold Robbins:/home/arnold:/bin/sh
+@print{} miriam:x:112:10:Miriam Robbins:/home/miriam:/bin/sh
+@print{} andy:x:113:10:Andy Jacobs:/home/andy:/bin/sh
+@dots{}
+@end example
+
+Dopo quest'introduzione, di seguito si riporta un gruppo di funzioni per
+ottenere informazioni sugli utenti. Ci sono diverse funzioni, che
+corrispondono alle omonime funzioni C:
+
+@cindex @code{_pw_init()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{_pw_init()}
+@example
+@c file eg/lib/passwdawk.in
+# passwd.awk --- accedere alle informazioni del file delle password
+@c endfile
+@ignore
+@c file eg/lib/passwdawk.in
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised October 2000
+# Revised December 2010
+@c endfile
+@end ignore
+@c file eg/lib/passwdawk.in
+
+BEGIN @{
+ # modificare per adattarlo al sistema in uso
+ _pw_awklib = "/usr/local/libexec/awk/"
+@}
+
+function _pw_init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat)
+@{
+ if (_pw_inizializzato)
+ return
+
+ oldfs = FS
+ oldrs = RS
+ olddol0 = $0
+ using_fw = (PROCINFO["FS"] == "FIELDWIDTHS")
+ using_fpat = (PROCINFO["FS"] == "FPAT")
+ FS = ":"
+ RS = "\n"
+
+ pwcat = _pw_awklib "pwcat"
+ while ((pwcat | getline) > 0) @{
+ _pw_byname[$1] = $0
+ _pw_byuid[$3] = $0
+ _pw_bycount[++_pw_totale] = $0
+ @}
+ close(pwcat)
+ _pw_contatore = 0
+ _pw_inizializzato = 1
+ FS = oldfs
+ if (using_fw)
+ FIELDWIDTHS = FIELDWIDTHS
+ else if (using_fpat)
+ FPAT = FPAT
+ RS = oldrs
+ $0 = olddol0
+@}
+@c endfile
+@end example
+
+@cindex @code{BEGIN}, criterio di ricerca, programma @code{pwcat}
+@cindex criterio di ricerca @code{BEGIN}, programma @code{pwcat}
+La regola @code{BEGIN} imposta una variabile privata col nome
+della directory in cui si
+trova @command{pwcat}.
+Poich@'e @`e destinata a essere usata da una routine di
+libreria di @command{awk}, si @`e scelto di metterla in
+@file{/usr/local/libexec/awk}; comunque, in un altro sistema potrebbe
+essere messa in una directory differente.
+
+La funzione @code{_pw_init()} mette tre copie delle informazioni sull'utente in
+tre vettori associativi. I vettori sono indicizzati per nome-utente
+(@code{_pw_byname}), per numero di ID-utente (@code{_pw_byuid}), e per ordine di
+occorrenza (@code{_pw_bycount}).
+La variabile @code{_pw_inizializzato} @`e usata per
+efficienza, poich@'e in questo modo @code{_pw_init()}
+viene chiamata solo una volta.
+
+@cindex @code{PROCINFO}, vettore, verificare la divisione in campi
+@cindex vettore @code{PROCINFO}, verificare la divisione in campi
+@cindex @code{getline}, comando, funzione definita dall'utente, @code{_pw_init()}
+@cindex comando @code{getline}, funzione definita dall'utente, @code{_pw_init()}
+Poich@'e questa funzione usa @code{getline} per leggere informazioni da
+@command{pwcat}, dapprima salva i valori di @code{FS}, @code{RS} e @code{$0}.
+Annota nella variabile @code{using_fw} se la suddivisione in campi
+usando @code{FIELDWIDTHS} @`e attiva o no.
+Far questo @`e necessario, poich@'e queste funzioni potrebbero essere chiamate da
+qualsiai parte all'interno di un programma dell'utente, e l'utente pu@`o
+suddividere i record in campi a suo piacimento.
+Ci@`o rende possibile ripristinare il corretto meccanismo di suddivisione dei
+campi in un secondo momento. La verifica pu@`o restituire solo @dfn{vero} per
+@command{gawk}.
+Il risultato pu@`o essere @dfn{falso} se si usa
+@code{FS} o @code{FPAT},
+o in qualche altra implementazione di @command{awk}.
+
+Il codice che controlla se si sta usando @code{FPAT}, utilizzando
+@code{using_fpat} e @code{PROCINFO["FS"]}, @`e simile.
+
+La parte principale della funzione usa un ciclo per leggere le righe della
+lista, suddividere le righe in campi, e poi memorizzare la riga
+all'interno di ogni vettore a seconda delle necessit@`a. Quando il ciclo @`e
+completato, @code{@w{_pw_init()}} fa pulizia chiudendo la @dfn{pipe},
+impostando @code{@w{_pw_inizializzato}} a uno, e ripristinando @code{FS}
+(e @code{FIELDWIDTHS} o @code{FPAT}
+se necessario), @code{RS} e @code{$0}.
+L'uso di @code{@w{_pw_contatore}} verr@`a spiegato a breve.
+
+@cindex @code{getpwnam()}, funzione (libreria C)
+@cindex funzione @code{getpwnam()} (libreria C)
+La funzione @code{getpwnam()} ha un nome utente come argomento di tipo
+stringa. Se
+quell'utente @`e presente nella lista, restituisce la riga appropriata.
+Altrimenti, il riferimento a un elemento inesistente del vettore
+aggiunge al vettore stesso un elemento il cui valore @`e la stringa nulla:
+
+@cindex @code{getpwnam()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getpwnam()}
+@example
+@group
+@c file eg/lib/passwdawk.in
+function getpwnam(nome)
+@{
+ _pw_init()
+ return _pw_byname[nome]
+@}
+@c endfile
+@end group
+@end example
+
+@cindex @code{getpwuid()}, funzione (libreria C)
+@cindex funzione @code{getpwuid()} (libreria C)
+In modo simile, la funzione @code{getpwuid()} ha per argomento
+il numero ID di un utente.
+Se un utente con quel numero si trova nella lista, restituisce la riga
+appropriata. Altrimenti restituisce la stringa nulla:
+
+@cindex @code{getpwuid()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getpwuid()}
+@example
+@c file eg/lib/passwdawk.in
+function getpwuid(uid)
+@{
+ _pw_init()
+ return _pw_byuid[uid]
+@}
+@c endfile
+@end example
+
+@cindex @code{getpwent()}, funzione (libreria C)
+@cindex funzione @code{getpwent()} (libreria C)
+La funzione @code{getpwent()} scorre semplicemnte la lista, un elemento
+alla volta. Usa @code{_pw_contatore} per tener traccia della posizione corrente
+nel vettore @code{_pw_bycount}:
+
+@cindex @code{getpwent()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getpwent()}
+@example
+@c file eg/lib/passwdawk.in
+function getpwent()
+@{
+ _pw_init()
+ if (_pw_contatore < _pw_totale)
+ return _pw_bycount[++_pw_contatore]
+ return ""
+@}
+@c endfile
+@end example
+
+@cindex @code{endpwent()}, funzione (libreria C)
+@cindex funzione @code{endpwent()} (libreria C)
+La funzione @code{@w{endpwent()}} reimposta @code{@w{_pw_contatore}} a zero,
+in modo che chiamate successive a @code{getpwent()} ricomincino da capo:
+
+@cindex @code{endpwent()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{endpwent()}
+@example
+@c file eg/lib/passwdawk.in
+function endpwent()
+@{
+ _pw_contatore = 0
+@}
+@c endfile
+@end example
+
+In questa serie di funzioni, il fatto che ogni subroutine chiami
+@code{@w{_pw_init()}}
+per inizializzare il vettore della lista utenti risponde a una precisa
+scelta progettuale.
+Il lavoro necessario per eseguire un processo separato che generi la
+lista degli utenti, e l'I/O per esaminarla, si ha solo se il programma
+principale dell'utente chiama effettivamente una di queste funzioni.
+Se questo
+file di libreria viene caricato assieme a un programma dell'utente, ma non
+viene mai chiamata nessuna delle routine, non c'@`e nessun lavoro aggiuntivo
+richiesto in fase di esecuzione.
+(L'alternativa @`e quella di spostare il corpo di @code{@w{_pw_init()}}
+all'interno di una regola @code{BEGIN}, che esegua sempre @command{pwcat}.
+Questo semplifica il codice ma richiede di eseguire un processo extra
+il cui risultato potrebbe non essere mai utilizzato dal programma.)
+
+A sua volta, chiamare ripetutamente @code{_pw_init()} non @`e troppo
+dispendioso, perch@'e la
+variabile @code{_pw_inizializzato} permette di evitare di leggere
+i dati relativi agli utenti pi@`u di una
+volta. Se la preoccupazione @`e quella di minimizzare il tempo di
+esecuzione del programma @command{awk},
+il controllo di @code{_pw_inizializzato} potrebbe essere spostato
+al di fuori di @code{_pw_init()} e duplicato in tutte le altre funzioni.
+In pratica, questo non @`e necessario, poich@'e la maggior parte dei
+programmi di @command{awk}
+@`e I/O-bound@footnote{I programmi si distinguono tradizionalemente in
+CPU-bound e I/O-bound. Quelli CPU-bound effettuano elaborazioni che non
+richiedono molta attivit@`a di I/O, come ad esempio la preparazione di una
+tavola di numeri primi. Quelli I/O bound leggono dei file, ma richiedono
+poca attivit@`a di elaborazione per ogni record letto.},
+e una tale modifica complicherebbe inutilmente il codice.
+
+Il programma @command{id} in @ref{Programma id}
+usa queste funzioni.
+
+@node Funzioni Group
+@section Leggere la lista dei gruppi
+
+@cindex libreria di funzioni @command{awk}, leggere la lista dei gruppi
+@cindex funzioni, libreria di, leggere la lista dei gruppi
+@cindex gruppi, lista dei, leggere la
+@cindex lista dei gruppi, leggere la
+@cindex @code{PROCINFO}, vettore, e appartenenza a gruppi
+@cindex @code{getgrent()}, funzione (libreria C)
+@cindex funzione @code{getgrent()} (libreria C)
+@cindex @code{getgrent()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getgrent()}
+@cindex gruppi@comma{} informazioni su
+@cindex account, informazioni sugli
+@cindex gruppi, file dei
+@cindex file dei gruppi
+Molto di quel che @`e stato detto
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzioni Passwd}
+vale anche per la lista dei gruppi. Sebbene questa sia tradizionalmente
+contenuta in
+un file ben noto (@file{/etc/group}) in un altrettanto noto formato,
+lo standard
+POSIX prevede solo una serie di routine della libreria C
+(@code{<grp.h>} e @code{getgrent()})
+per accedere a tali informazioni.
+Anche se il file suddetto @`e disponibile, potrebbe non contenere delle
+informazioni
+complete. Perci@`o, come per la lista degli utenti, @`e necessario avere un
+piccolo programma in C che genera la lista dei gruppi come suo output.
+@command{grcat}, un programma in C che fornisce la lista dei gruppi,
+@`e il seguente:
+
+@cindex @command{grcat}, programma C
+@cindex programma C, @command{grcat}
+@example
+@c file eg/lib/grcat.c
+/*
+ * grcat.c
+ *
+ * Genera una versione stampabile della lista dei gruppi.
+ */
+@c endfile
+@ignore
+@c file eg/lib/grcat.c
+/*
+ * Arnold Robbins, arnold@@skeeve.com, May 1993
+ * Public Domain
+ * December 2010, move to ANSI C definition for main().
+ */
+
+/* Per OS/2, non fare nulla. */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined (STDC_HEADERS)
+#include <stdlib.h>
+#endif
+
+#ifndef HAVE_GETGRENT
+int main() { return 0; }
+#else
+@c endfile
+@end ignore
+@c file eg/lib/grcat.c
+#include <stdio.h>
+#include <grp.h>
+
+int
+main(int argc, char **argv)
+@{
+ struct group *g;
+ int i;
+
+ while ((g = getgrent()) != NULL) @{
+@c endfile
+@ignore
+@c file eg/lib/grcat.c
+#ifdef ZOS_USS
+ printf("%s:%ld:", g->gr_name, (long) g->gr_gid);
+#else
+@c endfile
+@end ignore
+@c file eg/lib/grcat.c
+ printf("%s:%s:%ld:", g->gr_name, g->gr_passwd,
+ (long) g->gr_gid);
+@c endfile
+@ignore
+@c file eg/lib/grcat.c
+#else
+ printf("%s:*:%ld:", g->gr_name, (long) g->gr_gid);
+#endif
+@c endfile
+@end ignore
+@c file eg/lib/grcat.c
+ for (i = 0; g->gr_mem[i] != NULL; i++) @{
+ printf("%s", g->gr_mem[i]);
+@group
+ if (g->gr_mem[i+1] != NULL)
+ putchar(',');
+ @}
+@end group
+ putchar('\n');
+ @}
+ endgrent();
+ return 0;
+@}
+@c endfile
+@ignore
+@c file eg/lib/grcat.c
+#endif /* HAVE_GETGRENT */
+@c endfile
+@end ignore
+@end example
+
+Ciascuna riga nella lista dei gruppi rappresenta un gruppo. I campi sono
+separati da due punti e rappresentano le seguenti informazioni:
+
+@table @asis
+@item Nome del gruppo
+Il nome del gruppo.
+
+@item Password del gruppo
+La password del gruppo criptata. In pratica, questo campo non viene mai usato;
+normalmente @`e vuoto o impostato a @samp{x}.
+
+@item Numero ID del gruppo
+Il numero ID del gruppo in formato numerico;
+l'associazione del nome al numero dev'essere univoca all'interno di questo file.
+(Su alcuni sistemi, @`e un numero nel formato @code{long} [32bit]
+del linguaggio C, e non nel formato @code{int} [16bit].
+Quindi, lo cambieremo in @code{long} per sicurezza.)
+
+@item Lista dei membri del gruppo
+Una lista di nomi utente separati da virgole.
+Questi utenti sono i membri del gruppo.
+I sistemi Unix moderni consentono agli utenti di appartenere a
+diversi gruppi simultaneamente. Se il sistema in uso @`e uno di questi, ci sono
+elementi in @code{PROCINFO} che vanno da @code{"group1"} fino a
+@code{"group@var{N}"} per quei numeri di ID di gruppo.
+(Si noti che @code{PROCINFO} @`e un'estensione @command{gawk};
+@pxref{Variabili predefinite}.)
+@end table
+
+Di seguito si riporta quel che @command{grcat} potrebbe produrre:
+
+@example
+$ @kbd{grcat}
+@print{} wheel:x:0:arnold
+@print{} nogroup:x:65534:
+@print{} daemon:x:1:
+@print{} kmem:x:2:
+@print{} staff:x:10:arnold,miriam,andy
+@print{} other:x:20:
+@dots{}
+@end example
+
+Qui ci sono le funzioni per ottenere informazioni relative alla lista dei
+gruppi. Ce ne sono diverse, costruite sul modello delle omonime funzioni della
+libreria C:
+
+@cindex @code{getline}, comando, funzione definita dall'utente, @code{_gr_init()}
+@cindex comando @code{getline}, funzione definita dall'utente, @code{_gr_init()}
+@cindex @code{_gr_init()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{_gr_init()}
+@example
+@c file eg/lib/groupawk.in
+# group.awk --- funzioni per il trattamento del file dei gruppi
+@c endfile
+@ignore
+@c file eg/lib/groupawk.in
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised October 2000
+# Revised December 2010
+@c endfile
+@end ignore
+@c line break on _gr_init for smallbook
+@c file eg/lib/groupawk.in
+
+BEGIN @{
+ # Modificare in base alla struttura del proprio sistema
+ _gr_awklib = "/usr/local/libexec/awk/"
+@}
+
+function _gr_init( oldfs, oldrs, olddol0, grcat,
+ using_fw, using_fpat, n, a, i)
+@{
+ if (_gr_inizializzato)
+ return
+
+ oldfs = FS
+ oldrs = RS
+ olddol0 = $0
+ using_fw = (PROCINFO["FS"] == "FIELDWIDTHS")
+ using_fpat = (PROCINFO["FS"] == "FPAT")
+ FS = ":"
+ RS = "\n"
+
+ grcat = _gr_awklib "grcat"
+ while ((grcat | getline) > 0) @{
+ if ($1 in _gr_byname)
+ _gr_byname[$1] = _gr_byname[$1] "," $4
+ else
+ _gr_byname[$1] = $0
+ if ($3 in _gr_bygid)
+ _gr_bygid[$3] = _gr_bygid[$3] "," $4
+ else
+ _gr_bygid[$3] = $0
+
+ n = split($4, a, "[ \t]*,[ \t]*")
+ for (i = 1; i <= n; i++)
+ if (a[i] in _gr_groupsbyuser)
+ _gr_groupsbyuser[a[i]] = _gr_groupsbyuser[a[i]] " " $1
+ else
+ _gr_groupsbyuser[a[i]] = $1
+
+ _gr_bycount[++_gr_contatore] = $0
+ @}
+ close(grcat)
+ _gr_contatore = 0
+ _gr_inizializzato++
+ FS = oldfs
+ if (using_fw)
+ FIELDWIDTHS = FIELDWIDTHS
+ else if (using_fpat)
+ FPAT = FPAT
+ RS = oldrs
+ $0 = olddol0
+@}
+@c endfile
+@end example
+
+La regola @code{BEGIN} imposta una variabile privata con il nome della
+directory in cui si trova @command{grcat}.
+Poich@'e @`e destinata a essere usata da una routine di
+libreria di @command{awk}, si @`e scelto di metterla in
+@file{/usr/local/libexec/awk}; comunque, in un altro sistema potrebbe
+essere messa in una directory differente.
+
+Queste routine seguono le stesse linee generali delle routine per formare la
+lista degli utenti (@pxref{Funzioni Passwd}).
+La variabile @code{@w{_gr_inizializzato}} @`e usata per
+essere sicuri che la lista venga letta una volta sola.
+La funzione @code{@w{_gr_init()}} dapprima salva @code{FS},
+@code{RS} e
+@code{$0}, e poi imposta @code{FS} e @code{RS} ai valori da usare nel
+passare in rassegna le informazioni di gruppo. Inoltre
+viene annotato se si stanno usando @code{FIELDWIDTHS} o @code{FPAT}, per
+poter poi
+ripristinare il meccanismo di suddivisione in campi appropriato.
+
+Le informazioni sui gruppi sono memorizzate in diversi vettori associativi.
+I vettori sono indicizzati per nome di gruppo (@code{@w{_gr_byname}}), per
+numero ID del gruppo (@code{@w{_gr_bygid}}), e per posizione nella lista
+(@code{@w{_gr_bycount}}). C'@`e un vettore aggiuntivo indicizzato per nome utente
+(@code{@w{_gr_groupsbyuser}}), che @`e una lista, separata da spazi, dei
+gruppi ai quali ciascun utente appartiene.
+
+Diversamente dalla lista degli utenti, @`e possibile avere pi@`u record
+nella lista per lo stesso gruppo. Questo @`e frequente quando un gruppo ha
+un gran numero di membri. Un paio di tali voci potrebbero essere come queste:
+
+@example
+tvpeople:x:101:johnny,jay,arsenio
+tvpeople:x:101:david,conan,tom,joan
+@end example
+
+Per questo motivo, @code{_gr_init()} controlla se un nome di gruppo o un numero
+di ID di gruppo @`e stato gi@`a visto. Se cos@`{@dotless{i}} fosse, i nomi utente vanno
+semplicemente concatenati con la precedente lista di utenti.@footnote{C'@`e un
+piccolo problema col codice appena illustrato. Supponiamo che la prima volta
+non ci siano nomi. Questo codice aggiunge i nomi con una virgola iniziale.
+Inoltre non controlla che ci sia un @code{$4}.}
+
+Infine, @code{_gr_init()} chiude la @dfn{pipe} a @command{grcat}, ripristina
+@code{FS} (e @code{FIELDWIDTHS} o @code{FPAT}, se necessario), @code{RS} e
+@code{$0}, inizializza @code{_gr_contatore} a zero
+(per essere usato pi@`u tardi), e rende @code{_gr_inizializzato} diverso da zero.
+
+@cindex @code{getgrnam()}, funzione (libreria C)
+@cindex funzione @code{getgrnam()} (libreria C)
+La funzione @code{getgrnam()} ha come argomento un nome di gruppo, e se quel
+gruppo esiste, viene restituito.
+
+Altrimenti, il riferimento a un elemento inesistente del vettore
+aggiunge al vettore stesso un elemento il cui valore @`e la stringa nulla:
+
+@cindex @code{getgrnam()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getgrnam()}
+@example
+@c file eg/lib/groupawk.in
+function getgrnam(group)
+@{
+ _gr_init()
+ return _gr_byname[group]
+@}
+@c endfile
+@end example
+
+@cindex @code{getgrgid()}, funzione (libreria C)
+@cindex funzione @code{getgrgid()} (libreria C)
+La funzione @code{getgrgid()} @`e simile; ha come argomento un numero ID di
+gruppo e controlla le informazioni assiciate con quell'ID di gruppo:
+
+@cindex @code{getgrgid()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getgrgid()}
+@example
+@c file eg/lib/groupawk.in
+function getgrgid(gid)
+@{
+ _gr_init()
+ return _gr_bygid[gid]
+@}
+@c endfile
+@end example
+
+@cindex @code{getgruser()}, funzione (libreria C)
+@cindex funzione @code{getgruser()} (libreria C)
+La funzione @code{getgruser()} non ha un equivalente in C. Ha come argomento un
+nome-utente e restituisce l'elenco dei gruppi di cui l'utente @`e membro:
+
+@cindex @code{getgruser()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getgruser()}
+@example
+@c file eg/lib/groupawk.in
+function getgruser(user)
+@{
+ _gr_init()
+ return _gr_groupsbyuser[user]
+@}
+@c endfile
+@end example
+
+@cindex @code{getgrent()}, funzione (libreria C)
+@cindex funzione @code{getgrent()} (libreria C)
+La funzione @code{getgrent()} scorre la lista un elemento alla volta.
+Usa @code{_gr_contatore} per ricordare la posizione corrente nella lista:
+
+@cindex @code{getgrent()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{getgrent()}
+@example
+@c file eg/lib/groupawk.in
+function getgrent()
+@{
+ _gr_init()
+ if (++_gr_contatore in _gr_bycount)
+ return _gr_bycount[_gr_contatore]
+ return ""
+@}
+@c endfile
+@end example
+
+@cindex @code{endgrent()}, funzione (libreria C)
+@cindex funzione @code{endgrent()} (libreria C)
+La funzione @code{endgrent()} reimposta @code{_gr_contatore} a zero in modo che
+@code{getgrent()} possa ricominciare da capo:
+
+@cindex @code{endgrent()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{endgrent()}
+@example
+@c file eg/lib/groupawk.in
+function endgrent()
+@{
+ _gr_contatore = 0
+@}
+@c endfile
+@end example
+
+Come con le routine per la lista degli utenti, ogni funzione chiama
+@code{_gr_init()} per inizializzare i vettori.
+Cos@`{@dotless{i}} facendo si avr@`a il solo
+lavoro aggiuntivo di eseguire @command{grcat} se queste funzioni vengono
+usate (rispetto a spostare il corpo di @code{_gr_init()} all'interno della
+regola @code{BEGIN}).
+
+La maggior parte del lavoro consiste nell'ispezionare la lista e nel
+costruire i vari vettori associativi. Le funzioni che l'utente chiama sono
+di per s@'e molto semplici, poich@'e si appoggiano sui vettori associativi di
+@command{awk} per fare il lavoro.
+
+Il programma @command{id} in @ref{Programma id}
+usa queste funzioni.
+
+@node Visitare vettori
+@section Attraversare vettori di vettori
+
+@iftex
+La
+@end iftex
+@ref{Vettori di vettori} trattava come @command{gawk}
+avere a disposizione vettori di vettori. In particolare, qualsiasi elemento di
+un vettore pu@`o essere uno scalare o un altro vettore. La funzione
+@code{isarray()} (@pxref{Funzioni per i tipi})
+permette di distinguere un vettore
+da uno scalare.
+La seguente funzione, @code{walk_array()}, attraversa ricorsivamente
+un vettore, stampando gli indici e i valori di ogni elemento.
+Viene chiamata col vettore e con una stringa che contiene il nome
+del vettore:
+
+@cindex @code{walk_array()}, funzione definita dall'utente
+@cindex funzione definita dall'utente, @code{walk_array()}
+@example
+@c file eg/lib/walkarray.awk
+function walk_array(vett, nome, i)
+@{
+ for (i in vett) @{
+ if (isarray(vett[i]))
+ walk_array(vett[i], (nome "[" i "]"))
+ else
+ printf("%s[%s] = %s\n", nome, i, vett[i])
+ @}
+@}
+@c endfile
+@end example
+
+@noindent
+Funziona eseguendo un ciclo su ogni elemento del vettore. Se un dato elemento
+@`e esso stesso un vettore, la funzione chiama s@'e stessa ricorsivamente,
+passando il sottovettore e una nuova stringa che rappresenta l'indice corrente.
+In caso contrario, la funzione stampa semplicemente il nome, l'indice e il
+valore dell'elemento.
+Qui di seguito si riporta un programma principale che ne mostra l'uso:
+
+@example
+BEGIN @{
+ a[1] = 1
+ a[2][1] = 21
+ a[2][2] = 22
+ a[3] = 3
+ a[4][1][1] = 411
+ a[4][2] = 42
+
+ walk_array(a, "a")
+@}
+@end example
+
+Quando viene eseguito, il programma produce il seguente output:
+
+@example
+$ @kbd{gawk -f walk_array.awk}
+@print{} a[1] = 1
+@print{} a[2][1] = 21
+@print{} a[2][2] = 22
+@print{} a[3] = 3
+@print{} a[4][1][1] = 411
+@print{} a[4][2] = 42
+@end example
+
+La funzione appena illustrata stampa semplicemente il nome e il valore
+di ogni elemento costituito da un vettore scalare. Comunque @`e facile
+generalizzarla, passandole il nome di una funzione da chiamare
+quando si attraversa un vettore. La funzione modificata @`e simile a questa:
+
+@example
+@c file eg/lib/processarray.awk
+function process_array(vett, nome, elab, do_arrays, i, nuovo_nome)
+@{
+ for (i in vett) @{
+ nuovo_nome = (nome "[" i "]")
+ if (isarray(vett[i])) @{
+ if (do_arrays)
+ @@elab(nuovo_nome, vett[i])
+ process_array(vett[i], nuovo_nome, elab, do_arrays)
+ @} else
+ @@elab(nuovo_nome, vett[i])
+ @}
+@}
+@c endfile
+@end example
+
+Gli argomenti sono i seguenti:
+
+@table @code
+@item vett
+Il vettore.
+
+@item nome
+Il nome del vettore (una stringa).
+
+@item elab
+Il nome della funzione da chiamare.
+
+@item do_arrays
+Se vale @dfn{vero}, la funzione pu@`o gestire elementi che sono sottovettori.
+@end table
+
+Se devono essere elaborati sottovettori, questo vien fatto prima di
+attraversarne altri.
+
+Quando viene eseguita con la seguente struttura, la funzione produce lo stesso
+risultato della precedente versione di @code{walk_array()}:
+
+@example
+BEGIN @{
+ a[1] = 1
+ a[2][1] = 21
+ a[2][2] = 22
+ a[3] = 3
+ a[4][1][1] = 411
+ a[4][2] = 42
+
+ process_array(a, "a", "do_print", 0)
+@}
+
+function do_print(nome, elemento)
+@{
+ printf "%s = %s\n", nome, elemento
+@}
+@end example
+
+@node Sommario funzioni di libreria
+@section Riassunto
+
+@itemize @value{BULLET}
+@item
+Leggere i programmi @`e un eccellente metodo per imparare la "buona
+programmazione". Le funzioni e i programmi contenuti in questo @value{CHAPTER}
+e nel successivo si propongo questo obiettivo.
+
+@item
+Quando si scrivono funzioni di libreria di uso generale, si deve stare attenti
+ai nomi da dare alle variabili globali, facendo in modo che non entrino in
+conflitto con le variabili di un programma dell'utente.
+
+@item
+Le funzioni descritte qui appartengono alle seguenti categorie:
+
+@c nested list
+@table @asis
+@item Problemi generali
+Conversione di numeri in stringhe, verifica delle asserzioni, arrotondamenti,
+generazione di numeri casuali, conversione di caratteri in numeri, unione di
+stringhe, ottenimento di informazioni su data e ora facilmente usabili,
+e lettura di un intero file in una volta sola
+
+@item Gestione dei @value{DF}
+Annotazione dei limiti di un @value{DF}, rilettura del file corrente,
+ricerca di
+file leggibili, ricerca di file di lunghezza zero, e trattamento degli
+assegnamenti di variabili fatti sulla riga comando come @value{FNS}
+
+@item Elaborazione di opzioni sulla riga di comando
+Una versione @command{awk} della funzione del C standard @code{getopt()}
+
+@item Lettura dei file degli utenti e dei gruppi
+Due serie di routine equivalenti alle versioni disponibili nella libreria
+del linguaggio C
+
+@item Attraversamento di vettori di vettori
+Due funzioni che attraversano un vettore di vettori fino in fondo
+@end table
+@c end nested list
+
+@end itemize
+
+@c EXCLUDE START
+@node Esercizi con le librerie
+@section Esercizi
+
+@enumerate
+@item
+@iftex
+Nella
+@end iftex
+@ifnottex
+In
+@end ifnottex
+@ref{File vuoti}, abbiamo illustrato il programma @file{zerofile.awk},
+che fa uso della variabile di @command{gawk} @code{ARGIND}. Questo problema pu@`o
+essere risolto senza dipendere da @code{ARGIND}? Se s@`{@dotless{i}}, come?
+
+@ignore
+# zerofile2.awk --- same thing, portably
+
+BEGIN @{
+ ARGIND = Argind = 0
+ for (i = 1; i < ARGC; i++)
+ Fnames[ARGV[i]]++
+
+@}
+FNR == 1 @{
+ while (ARGV[ARGIND] != FILENAME)
+ ARGIND++
+ Seen[FILENAME]++
+ if (Seen[FILENAME] == Fnames[FILENAME])
+ do
+ ARGIND++
+ while (ARGV[ARGIND] != FILENAME)
+@}
+ARGIND > Argind + 1 @{
+ for (Argind++; Argind < ARGIND; Argind++)
+ zerofile(ARGV[Argind], Argind)
+@}
+ARGIND != Argind @{
+ Argind = ARGIND
+@}
+END @{
+ if (ARGIND < ARGC - 1)
+ ARGIND = ARGC - 1
+ if (ARGIND > Argind)
+ for (Argind++; Argind <= ARGIND; Argind++)
+ zerofile(ARGV[Argind], Argind)
+@}
+@end ignore
+
+@item
+Come esercizio collegato, rivedere quel codice per gestire il caso in cui un
+valore contenuto in @code{ARGV} sia un assegnamento di variabile.
+
+@ignore
+@c June 13 2015: Antonio points out that this is answered in the text. Ooops.
+@item
+@ref{Visitare vettori} ha illustrato una funzione che ispezionava un vettore
+multidimensionale per stamparlo. Comunque, ispezionare un vettore ed elaborare
+ogni elemento @`e un'operazione generica. Generalizzare la funzione
+@code{walk_array()} agggiungendo un parametro aggiuntivo chiamato
+@code{elab}.
+
+Quindi, all'interno del ciclo, invece di stampare l'indice e il valore
+dell'elemento del vettore, usare la sintassi della chiamata indiretta a una
+funzione (@pxref{Chiamate indirette})
+su @code{elab}, passandole l'indice e il valore.
+
+Nel chiamare @code{walk_array()}, si passa il nome di una
+funzione definita dall'utente che aspetta di ricevere un indice e un valore
+per poi elaborare l'elemento.
+
+Verificare la nuova versione stampando il vettore; si dovrebbe ottenere un
+output identico a quello della versione originale.
+@end ignore
+
+@end enumerate
+@c EXCLUDE END
+
+@node Programmi di esempio
+@chapter Programmi utili scritti in @command{awk}
+@cindex @command{awk}, programmi, esempi di
+@cindex programmi @command{awk}, esempi di
+@cindex esempi di programmi @command{awk}
+
+@c FULLXREF ON
+@iftex
+Il
+@end iftex
+@ref{Funzioni di libreria},
+ha prospettato l'idea che la lettura di programmi scritti in un certo
+linguaggio possa aiutare a imparare quel linguaggio. Questo
+@value{CHAPTER} ripropone lo stesso tema, presentando una miscellanea di
+programmi @command{awk} per il piacere di leggerli.
+@c FULLXREF OFF
+@ifnotinfo
+Ci sono tre @value{SECTIONS}.
+La prima spiega come eseguire i programmi descritti in questo
+@value{CHAPTER}.
+
+La seconda illustra la versione @command{awk}
+di parecchi comuni programmi di utilit@`a disponibili in POSIX.
+Si presuppone che si abbia gi@`a una certa familiarit@`a con questi programmi,
+e che quindi i problemi a loro legati siano facilmente comprensibili.
+Riscrivendo questi programmi in @command{awk},
+ci si pu@`o focalizzare sulle particolarit@`a di @command{awk} nella
+risoluzione dei problemi di programmazione.
+
+La terza sezione @`e una collezione di programmi interessanti.
+Essi mirano a risolvere un certo numero di differenti problemi di
+manipolazione e di gestione dati. Molti dei programmi sono brevi, per
+evidenziare la capacit@`a di @command{awk} di fare molte cose usando solo
+poche righe di codice.
+@end ifnotinfo
+
+Molti di questi programmi usano le funzioni di libreria che sono state presentate
+@iftex
+nel
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzioni di libreria}.
+
+@menu
+* Eseguire esempi:: Come eseguire questi esempi.
+* Cloni:: Cloni di programmi di utilit@`a comuni.
+* Programmi vari:: Alcuni interessanti programmi in
+ @command{awk}.
+* Sommario dei programmi:: Sommario dei programmi.
+* Esercizi sui programmi:: Esercizi.
+@end menu
+
+@node Eseguire esempi
+@section Come eseguire i programmi di esempio.
+
+
+Per eseguire un dato programma, si procederebbe tipicamente cos@`{@dotless{i}}:
+
+@example
+awk -f @var{programma} -- @var{opzioni} @var{file}
+@end example
+
+@noindent
+Qui, @var{programma} @`e il nome del programma @command{awk} (p.es.
+@file{cut.awk}), @var{opzioni} sono le opzioni sulla riga di comando
+per il programma che iniziano con un @samp{-}, e @var{file} sono i
+@value{DF} in input.
+
+Se il sistema prevede il meccanismo @samp{#!} di specifica di un
+@dfn{interprete}
+(@pxref{@dfn{Script} eseguibili}),
+si pu@`o invece eseguire direttamente un programma:
+
+@example
+cut.awk -c1-8 i_miei_file > risultati
+@end example
+
+Se @command{awk} non @`e @command{gawk}, pu@`o invece essere necessario usare:
+
+@example
+cut.awk -- -c1-8 i_miei_file > risultati
+@end example
+
+@node Cloni
+@section Reinventare la ruota per divertimento e profitto
+@cindex programmi POSIX, implementazione in @command{awk}
+@cindex POSIX, programmi, implementazione in @command{awk}
+
+Questa @value{SECTION} presenta un certo numero di programmi di utilit@`a
+POSIX implementati in @command{awk}. Riscrivere questi programmi in
+@command{awk} @`e spesso divertente,
+perch@'e gli algoritmi possono essere espressi molto chiaramente, e il codice
+@`e normalmente molto semplice e conciso. Ci@`o @`e possibile perch@'e @command{awk}
+facilita molto le cose al programmatore.
+
+Va precisato che questi programmi non sono necessariamente scritti per
+sostituire le versioni installate sul sistema in uso.
+Inoltre, nessuno di questi programmi @`e del tutto aderente ai pi@`u recenti
+standard POSIX. Questo non @`e un problema; il loro scopo
+@`e di illustrare la programmazione in linguaggio @command{awk} che serve nel
+``mondo reale''.
+
+I programmi sono presentati in ordine alfabetico.
+
+@menu
+* Programma cut:: Il programma di utilit@`a @command{cut}.
+* Programma egrep:: Il programma di utilit@`a @command{egrep}.
+* Programma id:: Il programma di utilit@`a @command{id}.
+* Programma split:: Il programma di utilit@`a @command{split}.
+* Programma tee:: Il programma di utilit@`a @command{tee}.
+* Programma uniq:: Il programma di utilit@`a @command{uniq}.
+* Programma wc:: Il programma di utilit@`a @command{wc}.
+@end menu
+
+@node Programma cut
+@subsection Ritagliare campi e colonne
+
+@cindex @command{cut}, programma di utilit@`a
+@cindex programma di utilit@`a @command{cut}
+@cindex campi, ritagliare
+@cindex colonne, ritagliare
+Il programma di utilit@`a @command{cut} seleziona, o ``taglia'' (@dfn{cut}),
+caratteri o campi dal suo standard input e li
+spedisce al suo standard output.
+I campi sono separati da caratteri TAB per default,
+ma @`e possibile fornire un'opzione dalla riga di comando per cambiare il campo
+@dfn{delimitatore} (cio@`e, il carattere che separa i campi). La definizione di
+campo di @command{cut} @`e meno generale di quella di @command{awk}.
+
+Un uso comune del comando @command{cut} potrebbe essere quello di estrarre
+i nomi degli utenti correntemente collegati al sistema, a partire
+dall'output del comando @command{who}. Per esempio, la seguente
+pipeline genera una lista in ordine alfabetico, senza doppioni, degli utenti
+correntemente collegati al sistema:
+
+@example
+who | cut -c1-8 | sort | uniq
+@end example
+
+Le opzioni per @command{cut} sono:
+
+@table @code
+@item -c @var{lista}
+Usare @var{lista} come lista di caratteri da ritagliare. Elementi
+all'interno della lista
+possono essere separati da virgole, e intervalli di caratteri possono essere
+separated da trattini. La lista
+@samp{1-8,15,22-35} specifica i caratteri da 1 a 8, 15, e da 22 a 35.
+
+@item -f @var{lista}
+Usare @var{lista} come lista di campi da ritagliare.
+
+@item -d @var{delimitatore}
+Usare @var{delimitatore} come carattere che separa i campi invece del
+carattere TAB.
+
+@item -s
+Evita la stampa di righe che non contengono il delimitatore di campo.
+@end table
+
+L'implementazione @command{awk} del comando @command{cut} usa la funzione
+di libreria @code{getopt()}
+(@pxref{Funzione getopt})
+e la funzione di libreria @code{join()}
+(@pxref{Funzione join}).
+
+Il programma inizia con un commento che descrive le opzioni, le funzioni
+di libreria necessarie, e una funzione @code{sintassi()} che stampa un
+messaggio ed esce. @code{sintassi()} @`e chiamato se si specificano degli
+argomenti non validi:
+
+@cindex @code{cut.awk}, programma
+@cindex programma @code{cut.awk}
+@example
+@c file eg/prog/cut.awk
+# cut.awk --- implementa cut in awk
+@c endfile
+@ignore
+@c file eg/prog/cut.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+@c endfile
+@end ignore
+@c file eg/prog/cut.awk
+
+# Opzioni:
+# -f lista Ritagliare campi
+# -d c Carattere di delimitazione di campo
+# -c lista Ritagliare caratteri
+#
+# -s Sopprimere righe che non contengono il delimitatore
+#
+# Richiede le funzioni di libreria getopt() e join()
+
+@group
+function sintassi()
+@{
+ print("sintassi: cut [-f lista] [-d c] [-s] [file...]") > "/dev/stderr"
+ print("sintassi: cut [-c lista] [file...]") > "/dev/stderr"
+ exit 1
+@}
+@end group
+@c endfile
+@end example
+
+@cindex @code{BEGIN}, criterio di ricerca, eseguire programmi @command{awk} e
+@cindex criterio di ricerca @code{BEGIN}, eseguire programmi @command{awk} e
+@cindex @code{FS}, variabile, eseguire programmi @command{awk} e
+@cindex variabile @code{FS}, eseguire programmi @command{awk} e
+Subito dopo c'@`e una regola @code{BEGIN} che analizza le opzioni della riga
+di comando.
+Questa regola imposta @code{FS} a un solo carattere TAB, perch@'e quello @`e
+il separatore di campo di @command{cut} per default.
+La regola poi imposta il separatore di campo in output allo stesso valore
+del separatore di campo in input. Un ciclo che usa @code{getopt()} esamina
+le opzioni della riga di comando. Una e una sola delle variabili
+@code{per_campi} o @code{per_caratteri} @`e impostata a "vero", per indicare
+che l'elaborazione sar@`a fatta per campi o per caratteri, rispettivamente.
+Quando si ritaglia per caratteri, il separatore di campo in output @`e
+impostato alla stringa nulla:
+
+@example
+@c file eg/prog/cut.awk
+BEGIN @{
+ FS = "\t" # default
+ OFS = FS
+ while ((c = getopt(ARGC, ARGV, "sf:c:d:")) != -1) @{
+ if (c == "f") @{
+ per_campi = 1
+ lista_campi = Optarg
+ @} else if (c == "c") @{
+ per_caratteri = 1
+ lista_campi = Optarg
+ OFS = ""
+ @} else if (c == "d") @{
+ if (length(Optarg) > 1) @{
+ printf("cut: usa il primo carattere di %s" \
+ " come delimitatore\n", Optarg) > "/dev/stderr"
+ Optarg = substr(Optarg, 1, 1)
+ @}
+ fs = FS = Optarg
+ OFS = FS
+ if (FS == " ") # mette specifica in formato awk
+ FS = "[ ]"
+ @} else if (c == "s")
+ sopprimi = 1
+ else
+ sintassi()
+ @}
+
+ # Toglie opzioni da riga di comando
+ for (i = 1; i < Optind; i++)
+ ARGV[i] = ""
+@c endfile
+@end example
+
+@cindex separatori di campo, spazi come
+@cindex spazi come separatori di campo
+Nella scrittura del codice si deve porre particolare attenzione quando il
+delimitatore di campo @`e uno spazio. Usare
+un semplice spazio (@code{@w{" "}}) come valore per @code{FS} @`e
+sbagliato: @command{awk} separerebbe i campi con serie di spazi,
+TAB, e/o ritorni a capo, mentre devono essere separati solo da uno spazio.
+Per far questo, salviamo il carattere di spazio originale nella variabile
+@code{fs} per un uso futuro; dopo aver impostato @code{FS} a @code{"[ ]"} non
+@`e possibile usarlo direttamente per vedere se il carattere delimitatore di
+campo @`e nella stringa.
+
+Si ricordi anche che dopo che si @`e finito di usare @code{getopt()}
+(come descritto nella @ref{Funzione getopt}),
+@`e necessario
+eliminare tutti gli elementi del vettore @code{ARGV} da 1 a @code{Optind},
+in modo che @command{awk} non tenti di elaborare le opzioni della riga di comando
+come @value{FNS}.
+
+Dopo aver elaborato le opzioni della riga di comando, il programma verifica
+che le opzioni siano coerenti. Solo una tra le opzioni @option{-c}
+e @option{-f} dovrebbe essere presente, ed entrambe richiedono una lista di
+campi. Poi il programma chiama
+@code{prepara_lista_campi()} oppure @code{prepara_lista_caratteri()} per
+preparare la lista dei campi o dei caratteri:
+
+@example
+@c file eg/prog/cut.awk
+ if (per_campi && per_caratteri)
+ sintassi()
+
+ if (per_campi == 0 && per_caratteri == 0)
+ per_campi = 1 # default
+
+ if (lista_campi == "") @{
+ print "cut: specificare lista per -c o -f" > "/dev/stderr"
+ exit 1
+ @}
+
+ if (per_campi)
+ prepara_lista_campi()
+ else
+ prepara_lista_caratteri()
+@}
+@c endfile
+@end example
+
+@code{prepara_lista_campi()} pone la lista campi, usando la virgola come
+separatore, in un vettore. Poi, per
+ogni elemento del vettore, controlla che esso non sia un intervallo. Se @`e
+un intervallo, lo fa diventare un elenco. La funzione controlla l'intervallo
+specificato, per assicurarsi che il primo numero sia minore del secondo.
+Ogni numero nella lista @`e aggiunto al vettore @code{lista_c}, che
+semplicemente elenca i campi che saranno stampati. Viene usata la normale
+separazione in campi di @command{awk}. Il programma lascia ad @command{awk}
+il compito di separare i campi:
+
+@example
+@c file eg/prog/cut.awk
+function prepara_lista_campi( n, m, i, j, k, f, g)
+@{
+ n = split(lista_campi, f, ",")
+ j = 1 # indice in lista_c
+ for (i = 1; i <= n; i++) @{
+ if (index(f[i], "-") != 0) @{ # un intervallo
+ m = split(f[i], g, "-")
+@group
+ if (m != 2 || g[1] >= g[2]) @{
+ printf("cut: lista campi errata: %s\n",
+ f[i]) > "/dev/stderr"
+ exit 1
+ @}
+@end group
+ for (k = g[1]; k <= g[2]; k++)
+ lista_c[j++] = k
+ @} else
+ lista_c[j++] = f[i]
+ @}
+ ncampi = j - 1
+@}
+@c endfile
+@end example
+
+La funzione @code{prepara_lista_caratteri()} @`e pi@`u complicata di
+@code{prepara_lista_campi()}.
+L'idea qui @`e di usare la variabile di @command{gawk} @code{FIELDWIDTHS}
+(@pxref{Dimensione costante}),
+che descrive input a larghezza costante. Quando si usa una lista di
+caratteri questo @`e proprio il nostro caso.
+
+Impostare @code{FIELDWIDTHS} @`e pi@`u complicato che semplicemente elencare
+i campi da stampare. Si deve tener traccia dei campi da
+stampare e anche dei caratteri che li separano, che vanno saltati.
+Per esempio, supponiamo che si vogliano i caratteri da 1 a 8, 15,
+e da 22 a 35. Per questo si specifica @samp{-c 1-8,15,22-35}. Il valore che
+corrisponde a questo nella variabile @code{FIELDWIDTHS} @`e
+@code{@w{"8 6 1 6 14"}}. Questi sono cinque campi, e quelli da stampare
+sono @code{$1}, @code{$3}, e @code{$5}.
+I campi intermedi sono @dfn{riempitivo} (@dfn{filler}),
+ossia @`e ci@`o che separa i dati che si desidera estrarre.
+@code{lista_c} lista i campi da stampare, e @code{t} traccia l'elenco
+completo dei campi, inclusi i riempitivi:
+
+@example
+@c file eg/prog/cut.awk
+function prepara_lista_caratteri( campo, i, j, f, g, n, m, t,
+ filler, ultimo, lungo)
+@{
+ campo = 1 # contatore totale campi
+ n = split(lista_campi, f, ",")
+ j = 1 # indice in lista_c
+ for (i = 1; i <= n; i++) @{
+ if (index(f[i], "-") != 0) @{ # intervallo
+ m = split(f[i], g, "-")
+ if (m != 2 || g[1] >= g[2]) @{
+ printf("cut: lista caratteri errata: %s\n",
+ f[i]) > "/dev/stderr"
+ exit 1
+ @}
+ lungo = g[2] - g[1] + 1
+ if (g[1] > 1) # calcola lunghezza del riempitivo
+ filler = g[1] - ultimo - 1
+ else
+ filler = 0
+@group
+ if (filler)
+ t[campo++] = filler
+@end group
+ t[campo++] = lungo # lunghezza del campo
+ ultimo = g[2]
+ lista_c[j++] = campo - 1
+ @} else @{
+ if (f[i] > 1)
+ filler = f[i] - ultimo - 1
+ else
+ filler = 0
+ if (filler)
+ t[campo++] = filler
+ t[campo++] = 1
+ ultimo = f[i]
+ lista_c[j++] = campo - 1
+ @}
+ @}
+ FIELDWIDTHS = join(t, 1, campo - 1)
+ ncampi = j - 1
+@}
+@c endfile
+@end example
+
+Poi viene la regola che elabora i dati. Se l'opzione @option{-s} @`e stata
+specificata, il flag @code{sopprimi}
+@`e vero. La prima istruzione
+@code{if} accerta che il record in input abbia il separatore di
+campo. Se @command{cut} sta elaborando dei campi, e @code{sopprimi} @`e vero,
+e il carattere di separazione dei campi non @`e presente nel record, il
+record @`e ignorato.
+
+Se il record @`e valido, @command{gawk} ha gi@`a separato i dati in campi,
+usando il carattere in @code{FS} o usando campi a lunghezza fissa
+e @code{FIELDWIDTHS}. Il ciclo scorre attraverso la lista di campi che
+si dovrebbero stampare. Il campo corrispondente @`e stampato se contiene dati.
+Se il campo successivo contiene pure dei dati, il carattere di separazione @`e
+scritto tra i due campi:
+
+@example
+@c file eg/prog/cut.awk
+@{
+ if (per_campi && sopprimi && index($0, fs) == 0)
+ next
+
+ for (i = 1; i <= ncampi; i++) @{
+ if ($lista_c[i] != "") @{
+ printf "%s", $lista_c[i]
+ if (i < ncampi && $lista_c[i+1] != "")
+ printf "%s", OFS
+ @}
+ @}
+ print ""
+@}
+@c endfile
+@end example
+
+Questa versione di @command{cut} utilizza la variabile @code{FIELDWIDTHS} di
+@command{gawk} per ritagliare in base alla posizione dei caratteri. @`E
+possibile, in altre implementazioni di @command{awk} usare @code{substr()}
+(@pxref{Funzioni per stringhe}), ma
+la cosa @`e molto pi@`u complessa.
+La variabile @code{FIELDWIDTHS} fornisce una soluzione elegante al problema
+di suddividere la riga in input in singoli caratteri.
+
+
+@node Programma egrep
+@subsection Ricercare espressioni regolari nei file
+
+@cindex espressioni regolari, ricerca di
+@cindex ricercare, in file, espressioni regolari
+@cindex file, ricercare espressioni regolari nei
+@cindex @command{egrep}, programma di utilit@`a
+@cindex programma di utilit@`a @command{egrep}
+Il programma di utilit@`a @command{egrep} ricerca occorrenze di espressioni
+regolari all'interno di file. Usa
+espressioni regolari che sono quasi identiche a quelle disponibili in
+@iftex
+@command{awk} (@pxrefil{Espressioni regolari}).
+@end iftex
+@ifnottex
+@command{awk} (@pxref{Espressioni regolari}).
+@end ifnottex
+Si richiama cos@`{@dotless{i}}:
+
+@display
+@command{egrep} [@var{opzioni}] @code{'@var{espressione}'} @var{file} @dots{}
+@end display
+
+@var{espressione} @`e un'espressione regolare. Normalmente, l'espressione
+regolare @`e protetta da apici per impedire alla shell di espandere ogni
+carattere speciale come @value{FN}.
+Normalmente, @command{egrep} stampa le righe per cui @`e stata trovata una
+corrispondenza. Se nella riga di comando si richiede di operare su pi@`u di un
+@value{FN}, ogni riga in output @`e preceduta dal nome del file, e dal segno
+due punti.
+
+Le opzioni di @command{egrep} sono le seguenti:
+
+@table @code
+@item -c
+Stampa un contatore delle righe che corrispondono al criterio di ricerca,
+e non le righe stesse.
+
+@item -s
+Funziona in silenzio. Non si produce alcun output ma il codice di ritorno
+indica se il criterio di ricerca ha trovato almeno una corrispondenza.
+
+@item -v
+Inverte il senso del test. @command{egrep} stampa le righe che
+@emph{non} soddisfano il criterio di ricerca ed esce con successo se il
+criterio di ricerca non @`e soddisfatto.
+
+@item -i
+Ignora maiuscolo/minuscolo sia nel criterio di ricerca che nei dati in input.
+
+@item -l
+Stampa (elenca) solo i nomi dei file che corrispondono, e non le righe trovate.
+
+@item -e @var{espressione}
+Usa @var{espressione} come @dfn{regexp} da ricercare. Il motivo per cui
+@`e prevista l'opzione @option{-e} @`e di
+permettere dei criteri di ricerca che
+inizino con un @samp{-}.
+@end table
+
+Questa versione usa la funzione di libreria @code{getopt()}
+(@pxref{Funzione getopt})
+e il programma di libreria che gestisce il passaggio da un file dati
+al successivo
+(@pxref{Funzione filetrans}).
+
+Il programma inizia con un commento descrittivo e poi c'@`e una regola
+@code{BEGIN}
+che elabora gli argomenti della riga di comando usando @code{getopt()}.
+L'opzione @option{-i} (ignora maiuscolo/minuscolo) @`e particolarmente facile
+da implementare con @command{gawk}; basta usare la variabile predefinita
+@code{IGNORECASE}
+(@pxref{Variabili predefinite}):
+
+@cindex @code{egrep.awk}, programma
+@cindex programma @code{egrep.awk}
+@example
+@c file eg/prog/egrep.awk
+# egrep.awk --- simula egrep in awk
+#
+@c endfile
+@ignore
+@c file eg/prog/egrep.awk
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+
+@c endfile
+@end ignore
+@c file eg/prog/egrep.awk
+# Opzioni:
+# -c conta le righe trovate
+# -s sileziosa: genera solo il codice di ritorno
+# -v inverte test, successo se @dfn{regexp} non presente
+# -i ignora maiuscolo/minuscolo
+# -l stampa solo nomi file
+# -e espressione da ricercare
+#
+# Richiede la funzione getopt() e il programma di libreria
+# che gestisce il passaggio da un file dati al successivo
+
+BEGIN @{
+ while ((c = getopt(ARGC, ARGV, "ce:svil")) != -1) @{
+ if (c == "c")
+ conta_e_basta++
+ else if (c == "s")
+ non_stampare++
+ else if (c == "v")
+ inverti_test++
+ else if (c == "i")
+ IGNORECASE = 1
+ else if (c == "l")
+ solo_nomi_file++
+ else if (c == "e")
+ criterio_di_ricerca = Optarg
+ else
+ sintassi()
+ @}
+@c endfile
+@end example
+
+Nel seguito c'@`e il codice che gestisce il comportamento specifico di
+@command{egrep}. Se non @`e fornito esplicitamente alcun criterio di ricerca
+tramite l'opzione @option{-e}, si usa il primo argomento sulla riga di
+comando che non sia un'opzione.
+Gli argomenti della riga di comando di @command{awk} fino ad
+@code{ARGV[Optind]} vengono cancellati,
+in modo che @command{awk} non tenti di elaborarli come file. Se
+non @`e stato specificato alcun nome di file, si usa lo standard input, e se
+@`e presente pi@`u di un nome di file, lo si annota, in modo che i @value{FNS}
+vengano scritti prima di ogni riga di output corrispondente:
+
+@example
+@c file eg/prog/egrep.awk
+ if (criterio_di_ricerca == "")
+ criterio_di_ricerca = ARGV[Optind++]
+
+ for (i = 1; i < Optind; i++)
+ ARGV[i] = ""
+ if (Optind >= ARGC) @{
+ ARGV[1] = "-"
+ ARGC = 2
+ @} else if (ARGC - Optind > 1)
+ servono_nomi_file++
+
+# if (IGNORECASE)
+# criterio_di_ricerca = tolower(criterio_di_ricerca)
+@}
+@c endfile
+@end example
+
+Le ultime due righe sono solo dei commenti, in quanto non necessarie in
+@command{gawk}. Per altre versioni di
+@command{awk}, potrebbe essere necessario utilizzarle come istruzioni
+effettive (togliendo il "#").
+
+Il prossimo insieme di righe dovrebbe essere decommentato
+se non si sta usando @command{gawk}.
+Questa regola converte in minuscolo tutti i caratteri della riga in input,
+se @`e stata specificata l'opzione @option{-i}.@footnote{Inoltre, qui si
+introduce un errore subdolo; se una corrispondenza viene trovata, viene
+inviata in output la riga tradotta, non quella originale.}
+La regola @`e
+commentata perch@'e non @`e necessaria se si usa @command{gawk}:
+
+@example
+@c file eg/prog/egrep.awk
+#@{
+# if (IGNORECASE)
+# $0 = tolower($0)
+#@}
+@c endfile
+@end example
+
+La funzione @code{a_inizio_file()} @`e chiamata dalla regola in @file{ftrans.awk}
+quando ogni nuovo file viene elaborato. In questo caso, non c'@`e molto da fare;
+ci si limita a inizializzare una variabile @code{contatore_file} a zero.
+@code{contatore_file} serve a ricordare quante righe nel file corrente
+corrispondono al criterio di ricerca.
+Scegliere come nome di parametro @code{da_buttare} indica che sappiamo che
+@code{a_inizio_file()} @`e chiamata con un parametro, ma che noi non siamo
+interessati al suo valore:
+
+@example
+@c file eg/prog/egrep.awk
+function a_inizio_file(da_buttare)
+@{
+ contatore_file = 0
+@}
+@c endfile
+@end example
+
+La funzione @code{endfile()} viene chiamata dopo l'elaborazione di ogni file.
+Ha influenza sull'output solo quando l'utente desidera un contatore del
+numero di righe che sono state individuate. @code{non_stampare} @`e vero nel
+caso si desideri solo il codice di
+ritorno. @code{conta_e_basta} @`e vero se si desiderano solo i contatori
+delle righe trovate. @command{egrep}
+quindi stampa i contatori solo se
+sia la stampa che il conteggio delle righe sono stati abilitati.
+Il formato di output deve tenere conto del numero di file sui quali si
+opera. Per finire, @code{contatore_file} @`e aggiunto a @code{totale}, in
+modo da stabilire qual @`e il numero totale di righe che ha soddisfatto il
+criterio di ricerca:
+
+@example
+@c file eg/prog/egrep.awk
+function endfile(file)
+@{
+ if (! non_stampare && conta_e_basta) @{
+ if (servono_nomi_file)
+ print file ":" contatore_file
+ else
+ print contatore_file
+ @}
+
+ totale += contatore_file
+@}
+@c endfile
+@end example
+
+Si potrebbero usare i criteri di ricerca speciali @code{BEGINFILE} ed
+@code{ENDFILE}
+(@pxref{BEGINFILE/ENDFILE}),
+ma in quel caso il programma funzionerebbe solo usando @command{gawk}.
+Inoltre, questo esempio @`e stato scritto prima che a @command{gawk} venissero
+aggiunti i criteri speciali @code{BEGINFILE} ed @code{ENDFILE}.
+
+La regola seguente fa il grosso del lavoro per trovare righe corrispondenti
+al criterio di ricerca fornito. La variabile
+@code{corrisponde} @`e vera se la riga @`e individuata dal criterio di ricerca.
+Se l'utente chiede invece le righe che non corrispondono, il senso di
+@code{corrisponde} @`e invertito, usando l'operatore @samp{!}.
+@code{contatore_file} @`e incrementato con il valore di
+@code{corrisponde}, che vale uno o zero, a seconda che la corrispondenza sia
+stata trovata oppure no. Se la riga non corrisponde, l'istruzione
+@code{next} passa ad esaminare il record successivo.
+
+Vengono effettuati anche altri controlli, ma soltanto se non
+si sceglie di contare le righe. Prima di tutto, se l'utente desidera solo
+il codice di ritorno (@code{non_stampare} @`e vero), @`e sufficiente sapere
+che @emph{una} riga nel file corrisponde, e si pu@`o passare al file successivo
+usando @code{nextfile}. Analogamente, se stiamo solo stampando @value{FNS},
+possiamo stampare il @value{FN}, e quindi saltare al file successivo con
+@code{nextfile}.
+Infine, ogni riga viene stampata, preceduta, se necessario, dal @value{FN} e
+dai due punti:
+
+@cindex @code{!} (punto esclamativo), operatore @code{!}
+@cindex punto esclamativo (@code{!}), operatore @code{!}
+@example
+@c file eg/prog/egrep.awk
+@{
+ corrisponde = ($0 ~ criterio_di_ricerca)
+ if (inverti_test)
+ corrisponde = ! corrisponde
+
+ contatore_file += corrisponde # 1 o 0
+
+ if (! corrisponde)
+ next
+
+ if (! conta_e_basta) @{
+ if (non_stampare)
+ nextfile
+
+ if (solo_nomi_file) @{
+ print nome_file
+ nextfile
+ @}
+
+ if (servono_nomi_file)
+ print nome_file ":" $0
+ else
+ print
+ @}
+@}
+@c endfile
+@end example
+
+La regola @code{END} serve a produrre il codice di ritorno corretto. Se
+non ci sono corrispondenze, il codice di ritorno @`e uno; altrimenti, @`e zero:
+
+@example
+@c file eg/prog/egrep.awk
+END @{
+ exit (totale == 0)
+@}
+@c endfile
+@end example
+
+La funzione @code{sintassi()} stampa un messaggio per l'utente, nel caso
+siano state specificate opzioni non valide, e quindi esce:
+
+@example
+@c file eg/prog/egrep.awk
+function sintassi()
+@{
+ print("sintassi: egrep [-csvil] [-e criterio_di_ricerca] [file ...]")\
+ > "/dev/stderr"
+ print("\n\tegrep [-csvil] criterio_di_ricerca [file ...]") > "/dev/stderr"
+ exit 1
+@}
+@c endfile
+@end example
+
+
+@node Programma id
+@subsection Stampare informazioni sull'utente
+
+@cindex stampare informazioni utente
+@cindex utenti, informazioni riguardo agli, stampare
+@cindex @command{id}, programma di utilit@`a
+@cindex programma di utilit@`a @command{id}
+Il programma di utilit@`a @command{id} elenca i numeri identificativi (ID)
+reali ed effettivi di un utente, e l'insieme dei gruppi a cui l'utente
+appartiene, se ve ne sono.
+@command{id} stampa i numeri identificativi di utente e di gruppo solo se
+questi sono differenti da quelli reali. Se possibile, @command{id} elenca
+anche i corrispondenti nomi di utente e di gruppo.
+L'output potrebbe essere simile a questo:
+
+@example
+$ @kbd{id}
+@print{} uid=1000(arnold) gid=1000(arnold) groups=1000(arnold),4(adm),7(lp),27(sudo)
+@end example
+
+@cindex @code{PROCINFO}, vettore, e @dfn{process ID} di utente e di gruppo
+Questa informazione @`e parte di ci@`o che @`e reso disponibile dal vettore
+@code{PROCINFO} di @command{gawk} (@pxref{Variabili predefinite}).
+Comunque, il programma di utilit@`a @command{id} fornisce un output pi@`u
+comprensibile che non una semplice lista di numeri.
+
+Ecco una versione semplice di @command{id} scritta in @command{awk}.
+Usa le funzioni di libreria che riguardano il database degli utenti
+(@pxref{Funzioni Passwd})
+e le funzioni di libreria che riguardano il database dei gruppi
+(@pxref{Funzioni Group})
+contenute
+@iftex
+nel
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzioni di libreria}.
+
+Il programma @`e abbastanza semplice. Tutto il lavoro @`e svolto nella regola
+@code{BEGIN}. I numeri ID di utente e di gruppo sono ottenuti da
+@code{PROCINFO}.
+Il codice @`e ripetitivo. La riga nel database degli utenti che descrive
+l'ID reale dell'utente @`e divisa in parti, separate tra loro da @samp{:}.
+Il nome @`e il primo campo. Un codice analogo @`e usato per l'ID effettivo, e
+per i numeri che descrivono i gruppi:
+
+@cindex @code{id.awk}, programma
+@cindex programma @code{id.awk}
+@example
+@c file eg/prog/id.awk
+# id.awk --- implement id in awk
+#
+# Richiede funzioni di libreria per utente e gruppo
+@c endfile
+@ignore
+@c file eg/prog/id.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised February 1996
+# Revised May 2014
+# Revised September 2014
+
+@c endfile
+@end ignore
+@c file eg/prog/id.awk
+# l'output @`e:
+# uid=12(pippo) euid=34(pluto) gid=3(paperino) \
+# egid=5(paperina) groups=9(nove),2(due),1(uno)
+
+@group
+BEGIN @{
+ uid = PROCINFO["uid"]
+ euid = PROCINFO["euid"]
+ gid = PROCINFO["gid"]
+ egid = PROCINFO["egid"]
+@end group
+
+ printf("uid=%d", uid)
+ pw = getpwuid(uid)
+ stampa_primo_campo(pw)
+
+ if (euid != uid) @{
+ printf(" euid=%d", euid)
+ pw = getpwuid(euid)
+ stampa_primo_campo(pw)
+ @}
+
+ printf(" gid=%d", gid)
+ pw = getgrgid(gid)
+ stampa_primo_campo(pw)
+
+ if (egid != gid) @{
+ printf(" egid=%d", egid)
+ pw = getgrgid(egid)
+ stampa_primo_campo(pw)
+ @}
+
+ for (i = 1; ("group" i) in PROCINFO; i++) @{
+ if (i == 1)
+ printf(" gruppi=")
+ group = PROCINFO["group" i]
+ printf("%d", group)
+ pw = getgrgid(group)
+ stampa_primo_campo(pw)
+ if (("group" (i+1)) in PROCINFO)
+ printf(",")
+ @}
+
+ print ""
+@}
+
+function stampa_primo_campo(str, a)
+@{
+ if (str != "") @{
+ split(str, a, ":")
+ printf("(%s)", a[1])
+ @}
+@}
+@c endfile
+@end example
+
+Il test incluso nel ciclo @code{for} @`e degno di nota.
+Ogni ulteriore gruppo nel vettore @code{PROCINFO} ha come indice da
+@code{"group1"} a @code{"group@var{N}"} dove il numero
+@var{N} @`e il numero totale di gruppi ulteriori).
+Tuttavia, non si sa quanti di questi gruppi ci siano per un dato utente.
+
+Questo ciclo inizia da uno, concatena il valore di ogni iterazione con
+@code{"group"}, e poi usando l'istruzione @code{in} verifica se quella
+chiave @`e nel vettore (@pxref{Visitare elementi}). Quando @code{i} @`e
+incrementato oltre l'ultimo gruppo presente nel vettore, il ciclo termina.
+
+Il ciclo funziona correttamente anche se @emph{non} ci sono ulteriori
+gruppi; in quel caso la condizione risulta falsa fin dal primo controllo, e
+il corpo del ciclo non viene mai eseguito.
+
+La funzione @code{stampa_primo_campo()} semplicemente incapsula quelle parti di
+codice che vengono usate ripetutamente, rendendo il programma pi@`u conciso e
+ordinato.
+In particolare, inserendo in questa funzione il test per la stringa nulla
+consente di risparmiare parecchie righe di programma.
+
+
+@node Programma split
+@subsection Suddividere in pezzi un file grosso
+
+@c FIXME: One day, update to current POSIX version of split
+
+@cindex file, splitting
+@cindex @code{split}, programma di utilit@`a
+@cindex programma di utilit@`a @code{split}
+Il programma @command{split} divide grossi file di testo in pezzi pi@`u piccoli.
+La sua sintassi @`e la seguente:@footnote{Questo @`e la sintassi tradizionale.
+La versione POSIX del comando ha una sintassi differente, ma per lo scopo di
+questo programma @command{awk} la cosa non ha importanza.}
+
+@display
+@command{split} [@code{-@var{contatore}}] [@var{file}] [@var{prefisso}]
+@end display
+
+Per default,
+i file di output avranno nome @file{xaa}, @file{xab}, e cos@`{@dotless{i}} via. Ogni file
+contiene 1.000 righe, con la probabile
+eccezione dell'ultimo file. Per
+cambiare il numero di righe in ogni file, va indicato un numero sulla riga
+di comando, preceduto da un segno meno (p.es., @samp{-500} per file con 500
+righe ognuno invece che 1.000). Per modificare i nomi dei file di output in
+qualcosa del tipo
+@file{miofileaa}, @file{miofileab}, e cos@`{@dotless{i}} via, va indicato un argomento
+ulteriore che specifica il prefisso del @value{FN}.
+
+Ecco una versione di @command{split} in @command{awk}. Usa le funzioni
+@code{ord()} e @code{chr()} descritte nella
+@ref{Funzioni ordinali}.
+
+Il programma dapprima imposta i suoi valori di default, e poi controlla che
+non siano stati specificati troppi argomenti. Quindi esamina gli argomenti
+uno alla volta. Il primo
+argomento potrebbe essere un segno meno seguito da un numero. Poich@'e il
+numero in questione pu@`o apparire negativo, lo si fa diventare positivo, e
+viene usato per contare le righe. Il nome del @value{DF} @`e per ora ignorato
+e l'ultimo argomento @`e usato come prefisso per i @value{FNS} in output:
+
+@cindex @code{split.awk}, programma di utilit@`a
+@cindex programma di utilit@`a @code{split.awk}
+@example
+@c file eg/prog/split.awk
+# split.awk --- comando split scritto in awk
+#
+# Richiede le funzioni di libreria ord() e chr()
+@c endfile
+@ignore
+@c file eg/prog/split.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised slightly, May 2014
+
+@c endfile
+@end ignore
+@c file eg/prog/split.awk
+# sintassi: split [-contatore] [file] [nome_in_output]
+
+BEGIN @{
+ outfile = "x" # default
+ contatore = 1000
+ if (ARGC > 4)
+ sintassi()
+
+ i = 1
+ if (i in ARGV && ARGV[i] ~ /^-[[:digit:]]+$/) @{
+ contatore = -ARGV[i]
+ ARGV[i] = ""
+ i++
+ @}
+ # testa argv nel caso che si legga da stdin invece che da file
+ if (i in ARGV)
+ i++ # salta nome file-dati
+ if (i in ARGV) @{
+ outfile = ARGV[i]
+ ARGV[i] = ""
+ @}
+
+ s1 = s2 = "a"
+ out = (outfile s1 s2)
+@}
+@c endfile
+@end example
+
+La regola seguente fa il grosso del lavoro. @code{contatore_t}
+(contatore temporaneo) tiene conto di
+quante righe sono state stampate sul file di output finora. Se questo
+numero supera il valore di @code{contatore}, @`e ora di chiudere il file
+corrente e di iniziare a scriverne uno nuovo.
+Le variabili @code{s1} e @code{s2} sono usate per creare i suffissi
+da apporre a @value{FN}. Se entrambi arrivano al valore @samp{z}, il file
+@`e troppo grosso. Altrimenti, @code{s1} passa alla successiva lettera
+dell'alfabeto e @code{s2} ricomincia da @samp{a}:
+
+@c else on separate line here for page breaking
+@example
+@c file eg/prog/split.awk
+@{
+ if (++contatore_t > contatore) @{
+ close(out)
+ if (s2 == "z") @{
+ if (s1 == "z") @{
+ printf("split: %s @`e troppo grosso da suddividere\n",
+ nome_file) > "/dev/stderr"
+ exit 1
+ @}
+ s1 = chr(ord(s1) + 1)
+ s2 = "a"
+ @}
+@group
+ else
+ s2 = chr(ord(s2) + 1)
+@end group
+ out = (outfile s1 s2)
+ contatore_t = 1
+ @}
+ print > out
+@}
+@c endfile
+@end example
+
+@noindent
+La funzione @code{sintassi()} stampa solo un messaggio di errore ed esce:
+
+@example
+@c file eg/prog/split.awk
+function sintassi()
+@{
+ print("sintassi: split [-num] [file] [nome_in_output]") > "/dev/stderr"
+ exit 1
+@}
+@c endfile
+@end example
+
+Questo programma @`e un po' approssimativo; conta sul fatto che @command{awk} chiuda
+automaticamente l'ultimo file invece di farlo in una regola @code{END}.
+Un altro presupposto del programma @`e che le lettere dell'alfabeto siano
+in posizioni consecutive nella codifica in uso, il che non @`e vero per i
+sistemi che usano la codifica EBCDIC.
+
+@ifset FOR_PRINT
+Si potrebbe pensare a come eliminare l'uso di
+@code{ord()} e @code{chr()}; la cosa si pu@`o fare in modo tale da risolvere
+anche il problema posto dalla codifica EBCDIC.
+@end ifset
+
+
+@node Programma tee
+@subsection Inviare l'output su pi@`u di un file
+
+@cindex file, multipli@comma{} duplicare l'output su
+@cindex output, duplicarlo su pi@`u file
+@cindex @code{tee}, programma di utilit@`a
+@cindex programma di utilit@`a @code{tee}
+Il programma @code{tee} @`e noto come @dfn{pipe fitting} (tubo secondario).
+@code{tee} copia il suo standard input al suo standard output e inoltre lo
+duplica scrivendo sui file indicati nella riga di comando. La sua sintassi
+@`e la seguente:
+
+@display
+@command{tee} [@option{-a}] @var{file} @dots{}
+@end display
+
+L'opzione @option{-a} chiede a @code{tee} di aggiungere in fondo al file
+indicato, invece che riscriverlo dall'inizio.
+
+La regola @code{BEGIN} dapprima fa una copia di tutti gli argomenti presenti
+sulla riga di comando, in un vettore di nome @code{copia}.
+@code{ARGV[0]} non serve, e quindi non viene copiato.
+@code{tee} non pu@`o usare @code{ARGV} direttamente, perch@'e @command{awk} tenta
+di elaborare ogni @value{FN} in @code{ARGV} come dati in input.
+
+@cindex flag, variabili di tipo
+@cindex variabili di tipo indicatore [@dfn{flag}]
+Se il primo argomento @`e @option{-a}, la variabile flag
+@code{append} viene impostata a vero, e sia @code{ARGV[1]} che
+@code{copia[1]} vengono cancellati. Se @code{ARGC} @`e minore di due, nessun
+@value{FN} @`e stato fornito, e @code{tee} stampa un messaggio di sintassi ed
+esce.
+Infine, @command{awk} viene obbligato a leggere lo standard input
+impostando @code{ARGV[1]} al valore @code{"-"} e @code{ARGC} a due:
+
+@cindex @code{tee.awk}, programma di utilit@`a
+@cindex programma di utilit@`a @code{tee.awk}
+@example
+@c file eg/prog/tee.awk
+# tee.awk --- tee in awk
+#
+# Copia lo standard input a tutti i file di output indicati.
+# Aggiunge in fondo se viene data l'opzione -a.
+#
+@c endfile
+@ignore
+@c file eg/prog/tee.awk
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised December 1995
+
+@c endfile
+@end ignore
+@c file eg/prog/tee.awk
+BEGIN @{
+ for (i = 1; i < ARGC; i++)
+ copia[i] = ARGV[i]
+
+ if (ARGV[1] == "-a") @{
+ append = 1
+ delete ARGV[1]
+ delete copia[1]
+ ARGC--
+ @}
+ if (ARGC < 2) @{
+ print "sintassi: tee [-a] file ..." > "/dev/stderr"
+ exit 1
+ @}
+ ARGV[1] = "-"
+ ARGC = 2
+@}
+@c endfile
+@end example
+
+La seguente regola @`e sufficiente da sola a eseguire il lavoro. Poich@'e non @`e
+presente alcun criterio di ricerca, la regola @`e eseguita per ogni riga di
+input. Il corpo della regola si limita a stampare la riga su ogni file
+indicato nella riga di comando, e poi sullo standard output:
+
+@example
+@c file eg/prog/tee.awk
+@{
+ # spostare l'if fuori dal ciclo ne velocizza l'esecuzione
+ if (append)
+ for (i in copia)
+ print >> copia[i]
+ else
+ for (i in copia)
+ print > copia[i]
+ print
+@}
+@c endfile
+@end example
+
+@noindent
+@`E anche possibile scrivere il ciclo cos@`{@dotless{i}}:
+
+@example
+for (i in copia)
+ if (append)
+ print >> copia[i]
+ else
+ print > copia[i]
+@end example
+
+@noindent
+Questa forma @`e pi@`u concisa, ma anche meno efficiente. L'@samp{if} @`e
+eseguito per ogni record e per ogni file di output. Duplicando il corpo
+del ciclo, l'@samp{if} @`e eseguito solo una volta per ogni record in input.
+Se ci sono
+@var{N} record in input e @var{M} file di output, il primo metodo esegue solo
+@var{N} istruzioni @samp{if}, mentre il secondo esegue
+@var{N}@code{*}@var{M} istruzioni @samp{if}.
+
+Infine, la regola @code{END} fa pulizia, chiudendo tutti i file di output:
+
+@example
+@c file eg/prog/tee.awk
+END @{
+ for (i in copia)
+ close(copia[i])
+@}
+@c endfile
+@end example
+
+@node Programma uniq
+@subsection Stampare righe di testo non duplicate
+
+@c FIXME: One day, update to current POSIX version of uniq
+
+@cindex stampare righe di testo non duplicate
+@cindex testo@comma{} stampare, righe non duplicate di
+@cindex @command{uniq}, programma di utilit@`a
+@cindex programma di utilit@`a @command{uniq}
+Il programma di utilit@`a @command{uniq} legge righe di dati ordinati sul suo
+standard input, e per default rimuove righe duplicate. In altre parole,
+stampa solo righe uniche; da cui il
+nome. @command{uniq} ha diverse opzioni. La sintassi @`e la seguente:
+
+@display
+@command{uniq} [@option{-udc} [@code{-@var{n}}]] [@code{+@var{n}}] [@var{file_input} [@var{file_output}]]
+@end display
+
+Le opzioni per @command{uniq} sono:
+
+@table @code
+@item -d
+Stampa solo righe ripetute (duplicate).
+
+@item -u
+Stampa solo righe non ripetute (uniche).
+
+@item -c
+Contatore righe. Quest'opzione annulla le opzioni @option{-d} e @option{-u}.
+Sia le righe ripetute che quelle non ripetute vengono contate.
+
+@item -@var{n}
+Salta @var{n} campi prima di confrontare le righe. La definizione di campo
+@`e simile al default di @command{awk}: caratteri non bianchi, separati da
+sequenze di spazi e/o TAB.
+
+@item +@var{n}
+Salta @var{n} caratteri prima di confrontare le righe. Eventuali campi
+specificati con @samp{-@var{n}} sono saltati prima.
+
+@item @var{file_input}
+I dati sono letti dal file in input specificato sulla riga di comando, invece
+che dallo standard input.
+
+@item @var{file_output}
+L'output generato @`e scritto sul file di output specificato, invece che sullo
+standard output.
+@end table
+
+Normalmente @command{uniq} si comporta come se siano state specificate entrambe
+le opzioni @option{-d} e @option{-u}.
+
+@command{uniq} usa la
+funzione di libreria @code{getopt()}
+(@pxref{Funzione getopt})
+e la funzione di libreria @code{join()}
+(@pxref{Funzione join}).
+
+Il programma inizia con una funzione @code{sintassi()} e poi con una breve
+spiegazione delle opzioni e del loro significato, sotto forma di commenti.
+La regola @code{BEGIN} elabora gli argomenti della riga di comando e le
+opzioni. Viene usato un artificio per poter impiegare @code{getopt()} con
+opzioni della forma @samp{-25},
+trattando quest'opzione come la lettera di opzione @samp{2} con
+l'argomento @samp{5}. Se si specificano due o pi@`u cifre (@code{Optarg}
+sembra essere numerico), @code{Optarg} @`e concatenato con la cifra che
+costituisce l'opzione e poi al risultato @`e addizionato zero, per trasformarlo
+in un numero. Se c'@`e solo una cifra nell'opzione, @code{Optarg} non @`e
+necessario. In tal caso, @code{Optind} dev'essere decrementata, in modo che
+@code{getopt()} la elabori quando viene nuovamente richiamato. Questo codice
+@`e sicuramente un po' intricato.
+
+Se non sono specificate opzioni, per default si stampano sia le righe
+ripetute che quelle non ripetute. Il file di output, se specificato, @`e
+assegnato a @code{file_output}. In precedenza, @code{file_output} @`e
+inizializzato allo standard output, @file{/dev/stdout}:
+
+@cindex @code{uniq.awk}, programma di utilit@`a
+@cindex programma di utilit@`a @code{uniq.awk}
+@example
+@c file eg/prog/uniq.awk
+@group
+# uniq.awk --- implementa uniq in awk
+#
+# Richiede le funzioni di libreria getopt() e join()
+@end group
+@c endfile
+@ignore
+@c file eg/prog/uniq.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+@c endfile
+@end ignore
+@c file eg/prog/uniq.awk
+
+function sintassi()
+@{
+ print("sintassi: uniq [-udc [-n]] [+n] [ in [ out ]]") > "/dev/stderr"
+ exit 1
+@}
+
+# -c contatore di righe. prevale su -d e -u
+# -d solo righe ripetute
+# -u solo righe non ripetute
+# -n salta n campi
+# +n salta n caratteri, salta prima eventuali campi
+
+BEGIN @{
+ contatore = 1
+ file_output = "/dev/stdout"
+ opts = "udc0:1:2:3:4:5:6:7:8:9:"
+ while ((c = getopt(ARGC, ARGV, opts)) != -1) @{
+ if (c == "u")
+ solo_non_ripetute++
+ else if (c == "d")
+ solo_ripetute++
+ else if (c == "c")
+ conta_record++
+ else if (index("0123456789", c) != 0) @{
+ # getopt() richiede argomenti per le opzioni
+ # questo consente di gestire cose come -5
+ if (Optarg ~ /^[[:digit:]]+$/)
+ contatore_file = (c Optarg) + 0
+ else @{
+ contatore_file = c + 0
+ Optind--
+ @}
+ @} else
+ sintassi()
+ @}
+
+ if (ARGV[Optind] ~ /^\+[[:digit:]]+$/) @{
+ conta_caratteri = substr(ARGV[Optind], 2) + 0
+ Optind++
+ @}
+
+ for (i = 1; i < Optind; i++)
+ ARGV[i] = ""
+
+ if (solo_ripetute == 0 && solo_non_ripetute == 0)
+ solo_ripetute = solo_non_ripetute = 1
+
+ if (ARGC - Optind == 2) @{
+ file_output = ARGV[ARGC - 1]
+ ARGV[ARGC - 1] = ""
+ @}
+@}
+@c endfile
+@end example
+
+La funzione seguente, @code{se_sono_uguali()}, confronta la riga corrente,
+@code{$0}, con la riga precedente, @code{ultima}. Gestisce il salto di
+campi e caratteri. Se non sono stati richiesti n@'e contatori di campo n@'e
+contatori di carattere, @code{se_sono_uguali()} restituisce uno o zero a
+seconda del risultato di un semplice confronto tra le stringhe @code{ultima}
+e @code{$0}.
+
+In caso contrario, le cose si complicano. Se devono essere saltati dei campi,
+ogni riga viene suddivisa in un vettore, usando @code{split()}
+(@pxref{Funzioni per stringhe}); i campi desiderati sono poi nuovamente uniti in
+un'unica riga usando @code{join()}. Le righe ricongiunte vengono
+immagazzinate in @code{campi_ultima} e @code{campi_corrente}. Se non ci
+sono campi da saltare, @code{campi_ultima} e @code{campi_corrente} sono
+impostati a @code{ultima} e @code{$0}, rispettivamente. Infine, se
+occorre saltare dei caratteri, si usa @code{substr()} per eliminare i primi
+@code{conta_caratteri} caratteri in @code{campi_ultima} e
+@code{campi_corrente}. Le due stringhe sono poi confrontare e
+@code{se_sono_uguali()} restituisce il risultato del confronto:
+
+@example
+@c file eg/prog/uniq.awk
+function se_sono_uguali( n, m, campi_ultima, campi_corrente,\
+vettore_ultima, vettore_corrente)
+@{
+ if (contatore_file == 0 && conta_caratteri == 0)
+ return (ultima == $0)
+
+ if (contatore_file > 0) @{
+ n = split(ultima, vettore_ultima)
+ m = split($0, vettore_corrente)
+ campi_ultima = join(vettore_ultima, contatore_file+1, n)
+ campi_corrente = join(vettore_corrente, contatore_file+1, m)
+ @} else @{
+ campi_ultima = ultima
+ campi_corrente = $0
+ @}
+ if (conta_caratteri) @{
+ campi_ultima = substr(campi_ultima, conta_caratteri + 1)
+ campi_corrente = substr(campi_corrente, conta_caratteri + 1)
+ @}
+
+ return (campi_ultima == campi_corrente)
+@}
+@c endfile
+@end example
+
+Le due regole seguenti sono il corpo del programma. La prima @`e eseguita solo
+per la prima riga dei dati. Imposta @code{ultima} al record corrente
+@code{$0}, in modo che le righe di testo successive abbiano qualcosa con cui
+essere confrontate.
+
+La seconda regola fa il lavoro. La variabile @code{uguale} vale uno o zero,
+a seconda del risultato del confronto effettuato in @code{se_sono_uguali()}.
+Se @command{uniq} sta contando le righe ripetute, e le righe sono uguali,
+viene incrementata la variabile @code{contatore}.
+Altrimenti, viene stampata la riga e azzerato @code{contatore},
+perch@'e le due righe non sono uguali.
+
+Se @command{uniq} non sta contando, e se le righe sono uguali,
+@code{contatore} @`e incrementato.
+Non viene stampato niente, perch@'e l'obiettivo @`e quello di rimuovere i duplicati.
+Altrimenti, se @command{uniq} sta contando le righe ripetute e viene trovata pi@`u
+di una riga, o se @command{uniq} sta contando le righe non ripetute
+e viene trovata solo una riga, questa riga viene stampata, e @code{contatore} @`e
+azzerato.
+
+Infine, una logica simile @`e usata nella regola @code{END} per stampare
+l'ultima riga di dati in input:
+
+@example
+@c file eg/prog/uniq.awk
+NR == 1 @{
+ ultima = $0
+ next
+@}
+
+@{
+ uguale = se_sono_uguali()
+
+ if (conta_record) @{ # prevale su -d e -u
+ if (uguale)
+ contatore++
+ else @{
+ printf("%4d %s\n", contatore, ultima) > file_output
+ ultima = $0
+ contatore = 1 # reset
+ @}
+ next
+ @}
+
+ if (uguale)
+ contatore++
+ else @{
+ if ((solo_ripetute && contatore > 1) ||
+ (solo_non_ripetute && contatore == 1))
+ print ultima > file_output
+ ultima = $0
+ contatore = 1
+ @}
+@}
+
+END @{
+ if (conta_record)
+ printf("%4d %s\n", contatore, ultima) > file_output
+ else if ((solo_ripetute && contatore > 1) ||
+ (solo_non_ripetute && contatore == 1))
+ print ultima > file_output
+ close(file_output)
+@}
+@c endfile
+@end example
+
+@c FIXME: Include this?
+@ignore
+This program does not follow our recommended convention of naming
+global variables with a leading capital letter. Doing that would
+make the program a little easier to follow.
+@end ignore
+
+@ifset FOR_PRINT
+La logica per scegliere quali righe stampare rappresenta una @dfn{macchina a
+stati}, che @`e ``un dispositivo che pu@`o trovarsi in una tra un dato numero di
+condizioni stabili, a seconda della sua condizione precedente e del valore
+corrente dei suoi input.''@footnote{Questa @`e la definizione trovata
+cercando @code{define: state machine} in Google.}
+Brian Kernighan suggerisce che
+``un approccio alternativo alle macchine a stati @`e quello di mettere l'input
+in un vettore, e poi usare gli indici. @`E quasi sempre pi@`u facile da
+programmare e, per molti input in cui si pu@`o usare questo metodo,
+altrettanto veloce.'' Si consideri come riscrivere la logica di questo
+programma per seguite questo suggerimento.
+@end ifset
+
+
+
+@node Programma wc
+@subsection Contare cose
+
+@c FIXME: One day, update to current POSIX version of wc
+
+@cindex contare
+@cindex file in input, contare elementi nel
+@cindex parole, contare le
+@cindex caratteri, contare i
+@cindex righe, contare le
+@cindex @command{wc}, programma di utilit@`a
+@cindex programma di utilit@`a @command{wc}
+Il programma di utilit@`a @command{wc} (@dfn{word count}, contatore di parole)
+conta righe, parole, e caratteri in uno o pi@`u file in input. La sua sintassi
+@`e la seguente:
+
+@display
+@command{wc} [@option{-lwc}] [@var{file} @dots{}]
+@end display
+
+Se nessun file @`e specificato sulla riga di comando, @command{wc} legge il suo
+standard input. Se ci sono pi@`u file, stampa anche il contatore totale di
+tutti i file. Le opzioni e il loro significato sono i seguenti:
+
+@table @code
+@item -l
+Conta solo le righe.
+
+@item -w
+Conta solo le parole.
+Una ``parola'' @`e una sequenza contigua di caratteri non bianchi, separata da
+spazi e/o TAB. Fortunatamente, questo @`e il modo normale in cui @command{awk}
+separa i campi nei suoi record in input.
+
+@item -c
+Conta solo i caratteri.
+@end table
+
+Implementare @command{wc} in @command{awk} @`e particolarmente elegante,
+perch@'e @command{awk} fa molto lavoro al posto nostro; divide le righe in
+parole (cio@`e, campi) e le conta, conta le righe (cio@`e, i record),
+e pu@`o facilmente dire quanto @`e lunga una riga.
+
+Questo programma usa la funzione di libreria @code{getopt()}
+(@pxref{Funzione getopt})
+e le funzioni di passaggio da un file all'altro
+(@pxref{Funzione filetrans}).
+
+Questa versione ha una differenza significativa rispetto alle versioni
+tradizionali di @command{wc}: stampa sempre i contatori rispettando l'ordine
+righe, parole e caratteri. Le versioni tradizionali rilevano l'ordine in cui
+sono specificate le opzioni @option{-l}, @option{-w} e @option{-c} sulla riga
+di comando, e stampano i contatori in quell'ordine.
+
+La regola @code{BEGIN} si occupa degli argomenti. La variabile
+@code{stampa_totale} @`e vera se pi@`u di un file @`e presente sulla
+riga di comando:
+
+@cindex @code{wc.awk}, programma di utilit@`a
+@cindex programma di utilit@`a @code{wc.awk}
+@example
+@c file eg/prog/wc.awk
+# wc.awk --- conta righe, parole, caratteri
+@c endfile
+@ignore
+@c file eg/prog/wc.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+@c endfile
+@end ignore
+@c file eg/prog/wc.awk
+
+# Opzioni:
+# -l conta solo righe
+# -w conta solo parole
+# -c conta solo caratteri
+#
+# Il default @`e di contare righe, parole, caratteri
+#
+# Richiede le funzioni di libreria getopt()
+# e il programma di libreria che gestisce
+# il passaggio da un file dati al successivo
+
+BEGIN @{
+ # consente a getopt() di stampare un messaggio se si specificano
+ # opzioni non valide. Noi le ignoriamo
+ while ((c = getopt(ARGC, ARGV, "lwc")) != -1) @{
+ if (c == "l")
+ conta_righe = 1
+ else if (c == "w")
+ conta_parole = 1
+ else if (c == "c")
+ conta_caratteri = 1
+ @}
+ for (i = 1; i < Optind; i++)
+ ARGV[i] = ""
+
+ # se nessuna opzione @`e specificata, conta tutto
+ if (! conta_righe && ! conta_parole && ! conta_caratteri)
+ conta_righe = conta_parole = conta_caratteri = 1
+
+ stampa_totale = (ARGC - i > 1)
+@}
+@c endfile
+@end example
+
+La funzione @code{a_inizio_file()} @`e semplice; si limita ad azzerare i contatori
+di righe, parole e caratteri, e salva il valore corrente di @value{FN} in
+@code{nome_file}:
+
+@example
+@c file eg/prog/wc.awk
+function a_inizio_file(file)
+@{
+ righe = parole = caratteri = 0
+ nome_file = FILENAME
+@}
+@c endfile
+@end example
+
+La funzione @code{a_fine_file()} aggiunge i numeri del file corrente al totale
+di righe, parole, e caratteri. Poi stampa i numeri relativi al file appena
+letto. La funzione
+@code{a_inizio_file()} azzera i numeri relativi al @value{DF} seguente:
+
+@example
+@c file eg/prog/wc.awk
+function a_fine_file(file)
+@{
+ totale_righe += righe
+ totale_parole += parole
+ totale_caratteri += caratteri
+ if (conta_righe)
+ printf "\t%d", righe
+@group
+ if (conta_parole)
+ printf "\t%d", parole
+@end group
+ if (conta_caratteri)
+ printf "\t%d", caratteri
+ printf "\t%s\n", nome_file
+@}
+@c endfile
+@end example
+
+C'@`e una regola che viene eseguita per ogni riga. Aggiunge la lunghezza del record
+pi@`u uno, a @code{caratteri}.@footnote{Poich@'e @command{gawk} gestisce le
+localizzazioni in cui un carattere pu@`o occupare pi@`u di un byte, questo codice
+conta i caratteri, non i byte.}
+Aggiungere uno alla lunghezza del record
+@`e necessario, perch@'e il carattere di ritorno a capo, che separa i record
+(il valore di @code{RS}) non @`e parte del record stesso, e quindi non @`e
+incluso nella sua lunghezza. Poi, @code{righe} @`e incrementata per ogni riga
+letta, e @code{parole} @`e incrementato con il valore @code{NF}, che @`e il
+numero di ``parole'' su questa riga:
+
+@example
+@c file eg/prog/wc.awk
+# per ogni riga...
+@{
+ caratteri += length($0) + 1 # aggiunge un ritorno a capo
+ righe++
+ parole += NF
+@}
+@c endfile
+@end example
+
+Infine, la regola @code{END} si limita a stampare i totali per tutti i file:
+
+@example
+@c file eg/prog/wc.awk
+END @{
+ if (stampa_totale) @{
+ if (conta_righe)
+ printf "\t%d", totale_righe
+ if (conta_parole)
+ printf "\t%d", totale_parole
+ if (conta_caratteri)
+ printf "\t%d", totale_caratteri
+ print "\ttotale"
+ @}
+@}
+@c endfile
+@end example
+
+@node Programmi vari
+@section Un paniere di programmi @command{awk}
+
+Questa @value{SECTION} @`e un ``paniere'' che contiene vari programmi.
+Si spera che siano interessanti e divertenti.
+
+@menu
+* Programma dupword:: Trovare parole duplicate in un documento.
+* Programma alarm:: Un programma di sveglia.
+* Programma translate:: Un programma simile al programma di utilit@`a
+ @command{tr}.
+* Programma labels:: Stampare etichette per lettere.
+* Programma utilizzo parole:: Un programma per produrre un contatore
+ dell'uso di parole in un testo.
+* Programma riordino diario:: Eliminare righe doppie da un file di
+ cronologia.
+* Programma extract :: Estrarre programmi da file sorgenti Texinfo.
+* Programma sed semplice:: Un semplice editor di flusso.
+* Programma igawk:: Un programma per fornire ad
+ @command{awk} la possibilit@`a di includere
+ file.
+* Programma anagram:: Trovare anagrammi da una lista di parole.
+* Programma signature:: La gente fa cose stupefacenti se ha troppo
+ tempo libero.
+@end menu
+
+@node Programma dupword
+@subsection Trovare parole duplicate in un documento
+
+@cindex parole duplicate, ricerca di
+@cindex ricerca di parole
+@cindex documenti@comma{} ricerca in
+Un errore comune quando si scrive un testo lungo @`e quello di ripetere
+accidentalmente delle parole. Tipicamente lo si pu@`o vedere in testi del tipo
+``questo questo programma fa quanto segue@dots{}'' Quando il testo @`e pubblicato in rete, spesso
+le parole duplicate sono poste tra il termine di
+@iftex
+di
+@end iftex
+una riga e l'inizio di un'altra, il che rende difficile scoprirle.
+@c as here!
+
+Questo programma, @file{dupword.awk}, legge un file una riga alla volta
+e cerca le occorrenze adiacenti della stessa parola. Conserva anche
+l'ultima parola di ogni riga (nella variabile @code{precedente}) per
+confrontarla con la prima parola sulla riga successiva.
+
+@cindex Texinfo
+Le prime due istruzioni fanno s@`{@dotless{i}} che la riga sia tutta in minuscolo,
+in modo che, per esempio, ``Il'' e ``il'' risultino essere la stessa parola.
+L'istruzione successiva sostituisce i caratteri che sono non alfanumerici e
+diversi dagli
+spazi bianchi con degli spazi, in modo che neppure la punteggiatura influenzi
+i confronti.
+I caratteri sono rimpiazzati da spazi in modo che i controlli di formattazione
+non creino parole prive di senso (p.es., l'espressione Texinfo
+@samp{@@code@{NF@}} diventa @samp{codeNF}, se ci si limita a eliminare la
+punteggiatura). Il record @`e poi
+suddiviso di nuovo in campi, producendo cos@`{@dotless{i}} solo la lista delle parole
+presenti sulla riga, esclusi eventuali campi nulli.
+
+Se, dopo aver rimosso tutta la punteggiatura, non rimane alcun campo, il
+record corrente @`e saltato. In caso contrario, il programma esegue il ciclo
+per ogni parola, confrontandola con quella che la precede:
+
+@cindex @code{dupword.awk}, programma
+@cindex programma @code{dupword.awk}
+@example
+@c file eg/prog/dupword.awk
+# dupword.awk --- trova parole duplicate in un testo
+@c endfile
+@ignore
+@c file eg/prog/dupword.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# December 1991
+# Revised October 2000
+
+@c endfile
+@end ignore
+@c file eg/prog/dupword.awk
+@{
+ $0 = tolower($0)
+ gsub(/[^[:alnum:][:blank:]]/, " ");
+ $0 = $0 # divide di nuovo in campi
+ if (NF == 0)
+ next
+ if ($1 == prec)
+ printf("%s:%d: duplicato %s\n",
+ nome_file, FNR, $1)
+ for (i = 2; i <= NF; i++)
+ if ($i == $(i-1))
+ printf("%s:%d: duplicato %s\n",
+ nome_file, FNR, $i)
+ prec = $NF
+@}
+@c endfile
+@end example
+
+@node Programma alarm
+@subsection Un programma di sveglia
+@cindex insonnia, cura per
+@cindex Robbins, Arnold
+@quotation
+@i{Nessuna cura contro l'insonnia @`e efficace quanto una sveglia che suona.}
+@author Arnold Robbins
+@end quotation
+@cindex Quanstrom, Erik
+@ignore
+Date: Sat, 15 Feb 2014 16:47:09 -0500
+Subject: Re: 9atom install question
+Message-ID: <l2jcvx6j6mey60xnrkb0hhob.1392500829294@email.android.com>
+From: Erik Quanstrom <quanstro@quanstro.net>
+To: Aharon Robbins <arnold@skeeve.com>
+
+yes.
+
+- erik
+
+Aharon Robbins <arnold@skeeve.com> wrote:
+
+>> sleep is for web developers.
+>
+>Can I quote you, in the gawk manual?
+>
+>Thanks,
+>
+>Arnold
+@end ignore
+@quotation
+@i{Il sonno @`e per sviluppatori web.}
+@author Erik Quanstrom
+@end quotation
+
+@cindex tempo, sveglia, programma di esempio
+@cindex sveglia, programma di esempio
+Il seguente programma @`e un semplice programma di ``sveglia''.
+Si pu@`o specificare un'ora del giorno e un messaggio opzionale. All'ora
+specificata, il programma stampa il messaggio sullo standard output. Inoltre,
+si pu@`o specificare il numero di volte in cui il messaggio va ripetuto, e
+anche un intervallo di tempo (ritardo) tra ogni ripetizione.
+
+Questo programma usa la funzione @code{getlocaltime()}
+@iftex
+dalla
+@end iftex
+@ifnottex
+da
+@end ifnottex
+@ref{Funzione getlocaltime}.
+
+Tutto il lavoro @`e svolto nella regola @code{BEGIN}. La prima parte @`e
+il controllo degli argomenti e l'impostazione dei valori di default:
+l'intervallo prima di ripetere, il contatore, e il messaggio da stampare.
+Se l'utente ha fornito un messaggio che non contiene il carattere ASCII BEL
+(noto come carattere ``campanello'', @code{"\a"}), questo viene aggiunto al
+messaggio. (Su molti sistemi, stampare il carattere ASCII BEL genera un suono
+udibile. Quindi, quando la sveglia suona, il sistema richiama l'attenzione
+su di s@'e nel caso che l'utente non stia guardando il computer.)
+Per amor di variet@`a, questo programma usa un'istruzione @code{switch}
+(@pxref{Istruzione switch}), ma l'elaborazione potrebbe anche essere fatta
+con una serie di istruzioni @code{if}-@code{else}.
+Ecco il programma:
+
+@cindex @code{alarm.awk}, programma
+@cindex programma @code{alarm.awk}
+@example
+@c file eg/prog/alarm.awk
+# alarm.awk --- impostare una sveglia
+#
+# Richiede la funzione di libreria getlocaltime()
+@c endfile
+@ignore
+@c file eg/prog/alarm.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised December 2010
+
+@c endfile
+@end ignore
+@c file eg/prog/alarm.awk
+# sintassi: alarm a_che_ora [ "messaggio" [ contatore [ ritardo ] ] ]
+
+BEGIN @{
+ # Controllo iniziale congruit@`a argomenti
+ sintassi1 = "sintassi: alarm a_che_ora ['messaggio' [contatore [ritardo]]]"
+ sintassi2 = sprintf("\t(%s) formato ora: ::= hh:mm", ARGV[1])
+
+ if (ARGC < 2) @{
+ print sintassi1 > "/dev/stderr"
+ print sintassi2 > "/dev/stderr"
+ exit 1
+ @}
+ switch (ARGC) @{
+ case 5:
+ ritardo = ARGV[4] + 0
+ # vai al caso seguente
+ case 4:
+ contatore = ARGV[3] + 0
+ # vai al caso seguente
+ case 3:
+ messaggio = ARGV[2]
+ break
+ default:
+ if (ARGV[1] !~ /[[:digit:]]?[[:digit:]]:[[:digit:]]@{2@}/) @{
+ print sintassi1 > "/dev/stderr"
+ print sintassi2 > "/dev/stderr"
+ exit 1
+ @}
+ break
+ @}
+
+ # imposta i valori di default per quando arriva l'ora desiderata
+ if (ritardo == 0)
+ ritardo = 180 # 3 minuti
+@group
+ if (contatore == 0)
+ contatore = 5
+@end group
+ if (messaggio == "")
+ messaggio = sprintf("\aAdesso sono le %s!\a", ARGV[1])
+ else if (index(message, "\a") == 0)
+ messaggio = "\a" messaggio "\a"
+@c endfile
+@end example
+
+La successiva @value{SECTION} di codice scompone l'ora specificata in ore e
+minuti, la converte (se @`e il caso) al formato 24-ore, e poi calcola il
+relativo numero di secondi dalla mezzanotte. Poi trasforma l'ora corrente in
+un contatore dei secondi dalla
+mezzanotte. La differenza tra i due @`e il tempo di attesa che deve passare
+prima di far scattare la sveglia:
+
+@example
+@c file eg/prog/alarm.awk
+ # scomponi ora della sveglia
+ split(ARGV[1], ore_minuti, ":")
+ ora = ore_minuti[1] + 0 # trasforma in numero
+ minuto = ore_minuti[2] + 0 # trasforma in numero
+
+ # ottiene ora corrente divisa in campi
+ getlocaltime(adesso)
+
+ # se l'ora desiderata @`e in formato 12-ore ed @`e nel pomeriggio
+ # (p.es., impostare `alarm 5:30' alle 9 del mattino
+ # vuol dire far suonare la sveglia alle 5:30 pomeridiane)
+ # aggiungere 12 all'ora richiesta
+ if (hour < 12 && adesso["hour"] > ora)
+ ora += 12
+
+ # imposta l'ora in secondi dalla mezzanotte
+ sveglia = (ora * 60 * 60) + (minuto * 60)
+
+ # ottieni l'ora corrente in secondi dalla mezzanotte
+ corrente = (now["hour"] * 60 * 60) + \
+ (now["minute"] * 60) + now["second"]
+
+ # quanto restare appisolati
+ sonno = sveglia - corrente
+ if (sonno <= 0) @{
+ print "alarm: l'ora @`e nel passato!" > "/dev/stderr"
+ exit 1
+ @}
+@c endfile
+@end example
+
+@cindex @command{sleep}, programma di utilit@`a
+@cindex programma di utilit@`a @command{sleep}
+Infine, il programma usa la funzione @code{system()}
+(@pxref{Funzioni di I/O})
+per chiamare il programma di utilit@`a @command{sleep}. Il programma di utilit@`a
+@command{sleep} non fa altro che aspettare per il numero di secondi
+specificato. Se il codice di ritorno restituito @`e diverso da zero, il
+programma suppone che @command{sleep} sia stato interrotto ed esce. Se
+@command{sleep} @`e terminato con un codice di ritorno corretto, (zero), il
+programma stampa il messaggio in un ciclo, utilizzando ancora @command{sleep}
+per ritardare per il numero di secondi necessario:
+
+@example
+@c file eg/prog/alarm.awk
+ # zzzzzz..... esci se sleep @`e interrotto
+ if (system(sprintf("sleep %d", sonno)) != 0)
+ exit 1
+
+ # @`e ora di avvisare!
+ command = sprintf("sleep %d", ritardo)
+ for (i = 1; i <= contatore; i++) @{
+ print messaggio
+ # se il comando sleep @`e interrotto, esci
+ if (system(command) != 0)
+ break
+ @}
+
+ exit 0
+@}
+@c endfile
+@end example
+
+@node Programma translate
+@subsection Rimpiazzare o eliminare caratteri
+
+@cindex caratteri, rimpiazzare
+@cindex rimpiazzare caratteri
+@cindex @command{tr}, programma di utilit@`a
+@cindex programma di utilit@`a @command{tr}
+Il programma di utilit@`a di sistema @command{tr} rimpiazza caratteri. Per
+esempio, @`e spesso usato per trasformare lettere maiuscole in lettere minuscole
+in vista di ulteriori elaborazioni:
+
+@example
+@var{generare dei dati} | tr 'A-Z' 'a-z' | @var{elaborare dei dati} @dots{}
+@end example
+
+@command{tr} richiede due liste di caratteri.@footnote{Su alcuni sistemi
+pi@`u datati, incluso Solaris, la versione di sistema di @command{tr} pu@`o
+richiedere che le liste siano scritte come espressioni di intervallo,
+racchiuse in parentesi quadre
+(@samp{[a-z]}) e tra apici, per evitare che la shell effettui
+espansioni di @value{FN}. Questo non @`e un miglioramento.} Quando
+si elabora l'input, il primo carattere della prima lista @`e rimpiazzato con il
+primo carattere della seconda lista, il secondo carattere della prima lista @`e
+rimpiazzato con il secondo carattere della seconda lista, e cos@`{@dotless{i}} via. Se ci
+sono pi@`u caratteri nella lista ``da'' che in quella ``a'', l'ultimo carattere
+della lista ``a'' @`e usato per i restanti caratteri della lista ``da''.
+
+In un lontano passato,
+@c early or mid-1989!
+un utente propose di aggiungere una funzione di traslitterazione a
+@command{gawk}.
+@c Wishing to avoid gratuitous new features,
+@c at least theoretically
+Il programma seguente @`e stato scritto per dimostrare che la traslitterazione
+di caratteri poteva essere fatta con una funzione definita dall'utente.
+Questo programma non @`e cos@`{@dotless{i}} completo come il programma di utilit@`a di sistema
+@command{tr}, ma svolge buona parte dello stesso lavoro.
+
+Il programma @command{translate} @`e stato scritto molto prima che @command{gawk}
+fosse in grado di separare ciascun carattere di una stringa in elementi
+distinti di un vettore. Questo @`e il motivo per cui usa ripetutamente le
+funzioni predefinite @code{substr()}, @code{index()}, e @code{gsub()}
+(@pxref{Funzioni per stringhe}).
+Ci sono due funzioni. La prima, @code{traduci_stringa()},
+richiede tre argomenti:
+
+@table @code
+@item da
+Una lista di caratteri da cui traslitterare
+
+@item a
+Una lista di caratteri a cui traslitterare
+
+@item stringa
+La stringa su cui effettuare la traslitterazione
+@end table
+
+I vettori associativi facilitano molto la parte di traslitterazione.
+@code{vettore_trad} contiene i caratteri ``a'', indicizzato dai
+caratteri ``da''. Poi un semplice
+ciclo scandisce @code{da}, un carattere alla volta. Per ogni carattere
+in @code{da}, se il carattere compare in @code{stringa}
+@`e rimpiazzato con il corrispondente carattere @code{a}.
+
+La funzione @code{traducilo()} chiama @code{traduci_stringa()}, usando @code{$0}
+come stringa. Il programma principale imposta due variabili globali, @code{DA} e
+@code{A}, dalla riga di comando, e poi modifica @code{ARGV} in modo che
+@command{awk} legga dallo standard input.
+
+Infine, la regola di elaborazione si limita a chiamare @code{traducilo()}
+per ogni record:
+
+@cindex @code{translate.awk}, programma
+@cindex programma @code{translate.awk}
+@example
+@c file eg/prog/translate.awk
+# translate.awk --- fa cose simili al comando tr
+@c endfile
+@ignore
+@c file eg/prog/translate.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# August 1989
+# February 2009 - bug fix
+
+@c endfile
+@end ignore
+@c file eg/prog/translate.awk
+# Bug: non gestisce cose del tipo tr A-Z a-z; deve essere
+# descritto carattere per carattere.
+# Tuttavia, se `a' @`e pi@`u corto di `da',
+# l'ultimo carattere in `a' @`e usato per il resto di `da'.
+
+function traduci_stringa(da, a, stringa, lf, lt, lstringa, vettore_trad,
+ i, c, risultato)
+@{
+ lf = length(da)
+ lt = length(a)
+ lstringa = length(stringa)
+ for (i = 1; i <= lt; i++)
+ vettore_trad[substr(da, i, 1)] = substr(a, i, 1)
+ if (lt < lf)
+ for (; i <= lf; i++)
+ vettore_trad[substr(da, i, 1)] = substr(a, lt, 1)
+ for (i = 1; i <= lstringa; i++) @{
+ c = substr(stringa, i, 1)
+ if (c in vettore_trad)
+ c = vettore_trad[c]
+ risultato = risultato c
+ @}
+ return risultato
+@}
+
+function traducilo(da, a)
+@{
+ return $0 = traduci_stringa(da, a, $0)
+@}
+
+# programma principale
+BEGIN @{
+@group
+ if (ARGC < 3) @{
+ print "sintassi: translate da a" > "/dev/stderr"
+ exit
+ @}
+@end group
+ DA = ARGV[1]
+ A = ARGV[2]
+ ARGC = 2
+ ARGV[1] = "-"
+@}
+
+@{
+ traducilo(DA, A)
+ print
+@}
+@c endfile
+@end example
+
+@`E possibile effettuare la traslitterazione di caratteri in una funzione a
+livello utente, ma non @`e detto che sia efficiente, e noi (sviluppatori
+di @command{gawk}) abbiamo iniziato a prendere in considerazione l'aggiunta di una funzione.
+Tuttavia, poco dopo aver scritto questo programma, abbiamo saputo che Brian
+Kernighan aveva aggiunto le funzioni @code{toupper()} e @code{tolower()} alla
+sua versione di @command{awk} (@pxref{Funzioni per stringhe}). Queste
+funzioni gestiscono la maggior parte dei casi in cui serva la traslitterazione
+di caratteri, e quindi abbiamo deciso di limitarci ad aggiungere le stesse
+funzioni a @command{gawk}, e di disinteressarci del resto.
+
+Un miglioramento ovvio a questo programma sarebbe di impostare il vettore
+@code{vettore_trad} solo una volta, in una regola @code{BEGIN}. Tuttavia, ci@`o
+presuppone che le liste ``da'' e ``a'' non cambino mai durante tutta
+l'esecuzione del programma.
+
+Un altro miglioramento ovvio @`e di consentire l'uso di intervalli, come
+@samp{a-z}, come consentito dal programma di utilit@`a @command{tr}. Si pu@`o
+trarre ispirazione dal codice di @file{cut.awk} (@pxref{Programma cut}).
+
+
+@node Programma labels
+@subsection Stampare etichette per lettere
+
+@cindex stampare etichette per lettera
+@cindex etichette per lettera@comma{} stampare
+Ecco un programma ``del mondo-reale''@footnote{``Del mondo-reale'' @`e definito
+come ``un programma effettivamente usato per realizzare qualcosa''.}.
+Questo script legge elenchi di nomi e indirizzi, e genera etichette per
+lettera. Ogni pagina di etichette contiene 20 etichette, su due file da 10
+etichette l'una. Gli indirizzi non possono contenere pi@`u di cinque righe di
+dati. Ogni indirizzo @`e separato dal successivo da una riga bianca.
+
+L'idea di base @`e di leggere dati per 20 etichette. Ogni riga di ogni etichetta
+@`e immagazzinata nel vettore @code{riga}. L'unica regola si occupa di riempire
+il vettore @code{riga} e di stampare la pagina dopo che sono state lette 20
+etichette.
+
+La regola @code{BEGIN} si limita a impostare @code{RS} alla stringa vuota, in
+modo che @command{awk} divida un record dal successivo quando incontra una riga
+bianca.
+(@pxref{Record}).
+Inoltre imposta @code{LIMITE_LINEE} a 100,
+perch@'e 100 @`e il massimo numero di righe sulla pagina
+@iftex
+(@math{20 @cdot 5 = 100}).
+@end iftex
+@ifnottex
+@ifnotdocbook
+(20 * 5 = 100).
+@end ifnotdocbook
+@end ifnottex
+@docbook
+(20 &sdot; 5 = 100).
+@end docbook
+
+Il grosso del lavoro @`e svolto nella funzione @code{stampa_pagina()}.
+Le righe che compongono le etichette sono immagazzinate sequenzialmente nel vettore
+@code{riga}. Ma occorre stamparle in
+orizzontale: @code{riga[1]} a fianco di @code{riga[6]}, @code{riga[2]} a
+fianco di @code{riga[7]}, e cos@`{@dotless{i}} via. Questo si pu@`o fare utilizzando due
+cicli. Quello pi@`u esterno, controllato dalla variabile @code{i}, gestisce 10
+righe di dati, ovvero la stampa di due etichette una a fianco dell'altra.
+Il ciclo pi@`u interno
+controllato dalla variabile @code{j}, gestisce le singole righe che compongono
+ognuno degli indirizzi.
+Poich@'e @code{j} varia da 0 a 4, @samp{i+j} @`e la riga @code{j}-esima
+dell'indirizzo di sinistra, e @samp{i+j+5} @`e quella stampata alla sua destra.
+L'output @`e simile a quello mostrato qui sotto:
+
+@example
+riga 1 riga 6
+riga 2 riga 7
+riga 3 riga 8
+riga 4 riga 9
+riga 5 riga 10
+@dots{}
+@end example
+
+@noindent
+La stringa di formato per @code{printf} @samp{%-41s} allinea a
+sinistra i dati, e li stampa in un campo di lunghezza fissa.
+
+Come nota finale, un'ulteriore riga bianca extra viene stampata alle righe 21 e
+61, per mantenere entro i bordi l'output sulle etichette. Ci@`o dipende dalla
+particolare marca di etichette in uso quando il programma @`e stato scritto.
+Si noti anche che ci sono due righe bianche a inizio pagina e due righe
+bianche a fine pagina.
+
+La regola @code{END} si occupa di stampare l'ultima pagina di
+etichette; @`e improbabile che il numero di indirizzi da stampare sia un
+multiplo esatto di 20:
+
+@cindex @code{labels.awk}, programma
+@cindex programma @code{labels.awk}
+@example
+@c file eg/prog/labels.awk
+# labels.awk --- stampare etichette per lettera
+@c endfile
+@ignore
+@c file eg/prog/labels.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# June 1992
+# December 2010, minor edits
+@c endfile
+@end ignore
+@c file eg/prog/labels.awk
+
+# Ogni etichetta @`e 5 righe di dati, qualcuna delle quali pu@`o essere bianca.
+# I fogli con le etichetta hanno 2 righe bianche in cima alla pagina e altre 2
+# a fine pagina.
+
+BEGIN @{ RS = "" ; LIMITE_LINEE = 100 @}
+
+function stampa_pagina( i, j)
+@{
+ if (NUMEROrighe <= 0)
+ return
+
+ printf "\n\n" # in cima
+
+ for (i = 1; i <= NUMEROrighe; i += 10) @{
+ if (i == 21 || i == 61)
+ print ""
+ for (j = 0; j < 5; j++) @{
+ if (i + j > LIMITE_LINEE)
+ break
+ printf " %-41s %s\n", riga[i+j], riga[i+j+5]
+ @}
+ print ""
+ @}
+
+ printf "\n\n" # in fondo
+
+ delete riga
+@}
+
+# regola principale
+@{
+ if (contatore >= 20) @{
+ stampa_pagina()
+ contatore = 0
+ NUMEROrighe = 0
+ @}
+ n = split($0, a, "\n")
+ for (i = 1; i <= n; i++)
+ riga[++NUMEROrighe] = a[i]
+ for (; i <= 5; i++)
+ riga[++NUMEROrighe] = ""
+ contatore++
+@}
+
+END @{
+ stampa_pagina()
+@}
+@c endfile
+@end example
+
+@node Programma utilizzo parole
+@subsection Generare statistiche sulla frequenza d'uso delle parole
+
+@cindex parole, statistica utilizzo delle
+@cindex statistica utilizzo delle parole
+
+Quando si lavora con una grande quantit@`a di testo, pu@`o essere interessante
+sapere quanto spesso ricorrono le diverse parole. Per esempio, un autore pu@`o
+fare un uso eccessivo di certe parole, e in questo caso si potrebbero
+trovare sinonimi da sostituire a
+parole che appaiono troppo spesso.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SUBSECTION} spiega come
+scrivere un programma per contare le parole e presentare in un formato
+utile le informazioni relative alla loro frequenza.
+
+A prima vista, un programma come questo sembrerebbe essere sufficiente:
+
+@example
+# wordfreq-first-try.awk --- stampa lista frequenze utilizzo parole
+
+@{
+ for (i = 1; i <= NF; i++)
+ freq[$i]++
+@}
+
+END @{
+ for (word in freq)
+ printf "%s\t%d\n", word, freq[word]
+@}
+@end example
+
+Il programma si affida al meccanismo con cui @command{awk} divide i campi per
+default, per suddividere ogni riga in ``parole'' e usa un vettore associativo
+di nome @code{freq}, che ha per indici le singole parole, per contare il
+numero di volte che ogni parola viene usata. Nella regola @code{END}, stampa i
+contatori.
+
+Questo programma ha parecchi problemi che lo rendono praticamente inutile
+su file di testo reali:
+
+@itemize @value{BULLET}
+@item
+Il linguaggio @command{awk} considera i caratteri maiuscoli e minuscoli come
+distinti (non equivalenti). Quindi, ``barista'' e ``Barista'' sono
+considerate parole differenti. Questo non @`e un comportamento auspicabile,
+perch@'e le parole iniziano con la lettera maiuscola se sono a inizio frase in
+un testo normale, e un analizzatore di frequenze dovrebbe ignorare la
+distinzione maiuscolo/minuscolo.
+
+@item
+Le parole sono individuate usando la convenzione @command{awk} secondo cui i
+campi sono separati solo da spazi bianchi. Altri caratteri nell'input
+(tranne il ritorno a capo) non hanno alcun particolare significato per
+@command{awk}. Questo significa che i segni di interpunzione sono visti come
+parte di una parola.
+
+@item
+L'output non @`e scritto in alcun ordine utile. Si @`e probabilmente pi@`u
+interessati a sapere quali parole ricorrono pi@`u di frequente, o ad avere
+una tabella in ordine alfabetico che mostra quante volte ricorre ogni parola.
+@end itemize
+
+@cindex @command{sort}, programma di utilit@`a
+@cindex programma di utilit@`a @command{sort}
+Il primo problema si pu@`o risolvere usando @code{tolower()} per rimuovere la
+distinzione maiuscolo/minuscolo. Il secondo problema si pu@`o risolvere usando
+@code{gsub()} per rimuovere i caratteri di interpunzione. Infine, per
+risolvere il terzo problema si pu@`o usare il programma di utilit@`a
+@command{sort} per elaborare l'output dello script @command{awk}. Ecco la
+nuova versione del programma:
+
+@cindex @code{wordfreq.awk}, programma
+@cindex programma @code{wordfreq.awk}
+@example
+@c file eg/prog/wordfreq.awk
+# wordfreq.awk --- stampa la lista con la frequenza delle parole
+
+@{
+ $0 = tolower($0) # togli maiuscolo/minuscolo
+ # togli interpunzione
+ gsub(/[^[:alnum:]_[:blank:]]/, "", $0)
+ for (i = 1; i <= NF; i++)
+ freq[$i]++
+@}
+
+@c endfile
+END @{
+ for (word in freq)
+ printf "%s\t%d\n", word, freq[word]
+@}
+@end example
+
+La @dfn{regexp} @code{/[^[:alnum:]_[:blank:]]/} si poteva scrivere come
+@code{/[[:punct:]]/}, ma in questo modo il caratteri trattino basso sarebbe
+stato rimosso, mentre si desidera conservarlo.
+
+Supponendo di aver salvato questo programma in un file di nome
+@file{wordfreq.awk},
+e che i dati siano in @file{file1}, il seguente comando con @dfn{pipeline}:
+
+@example
+awk -f wordfreq.awk file1 | sort -k 2nr
+@end example
+
+@noindent
+produce una tabella delle parole che appaiono in @file{file1} in ordine
+descrescente di frequenza.
+
+Il programma @command{awk} da solo gestisce adeguatamente i dati e produce
+una tabella delle frequenza che non @`e ordinata.
+L'output di @command{awk} @`e poi messo in ordine dal programma di utilit@`a
+@command{sort} e stampato sullo schermo.
+
+Le opzioni passate a @command{sort}
+richiedono un ordinamento che usi come chiave il secondo campo di ogni riga
+in input (saltando il primo campo), che le chiavi di ordinamento siano
+trattate come quantit@`a numeriche
+(altrimenti @samp{15} sarebbe stampato prima di @samp{5}), e che l'ordinamento
+sia fatto in ordine decrescente (inverso).
+
+Il comando @command{sort} potrebbe anche essere richiamato dall'interno del
+programma, cambiando l'azione da fare nella regola @code{END} a:
+
+@example
+@c file eg/prog/wordfreq.awk
+END @{
+ sort = "sort -k 2nr"
+ for (word in freq)
+ printf "%s\t%d\n", word, freq[word] | sort
+ close(sort)
+@}
+@c endfile
+@end example
+
+Questa maniera di ordinare dev'essere usata su sistemi che non hanno delle
+vere e proprie @dfn{pipe} a livello di riga di comando (o di procedura di
+comandi).
+Si veda la documentazione generale riguardo al sistema operativo per maggiori
+informazioni su come usare il programma @command{sort}.
+
+@node Programma riordino diario
+@subsection Eliminare duplicati da un file non ordinato
+
+@cindex righe, duplicate@comma{} rimuovere
+@cindex rimuovere righe duplicate
+Il programma @command{uniq}
+(@pxref{Programma uniq})
+rimuove righe duplicate da dati @emph{ordinati}.
+
+Si supponga, tuttavia, di dover rimuovere righe duplicate da un @value{DF},
+ma di voler conservare l'ordine in cui le righe sono state scritte. Un buon
+esempio di questo tipo potrebbe essere un file della cronologia dei comandi
+della shell. Il file della cronologia dei comandi
+mantiene copia di tutti i comandi che sono stati dati, e non @`e
+insolito ripetere un comando molte volte di fila. Occasionalmente si
+potrebbe voler compattare la cronologia togliendo le righe duplicate.
+Tuttavia sarebbe opportuno mantenere l'ordine originale dei comandi.
+
+Questo semplice programma fa questo. Usa due vettori. Il vettore @code{dati}
+ha come indice il testo di ogni riga.
+Per ogni riga, @code{dati[$0]} @`e incrementato di uno.
+Se una particolare riga non @`e stata ancora vista, @code{dati[$0]} @`e zero.
+In tal caso, il testo della riga @`e immagazzinato in @code{righe[contatore]}.
+Ogni elemento del vettore @code{righe} @`e un comando unico, e gli
+indici di @code{righe} indicano l'ordine in cui quelle righe sono state
+incontrate.
+La regola @code{END} stampa semplicemente le righe, in ordine:
+
+@cindex Rakitzis, Byron
+@cindex @code{histsort.awk}, programma
+@cindex programma @code{histsort.awk}
+@example
+@c file eg/prog/histsort.awk
+# histsort.awk --- compatta un file della cronologia dei comandi della shell
+# Grazie a Byron Rakitzis per l'idea generale
+@c endfile
+@ignore
+@c file eg/prog/histsort.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+@c endfile
+@end ignore
+@c file eg/prog/histsort.awk
+
+@group
+@{
+ if (dati[$0]++ == 0)
+ righe[++contatore] = $0
+@}
+@end group
+
+@group
+END @{
+ for (i = 1; i <= contatore; i++)
+ print righe[i]
+@}
+@end group
+@c endfile
+@end example
+
+Questo programma pu@`o essere un punto di partenza per generare altre
+informazioni utili.
+Per esempio, usando la seguente istruzione @code{print} nella regola
+@code{END} permette di sapere quante volte viene usato un certo comando:
+
+@example
+print dati[righe[i]], righe[i]
+@end example
+
+@noindent
+Questo si pu@`o fare perch@'e @code{dati[$0]} @`e incrementato ogni volta che una
+riga @`e stata trovata.
+
+@node Programma extract
+@subsection Estrarre programmi da un file sorgente Texinfo
+
+@cindex Texinfo, estrarre programma da file sorgente
+@cindex estrarre programma da file sorgente Texinfo
+@cindex file Texinfo, estrarre programma da
+@ifnotinfo
+Sia questo capitolo che il precedente
+(@ref{Funzioni di libreria})
+presentano un numero elevato di programmi @command{awk}.
+@end ifnotinfo
+@ifinfo
+I nodi
+@ref{Funzioni di libreria},
+e @ref{Programmi di esempio},
+sono nodi al livello pi@`u elevato, e
+contengono nodi che descrivono un numero elevato di programmi @command{awk}.
+@end ifinfo
+Se si vuole fare pratica con questi programmi, @`e fastidioso doverli
+digitare di nuovo manualmente. @`E per questo che abbiamo pensato a un programma
+in grado di estrarre parti di un file in input Texinfo e metterli in file
+separati.
+
+@cindex Texinfo
+Questo @value{DOCUMENT} @`e scritto in @uref{http://www.gnu.org/software/texinfo/, Texinfo},
+il programma di formattazione di documenti del progetto GNU.
+Un solo file sorgente Texinfo pu@`o essere usato per produrre sia la
+documentazione stampata, usando @TeX{}, sia quella online.
+@ifnotinfo
+(Texinfo @`e esaurientemente documentato nel libro
+@cite{Texinfo---The GNU Documentation Format},
+disponibile alla Free Software Foundation,
+e anche @uref{http://www.gnu.org/software/texinfo/manual/texinfo/, online}.)
+@end ifnotinfo
+@ifinfo
+(Il linguaggio Texinfo @`e descritto esaurientemente, a partire da
+@inforef{Top, , Texinfo, texinfo,Texinfo---The GNU Documentation Format}.)
+@end ifinfo
+
+Per quel che ci riguarda, @`e sufficiente sapere tre cose riguardo ai file di
+input Texinfo:
+
+@itemize @value{BULLET}
+@item
+Il simbolo ``chiocciola'' (@samp{@@}) @`e speciale per
+Texinfo, proprio come la barra inversa (@samp{\}) lo @`e per il linguaggio C
+o per @command{awk}. I simboli @samp{@@} sono rappresentati nel sorgente
+Texinfo come @samp{@@@@}.
+
+@item
+I commenti iniziano con @samp{@@c} o con @samp{@@comment}.
+Il programma di estrazione file funziona usando dei commenti speciali che
+sono posti all'inizio di una riga.
+
+@item
+Righe contenenti comandi @samp{@@group} e @samp{@@end group} racchiudono testi
+di esempio che non dovrebbero andare a cavallo di due pagine.
+(Sfortunatamente, @TeX{} non @`e sempre in grado di fare le cose in maniera
+esatta, e quindi va un po' aiutato).
+@end itemize
+
+Il programma seguente, @file{extract.awk}, legge un file sorgente Texinfo
+e fa due cose, basandosi sui commenti speciali.
+Dopo aver visto il commento @samp{@w{@@c system @dots{}}},
+esegue un comando, usando il testo del comando contenuto nella
+riga di controllo e passandolo alla funzione @code{system()}
+(@pxref{Funzioni di I/O}).
+Dopo aver trovato il commento @samp{@@c file @var{nome_file}}, ogni riga
+successiva @`e spedita al file @var{nome_file}, fino a che si trova un
+commento @samp{@@c endfile}.
+Le regole in @file{extract.awk} sono soddisfatte sia quando incontrano
+@samp{@@c} che quando incontrano @samp{@@comment} e quindi la parte
+@samp{omment} @`e opzionale.
+Le righe che contengono @samp{@@group} e @samp{@@end group} sono semplicemente
+ignorate.
+@file{extract.awk} usa la funzione di libreria @code{join()}
+(@pxref{Funzione join}).
+
+I programmi di esempio nel sorgente Texinfo online di @cite{@value{TITLE}}
+(@file{gawktexi.in}) sono stati tutti inseriti tra righe @samp{file} e righe
+@samp{endfile}. La distribuzione di @command{gawk} usa una copia di
+@file{extract.awk} per estrarre i programmi di esempio e per installarne
+molti in una particolare directory dove @command{gawk} li pu@`o trovare.
+Il file Texinfo ha un aspetto simile a questo:
+
+@example
+@dots{}
+Questo programma ha una regola @@code@{BEGIN@}
+che stampa un messaggio scherzoso:
+
+@@example
+@@c file esempi/messages.awk
+BEGIN @@@{ print "Non v'allarmate!" @@@}
+@@c endfile
+@@end example
+
+Stampa anche qualche avviso conclusivo:
+
+@@example
+@@c file esempi/messages.awk
+END @@@{ print "Evitate sempre gli archeologi annoiati!" @@@}
+@@c endfile
+@@end example
+@dots{}
+@end example
+
+Il programma @file{extract.awk} inizia con l'impostare @code{IGNORECASE} a
+uno, in modo che un miscuglio di lettere maiuscole e minuscole nelle direttive
+non faccia differenza.
+
+La prima regola gestisce le chiamate a @code{system()}, controllando che sia
+stato fornito un comando (@code{NF} dev'essere almeno tre) e controllando
+anche che il comando termini con un codice di ritorno uguale a zero, che sta
+a significare che tutto @`e andato bene:
+
+@cindex @code{extract.awk}, programma
+@cindex programma @code{extract.awk}
+@example
+@c file eg/prog/extract.awk
+# extract.awk --- estrae file ed esegue programmi dal file Texinfo
+@c endfile
+@ignore
+@c file eg/prog/extract.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# May 1993
+# Revised September 2000
+@c endfile
+@end ignore
+@c file eg/prog/extract.awk
+
+BEGIN @{ IGNORECASE = 1 @}
+
+/^@@c(omment)?[ \t]+system/ @{
+ if (NF < 3) @{
+ e = ("extract: " FILENAME ":" FNR)
+ e = (e ": riga `system' con formato errato")
+ print e > "/dev/stderr"
+ next
+ @}
+ $1 = ""
+ $2 = ""
+ stat = system($0)
+ if (stat != 0) @{
+ e = ("extract: " FILENAME ":" FNR)
+ e = (e ": attenzione: system ha restituito " stat)
+ print e > "/dev/stderr"
+ @}
+@}
+@c endfile
+@end example
+
+@noindent
+La variabile @code{e} @`e stata usata per far s@`{@dotless{i}} che la regola
+sia agevolemente contenuta nella @value{PAGE}.
+
+La seconda regola gestisce il trasferimento di dati in un file. Verifica che
+nella direttiva sia stato fornito un @value{FN}.
+Se il nome del file non @`e quello del file corrente, il file
+corrente viene chiuso. Mantenere aperto il file corrente finch@'e non si trova
+un nuovo nome file permette di usare la ridirezione @samp{>} per stampare i
+contenuti nel file, semplificando la gestione dei file aperti.
+
+Il ciclo @code{for} esegue il lavoro. Legge le righe usando @code{getline}
+(@pxref{Getline}).
+Se si raggiunge una fine-file inattesa, viene chiamata la funzione
+@code{@w{fine_file_inattesa()}}. Se la riga @`e una riga ``endfile'',
+il ciclo viene abbandonato.
+Se la riga inizia con @samp{@@group} o @samp{@@end group}, la riga viene
+ignorata, e si passa a quella seguente. Allo stesso modo, eventuali commenti
+all'interno degli esempi vengono ignorati.
+
+Il grosso del lavoro @`e nelle poche righe che seguono. Se la riga non ha
+simboli @samp{@@}, il programma la pu@`o
+stampare cos@`{@dotless{i}} com'@`e. Altrimenti, ogni @samp{@@} a inizio parola dev'essere
+eliminato.
+Per rimuovere i simboli @samp{@@}, la riga viene divisa nei singoli elementi
+del vettore @code{a}, usando la funzione @code{split()}
+(@pxref{Funzioni per stringhe}).
+Il simbolo @samp{@@} @`e usato come carattere di separazione.
+Ogni elemento del vettore @code{a} che risulti vuoto indica due caratteri
+@samp{@@} contigui nella riga originale. Per ogni due elementi vuoti
+(@samp{@@@@} nel file originale), va inserito un solo simbolo @samp{@@} nel
+file in output.
+
+Una volta terminato di esaminare il vettore, viene chiamata la funzione @code{join()}
+specificando nella chiamata il valore di @code{SUBSEP}
+(@pxref{Vettori multidimensionali}),
+per riunire nuovamente i pezzi in una riga sola.
+La riga @`e poi stampata nel file di output:
+
+@example
+@c file eg/prog/extract.awk
+/^@@c(omment)?[ \t]+file/ @{
+ if (NF != 3) @{
+ e = ("extract: " FILENAME ":" FNR ": riga `file' con formato errato")
+ print e > "/dev/stderr"
+ next
+ @}
+ if ($3 != file_corrente) @{
+ if (file_corrente != "")
+ close(file_corrente)
+ file_corrente = $3
+ @}
+
+ for (;;) @{
+ if ((getline riga) <= 0)
+ fine_file_inattesa()
+ if (riga ~ /^@@c(omment)?[ \t]+endfile/)
+ break
+ else if (riga ~ /^@@(end[ \t]+)?group/)
+ continue
+ else if (riga ~ /^@@c(omment+)?[ \t]+/)
+ continue
+ if (index(riga, "@@") == 0) @{
+ print riga > file_corrente
+ continue
+ @}
+ n = split(riga, a, "@@")
+ # if a[1] == "", vuol dire riga che inizia per @@,
+ # non salvare un @@
+ for (i = 2; i <= n; i++) @{
+ if (a[i] == "") @{ # era un @@@@
+ a[i] = "@@"
+ if (a[i+1] == "")
+ i++
+ @}
+ @}
+ print join(a, 1, n, SUBSEP) > file_corrente
+ @}
+@}
+@c endfile
+@end example
+
+@`E importante notare l'uso della ridirezione @samp{>} .
+L'output fatto usando @samp{>} apre il file solo la prima volta; il file resta
+poi aperto, e ogni scrittura successiva @`e aggiunta in fondo al file.
+(@pxref{Ridirezione}).
+Ci@`o rende possibile mischiare testo del programm e commenti esplicativi
+(come @`e stato fatto qui) nello stesso file sorgente, senza nessun problema.
+Il file viene chiuso solo quando viene trovato un nuovo nome di
+@value{DF} oppure alla fine del file in input.
+
+Per finire, la funzione @code{@w{fine_file_inattesa()}} stampa un
+appropriato messaggio di errore ed esce.
+La regola @code{END} gestisce la pulizia finale, chiudendo il file aperto:
+
+@example
+@c file eg/prog/extract.awk
+@group
+function fine_file_inattesa()
+@{
+ printf("extract: %s:%d: fine-file inattesa, o errore\n",
+ FILENAME, FNR) > "/dev/stderr"
+ exit 1
+@}
+@end group
+
+END @{
+ if (file_corrente)
+ close(file_corrente)
+@}
+@c endfile
+@end example
+
+@node Programma sed semplice
+@subsection Un semplice editor di flusso
+
+@cindex @command{sed}, programma di utilit@`a
+@cindex programma di utilit@`a @command{sed}
+@cindex editori di flusso
+@cindex flusso, editori di
+Il programma di utilit@`a @command{sed} @`e un @dfn{editore di flusso},
+ovvero un programma che legge un flusso di dati, lo modifica, e scrive il file
+cos@`{@dotless{i}} modificato.
+@`E spesso usato per fare modifiche generalizzate a un grosso file, o a un
+flusso di dati generato da una @dfn{pipeline} di comandi.
+Sebbene @command{sed} sia un programma piuttosto complesso di suo, l'uso che
+se ne fa solitamente @`e di effettuare delle sostituzioni globali attraverso
+una @dfn{pipeline}:
+
+@example
+@var{comando1} < dati.originali | sed 's/vecchio/nuovo/g' | @var{comando2} > risultato
+@end example
+
+Qui, @samp{s/vecchio/nuovo/g} chiede a @command{sed} di ricercare la
+@dfn{regexp} @samp{vecchio} in ogni riga di input e di sostituirla
+dappertutto con il testo @samp{nuovo} (cio@`e, in tutte le occorrenze di
+ciascuna riga). Questo @`e simile a quello che fa la funzione di @command{awk}
+@code{gsub()}
+(@pxref{Funzioni per stringhe}).
+
+Il programma seguente, @file{awksed.awk}, accetta almeno due argomenti dalla
+riga di comando: l'espressione da ricercare e il testo con cui rimpiazzarla.
+Ogni ulteriore argomento @`e considerato
+come un nome di @value{DF} da elaborare. Se non ne viene fornito alcuno, si
+usa lo standard input:
+
+@cindex Brennan, Michael
+@cindex @command{awksed.awk}, programma
+@cindex programma @command{awksed.awk}
+@c @cindex simple stream editor
+@c @cindex stream editor, simple
+@example
+@c file eg/prog/awksed.awk
+# awksed.awk --- fa s/pippo/pluto/g usando solo print
+# Ringraziamenti a Michael Brennan per l'idea
+@c endfile
+@ignore
+@c file eg/prog/awksed.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# August 1995
+@c endfile
+@end ignore
+@c file eg/prog/awksed.awk
+
+function sintassi()
+@{
+ print "sintassi: awksed espressione rimpiazzo [file...]" > "/dev/stderr"
+ exit 1
+@}
+
+BEGIN @{
+ # valida argomenti
+ if (ARGC < 3)
+ sintassi()
+
+ RS = ARGV[1]
+ ORS = ARGV[2]
+
+ # non usare argomenti come nomi di file
+ ARGV[1] = ARGV[2] = ""
+@}
+
+@group
+# guarda, mamma, senza mani!
+@{
+ if (RT == "")
+ printf "%s", $0
+ else
+ print
+@}
+@end group
+@c endfile
+@end example
+
+Il programma fa assegnamento sulla capacit@`a di @command{gawk} di avere come
+@code{RS} una @dfn{regexp},
+e anche sul fatto che @code{RT} viene impostato al testo che effettivamente
+delimita il record (@pxref{Record}).
+
+L'idea @`e di usare @code{RS} come espressione da ricercare. @command{gawk}
+automaticamente imposta @code{$0} al testo che compare tra due corrispondenze
+all'espressione di ricerca.
+Questo @`e appunto il testo che vogliamo conservare inalterato. Quindi,
+impostando @code{ORS} al testo che si vuole sostituire, una semplice
+istruzione @code{print} scrive il testo che si vuole mantenere, seguito dal
+testo che si vuole invece sostituire.
+
+C'@`e un problema in questo schema, ossia cosa fare se l'ultimo record
+non termina con un testo che corrisponde a @code{RS}. Usando un'istruzione
+@code{print} incondizionatamente stampa il testo da sostituire, il che non
+@`e corretto.
+Tuttavia, se il file non termina con del testo che corrisponde a @code{RS},
+@code{RT} @`e impostata alla stringa nulla. In tal caso, si pu@`o stampare
+@code{$0} usando @code{printf}
+(@pxref{Printf}).
+
+La regola @code{BEGIN} gestisce la preparazione, controllando che ci sia
+il numero giusto di argomenti e chiamando @code{sintassi()} se c'@`e un problema.
+Poi imposta @code{RS} e @code{ORS} dagli argomenti della riga di comando e
+imposta @code{ARGV[1]} e @code{ARGV[2]} alla stringa nulla, per impedire che
+vengano considerati dei @value{FNS}
+(@pxref{ARGC e ARGV}).
+
+La funzione @code{sintassi()} stampa un messaggio di errore ed esce.
+Per finire, l'unica regola gestisce lo schema di stampa delineato pi@`u sopra,
+usando @code{print} o @code{printf} come richiesto, a seconda del valore di
+@code{RT}.
+
+@node Programma igawk
+@subsection Una maniera facile per usare funzioni di libreria
+
+@cindex libreria di funzioni @command{awk}, programma di esempio per usare
+@cindex funzioni, librerie di, programma di esempio per usare
+@iftex
+Nella
+@end iftex
+@ifnottex
+In
+@end ifnottex
+@ref{Includere file}, abbiamo visto come @command{gawk} preveda la
+possibilit@`a di includere file. Tuttavia, questa @`e un'estensione @command{gawk}.
+Questa @value{SECTION} evidenzia l'utilit@`a di rendere l'inclusione di
+file disponibile per @command{awk} standard, e mostra come farlo utilizzando
+una combinazione di programmazione di shell e di @command{awk}.
+
+Usare funzioni di libreria in @command{awk} pu@`o presentare molti vantaggi.
+Incoraggia il riutilizzo di codice e la scrittura di funzioni di tipo
+generale. I programmi sono pi@`u snelli e quindi pi@`u comprensibili.
+Tuttavia, usare funzioni di libreria @`e facile solo in fase di scrittura di
+programmi @command{awk}; @`e invece complicato al momento di eseguirli,
+rendendo necessario specificare molte opzioni @option{-f}. Se @command{gawk}
+non @`e disponibile, non lo sono neppure la variabile d'ambiente @env{AWKPATH} e
+la possibilit@`a di conservare funzioni @command{awk} in una directory di
+libreria (@pxref{Opzioni}).
+Sarebbe bello poter scrivere programmi nel modo seguente:
+
+@example
+# funzioni di libreria
+@@include getopt.awk
+@@include join.awk
+@dots{}
+
+# programma principale
+BEGIN @{
+ while ((c = getopt(ARGC, ARGV, "a:b:cde")) != -1)
+ @dots{}
+ @dots{}
+@}
+@end example
+
+Il programma seguente, @file{igawk.sh}, fornisce questo servizio.
+Simula la ricerca da parte di @command{gawk} della variabile d'ambiente
+@env{AWKPATH} e permette anche delle inclusioni @dfn{nidificate} (cio@`e,
+un file che @`e stato incluso tramite
+@code{@@include} pu@`o contenere ulteriori istruzioni @code{@@include}).
+@command{igawk} tenta di includere ogni file una volta sola, in modo che delle
+inclusioni nidificate non contengano accidentalmente una funzione di libreria
+pi@`u di una volta.
+
+@command{igawk} dovrebbe comportarsi esternamente proprio come @command{gawk}.
+Questo vuol dire che dovrebbe accettare sulla riga di comando tutti gli
+argomenti di @command{gawk}, compresa
+la capacit@`a di specificare pi@`u file
+sorgenti tramite l'opzione @option{-f}
+e la capacit@`a di mescolare istruzioni da riga di comando e file di sorgenti di
+libreria.
+
+Il programma @`e scritto usando il linguaggio della Shell POSIX
+(@command{sh}).@footnote{Una spiegazione dettagliata del linguaggio della
+@command{sh} non rientra negli intenti di questo libro. Qualche spiegazione
+sommaria viene fornita, ma se si desidera una comprensione pi@`u dettagliata, si
+dovrebbe consultare un buon libro sulla programmazione della shell.}
+Il funzionamento @`e il seguente:
+
+@enumerate
+@item
+Esegue un ciclo attraverso gli argomenti, salvando tutto ci@`o che non si presenta come
+codice sorgente @command{awk}, per quando il programma espanso sar@`a eseguito.
+
+@item
+Per ogni argomento che rappresenta del codice @command{awk}, mette l'argomento
+in una variabile di shell che verr@`a espansa. Ci sono due casi:
+
+@enumerate a
+@item
+Un testo letterale, fornito con l'opzione @option{-e} o @option{--source}.
+Questo testo viene aggiunto direttamente in fondo.
+
+@item
+@value{FNS} sorgenti, forniti con l'opzione @option{-f}. Usiamo il trucchetto
+di aggiungere @samp{@@include @var{nome_file}} in fondo ai contenuti della
+variabile di shell. Poich@'e il programma di inclusione dei file funziona
+allo stesso modo in cui funziona @command{gawk}, ne risulta che il file viene
+incluso nel programma al punto giusto.
+@end enumerate
+
+@item
+Esegue un programma (naturalmente @command{awk}) sui contenuti della variabile
+di shell per espandere le istruzioni
+@code{@@include}. Il programma espanso @`e messo in una seconda variabile di
+shell.
+
+@item
+Esegue il programma espanso richiamando @command{gawk} e tutti gli altri
+argomenti originalmente forniti dall'utente sulla riga di comando (come p.es.
+dei nomi di @value{DF}).
+@end enumerate
+
+Questo programma usa variabili di shell in quantit@`a: per immagazzinare
+argomenti della riga di comando e
+il testo del programma @command{awk} che espander@`a il programma dell'utente,
+per il programma originale dell'utente e per il programma espanso. Questo
+modo di procedere risolve potenziali
+problemi che potrebbero presentarsi se si usassero invece dei file temporanei,
+ma rende lo script un po' pi@`u complicato.
+
+La parte iniziale del programma attiva il tracciamento della shell se il primo
+argomento @`e @samp{debug}.
+
+La parte successiva esegue un ciclo che esamina ogni argomento della riga di
+comando.
+Ci sono parecchi casi da esaminare:
+
+@c @asis for docbook
+@table @asis
+@item @option{--}
+Quest'opzione termina gli argomenti per @command{igawk}. Tutto quel che segue
+dovrebbe essere passato al programma @command{awk} dell'utente senza essere
+preso in considerazione.
+
+@item @option{-W}
+Questo indica che l'opzione successiva @`e propria di @command{gawk}. Per
+facilitare l'elaborazione degli argomenti, l'opzione @option{-W} @`e aggiunta
+davanti agli argomenti rimanenti, e il
+ciclo continua. (Questo @`e un trucco di programmazione della @command{sh}.
+Non @`e il caso di preoccuparsene se non si ha familiarit@`a con il comando
+@command{sh}.)
+
+@item @option{-v}, @option{-F}
+Queste opzioni sono conservate e lasciate da gestire a @command{gawk}.
+
+@item @option{-f}, @option{--file}, @option{--file=}, @option{-Wfile=}
+Il @value{FN} @`e aggiunto alla variabile di shell @code{programma}, insieme
+a un'istruzione @code{@@include}.
+Il programma di utilit@`a @command{expr} @`e usato per eliminare la parte
+iniziale dell'argomento (p.es., @samp{--file=}).
+(La sintassi tipica di @command{sh} richiederebbe di usare il comando
+@command{echo} e il programma di utilit@`a @command{sed} per far questo.
+Sfortunatamente, alcune versioni di @command{echo} valutano le sequenze
+di protezione contenute nei loro argomenti, e questo potrebbe finire per
+alterare il testo del programma.
+L'uso di @command{expr} evita questo problema.)
+
+@item @option{--source}, @option{--source=}, @option{-Wsource=}
+Il testo sorgente @`e aggiunto in fondo a @code{programma}.
+
+@item @option{--version}, @option{-Wversion}
+@command{igawk} stampa il proprio numero di versione, esegue
+@samp{gawk --version} per ottenere l'informazione relativa alla versione di
+@command{gawk}, ed esce.
+@end table
+
+Se nessuno degli argomenti
+@option{-f}, @option{--file}, @option{-Wfile}, @option{--source},
+o @option{-Wsource} @`e stato fornito, il primo argomento che non @`e un'opzione
+dovrebbe essere il programma @command{awk}. Se non ci sono argomenti rimasti
+sulla riga di comando, @command{igawk} stampa un messaggio di errore ed esce.
+Altrimenti, il primo argomento @`e aggiunto in fondo a @code{programma}.
+In qualsiasi caso, dopo che gli argomenti sono stati elaborati,
+la variabile di shell
+@code{programma} contiene il testo completo del programma originale
+@command{awk}.
+
+Il programma @`e il seguente:
+
+@cindex @code{igawk.sh}, programma
+@cindex programma @code{igawk.sh}
+@example
+@c file eg/prog/igawk.sh
+#! /bin/sh
+# igawk --- come gawk ma abilita l'uso di @@include
+@c endfile
+@ignore
+@c file eg/prog/igawk.sh
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# July 1993
+# December 2010, minor edits
+@c endfile
+@end ignore
+@c file eg/prog/igawk.sh
+
+if [ "$1" = debug ]
+then
+ set -x
+ shift
+fi
+
+# Un ritorno a capo letterale,
+# per formattare correttamente il testo del programma
+n='
+'
+
+# Inizializza delle variabili alla stringa nulla
+programma=
+opts=
+
+while [ $# -ne 0 ] # ciclo sugli argomenti
+do
+ case $1 in
+ --) shift
+ break ;;
+
+ -W) shift
+ # Il costrutto $@{x?'messaggio qui'@} stampa un
+ # messaggio diagnostico se $x @`e la stringa nulla
+ set -- -W"$@{@@?'manca operando'@}"
+ continue ;;
+
+ -[vF]) opts="$opts $1 '$@{2?'manca operando'@}'"
+ shift ;;
+
+ -[vF]*) opts="$opts '$1'" ;;
+
+ -f) programma="$programma$n@@include $@{2?'manca operando'@}"
+ shift ;;
+
+ -f*) f=$(expr "$1" : '-f\(.*\)')
+ programma="$programma$n@@include $f" ;;
+
+ -[W-]file=*)
+ f=$(expr "$1" : '-.file=\(.*\)')
+ programma="$programma$n@@include $f" ;;
+
+ -[W-]file)
+ programma="$programma$n@@include $@{2?'manca operando'@}"
+ shift ;;
+
+ -[W-]source=*)
+ t=$(expr "$1" : '-.source=\(.*\)')
+ programma="$programma$n$t" ;;
+
+ -[W-]source)
+ programma="$programma$n$@{2?'manca operando'@}"
+ shift ;;
+
+ -[W-]version)
+ echo igawk: version 3.0 1>&2
+ gawk --version
+ exit 0 ;;
+
+ -[W-]*) opts="$opts '$1'" ;;
+
+ *) break ;;
+ esac
+ shift
+done
+
+if [ -z "$programma" ]
+then
+ programma=$@{1?'manca programma'@}
+ shift
+fi
+
+# A questo punto, `programma' contiene il programma.
+@c endfile
+@end example
+
+Il programma @command{awk} che elabora le direttive @code{@@include}
+@`e immagazzinato nella variabile di shell @code{progr_che_espande}. Ci@`o serve
+a mantenere leggibile lo script. Questo programma @command{awk} legge
+tutto il programma dell'utente, una riga per volta, usando @code{getline}
+(@pxref{Getline}). I @value{FNS} in input e le istruzioni @code{@@include}
+sono gestiti usando una pila. Man mano che viene trovata una @code{@@include},
+il valore corrente di @value{FN} @`e
+``spinto'' sulla pila e il file menzionato nella direttiva @code{@@include}
+diventa il @value{FN} corrente. Man mano che un file @`e finito,
+la pila viene ``disfatta'', e il precedente file in input diventa nuovamente il
+file in input corrente. Il processo viene iniziato ponendo il file originale
+come primo file sulla pila.
+
+La funzione @code{percorso()} trova qual @`e il percorso completo di un file.
+Simula il comportamento di @command{gawk} quando utilizza la variabile
+d'ambiente @env{AWKPATH}
+(@pxref{AWKPATH (Variabile)}).
+Se un @value{FN} contiene una @samp{/}, non viene effettuata la ricerca del
+percorso. Analogamente, se il
+@value{FN} @`e @code{"-"}, viene usato senza alcuna modifica. Altrimenti,
+il @value{FN} @`e concatenato col nome di ogni directory nella lista dei
+percorsi, e vien fatto un tentativo per aprire il @value{FN} cos@`{@dotless{i}} generato.
+Il solo modo di controllare se un file @`e leggibile da @command{awk} @`e di
+andare avanti e tentare di leggerlo con
+@code{getline}; questo @`e quel che
+@code{percorso()} fa.@footnote{In alcune versioni molto datate di
+@command{awk}, il test @samp{getline da_buttare < t} pu@`o ripetersi in un ciclo
+infinito se il file esiste ma @`e vuoto.}
+Se il file pu@`o essere letto, viene chiuso e viene restituito il valore di
+@value{FN}:
+
+@ignore
+An alternative way to test for the file's existence would be to call
+@samp{system("test -r " t)}, which uses the @command{test} utility to
+see if the file exists and is readable. The disadvantage to this method
+is that it requires creating an extra process and can thus be slightly
+slower.
+@end ignore
+
+@example
+@c file eg/prog/igawk.sh
+progr_che_espande='
+
+function percorso(file, i, t, da_buttare)
+@{
+ if (index(file, "/") != 0)
+ return file
+
+ if (file == "-")
+ return file
+
+ for (i = 1; i <= n_dir; i++) @{
+ t = (lista_percorsi[i] "/" file)
+@group
+ if ((getline da_buttare < t) > 0) @{
+ # found it
+ close(t)
+ return t
+ @}
+@end group
+ @}
+ return ""
+@}
+@c endfile
+@end example
+
+Il programma principale @`e contenuto all'interno di una regola @code{BEGIN}.
+La prima cosa che fa @`e di impostare il vettore @code{lista_percorsi} usato
+dalla funzione @code{percorso()}. Dopo aver diviso la lista usando come
+delimitatore @samp{:}, gli elementi nulli sono sostituiti da @code{"."},
+che rappresenta la directory corrente:
+
+@example
+@c file eg/prog/igawk.sh
+BEGIN @{
+ percorsi = ENVIRON["AWKPATH"]
+ n_dir = split(percorsi, lista_percorsi, ":")
+ for (i = 1; i <= n_dir; i++) @{
+ if (lista_percorsi[i] == "")
+ lista_percorsi[i] = "."
+ @}
+@c endfile
+@end example
+
+La pila @`e inizializzata con @code{ARGV[1]}, che sar@`a @code{"/dev/stdin"}.
+Il ciclo principale viene subito dopo. Le righe in input sono lette una dopo
+l'altra. Righe che non iniziano con @code{@@include} sono stampate cos@`{@dotless{i}} come
+sono.
+Se la riga inizia con @code{@@include}, il @value{FN} @`e in @code{$2}.
+La funzione @code{percorso()} @`e chiamata per generare il percorso completo.
+Se questo non riesce, il programma stampa un messaggio di errore e continua.
+
+Subito dopo occorre controllare se il file sia gi@`a stato incluso. Il vettore
+@code{gia_fatto} @`e indicizzato dal nome completo di ogni @value{FN} incluso
+e tiene traccia per noi di questa informazione. Se un file viene visto pi@`u
+volte, viene stampato un messaggio di avvertimento. Altrimenti il nuovo
+@value{FN} @`e aggiunto alla pila e l'elaborazione continua.
+
+Infine, quando @code{getline} giunge alla fine del file in input, il file
+viene chiuso, e la pila viene elaborata. Quando @code{indice_pila} @`e minore
+di zero, il programma @`e terminato:
+
+@example
+@c file eg/prog/igawk.sh
+ indice_pila = 0
+ input[indice_pila] = ARGV[1] # ARGV[1] @`e il primo file
+
+ for (; indice_pila >= 0; indice_pila--) @{
+ while ((getline < input[indice_pila]) > 0) @{
+ if (tolower($1) != "@@include") @{
+ print
+ continue
+ @}
+ cammino = percorso($2)
+@group
+ if (cammino == "") @{
+ printf("igawk: %s:%d: non riesco a trovare %s\n",
+ input[indice_pila], FNR, $2) > "/dev/stderr"
+ continue
+ @}
+@end group
+ if (! (cammino in gia_fatto)) @{
+ gia_fatto[cammino] = input[indice_pila]
+ input[++indice_pila] = cammino # aggiungilo alla pila
+ @} else
+ print $2, "incluso in", input[indice_pila],
+ "era gi@`a incluso in",
+ gia_fatto[cammino] > "/dev/stderr"
+ @}
+ close(input[indice_pila])
+ @}
+@}' # l'apice chiude la variabile `progr_che_espande'
+
+programma_elaborato=$(gawk -- "$progr_che_espande" /dev/stdin << EOF
+$programma
+EOF
+)
+@c endfile
+@end example
+
+Il costrutto di shell @samp{@var{comando} << @var{marcatore}} @`e chiamato
+@dfn{here document} (@dfn{documento sul posto}). Ogni riga presente nello
+script di shell fino al @var{marcatore} @`e passato in input a @var{comando}.
+La shell elabora i contenuti dell'@dfn{here document} sostituendo, dove serve,
+variabili e comandi (ed eventualmente altre cose, a seconda della shell
+in uso).
+
+Il costrutto di shell @samp{$(@dots{})} @`e chiamato @dfn{sostituzione di comando}.
+L'output del comando posto all'interno delle parentesi @`e sostituito
+nella riga di comando.
+Poich@'e il risultato @`e usato in un assegnamento di variabile,
+viene salvato come un'unica stringa di caratteri, anche se il risultato
+contiene degli spazi bianchi.
+
+Il programma espanso @`e salvato nella variabile @code{programma_elaborato}.
+Il tutto avviene secondo le fasi seguenti:
+
+@enumerate
+@item
+Si esegue @command{gawk} con il programma che gestisce le @code{@@include}
+(il valore della variabile di shell
+@code{progr_che_espande}) leggendo lo standard input.
+
+@item
+Lo standard input contiene il programma dell'utente,
+nella variabile di shell @code{programma}.
+L'input @`e passato a @command{gawk} tramite un @dfn{here document}.
+
+@item
+I risultati di questo processo sono salvati nella variabile di shell
+@code{programma_elaborato} usando la sostituzione di comando.
+@end enumerate
+
+L'ultima fase @`e la chiamata a @command{gawk} con il programma espanso,
+insieme alle opzioni originali e agli argomenti della riga di comando che
+l'utente aveva fornito:
+
+@example
+@c file eg/prog/igawk.sh
+eval gawk $opts -- '"$programma_elaborato"' '"$@@"'
+@c endfile
+@end example
+
+Il comando @command{eval} @`e una struttura della shell che riesegue
+l'elaborazione dei parametri della riga di comando. Gli apici proteggono le
+parti restanti.
+
+Questa versione di @command{igawk} @`e la quinta versione di questo programma.
+Ci sono quattro semplificazioni migliorative:
+
+@itemize @value{BULLET}
+@item
+L'uso di @code{@@include} anche per i file specificati tramite l'opzione
+@option{-f} consente di semplificare di molto la preparazione del programma
+iniziale @command{awk}; tutta l'elaborazione delle istruzioni @code{@@include}
+pu@`o essere svolta in una sola volta.
+
+@item
+Non tentare di salvare la riga letta tramite @code{getline} all'interno della
+funzione @code{percorso()} quando si controlla se il file @`e accessibile
+per il successivo uso nel programma principale semplifica notevolmente
+le cose.
+
+@item
+Usare un ciclo di @code{getline} nella regola @code{BEGIN} rende possibile
+fare tutto in un solo posto. Non @`e necessario programmare un ulteriore ciclo
+per elaborare le istruzioni @code{@@include} nidificate.
+
+@item
+Invece di salvare il programma espanso in un file temporaneo, assegnarlo a
+una variabile di shell evita alcuni potenziali problemi di sicurezza.
+Ci@`o per@`o ha lo svantaggio di basare lo script su funzionalit@`a del
+linguaggio @command{sh}, il che rende pi@`u difficile la comprensione a chi non
+abbia familiarit@`a con il comando
+@command{sh}.
+@end itemize
+
+Inoltre, questo programma dimostra come spesso valga la pena di utilizzare
+insieme la programmazione della @command{sh} e quella di @command{awk}.
+Solitamente, si pu@`o fare parecchio senza dover ricorrere alla programmazione
+di basso livello in C o C++, ed @`e spesso pi@`u facile fare certi tipi di
+manipolazioni di stringhe e argomenti usando la shell, piuttosto che
+@command{awk}.
+
+Infine, @command{igawk} dimostra che non @`e sempre necessario aggiungere nuove
+funzionalit@`a a un programma; queste possono spesso essere aggiunte in
+cima.@footnote{@command{gawk}
+@`e in grado di elaborare istruzioni @code{@@include} al suo stesso interno, per
+permettere l'uso di programmi @command{awk} come script Web CGI.}
+
+
+@node Programma anagram
+@subsection Trovare anagrammi da una lista di parole
+
+@cindex anagrammi, trovare
+Un'interessante sfida per il programmatore @`e quella di cercare @dfn{anagrammi} in una
+lista di parole (come
+@file{/usr/share/dict/italian} presente in molti sistemi GNU/Linux).
+Una parola @`e un anagramma di un'altra se entrambe le parole contengono
+le stesse lettere
+(p.es., ``branzino'' e ``bronzina'').
+
+La Colonna 2, Problema C, della seconda edizione del libro di Jon Bentley
+@cite{Programming Pearls}, presenta un algoritmo elegante.
+L'idea @`e di assegnare a parole che sono anagrammi l'una dell'altra una
+firma comune, e poi di ordinare tutte le parole in base alla loro
+firma e di stamparle.
+Il Dr.@: Bentley fa notare che prendere tutte le lettere di ogni parola ed
+elencarle in ordine alfabetico produce queste firme comuni.
+
+Il programma seguente usa vettori di vettori per riunire
+parole con la stessa firma, e l'ordinamento di vettori per stampare le
+parole trovate in ordine alfabetico:
+
+@cindex @code{anagram.awk}, programma
+@cindex programma @code{anagram.awk}
+@example
+@c file eg/prog/anagram.awk
+# anagram.awk --- Un'implementazione dell'algoritmo per trovare anagrammi
+# dalla seconda edizione
+# del libro di Jon Bentley "Programming Pearls".
+# Addison Wesley, 2000, ISBN 0-201-65788-0.
+# Colonna 2, Problema C, sezione 2.8, pp 18-20.
+@c endfile
+@ignore
+@c file eg/prog/anagram.awk
+#
+# Questo programma richiede gawk 4.0 o una versione successiva.
+# Funzionalit@`a di gawk richieste:
+# - veri vettori multidimensionali
+# - split() con separatore "" per separare ogni singolo carattere
+# - le funzioni asort() e asorti()
+#
+# Vedere http://savannah.gnu.org/projects/gawk.
+#
+# Arnold Robbins
+# arnold@@skeeve.com
+# Public Domain
+# January, 2011
+@c endfile
+@end ignore
+@c file eg/prog/anagram.awk
+
+/'s$/ @{ next @} # Salta i genitivi sassoni
+@c endfile
+@end example
+
+Il programma inizia con un'intestazione, e poi una regola per saltare
+i genitivi sassoni eventualmente contenuti nel file che contiene la lista di
+parole. La regola
+successiva costruisce la struttura dei dati. Il primo indice del vettore
+@`e rappresentato dalla firma; il secondo @`e la parola stessa:
+
+@example
+@c file eg/prog/anagram.awk
+@{
+ chiave = da_parola_a_chiave($1) # costruisce la firma
+ data[chiave][$1] = $1 # Immagazzina parola con questa firma
+@}
+@c endfile
+@end example
+
+La funzione @code{da_parola_a_chiave()} crea la firma.
+Divide la parola in lettere singole, mette in ordine alfabetico le lettere,
+e poi le rimette ancora insieme:
+
+@example
+@c file eg/prog/anagram.awk
+# da_parola_a_chiave --- divide parole in lettere, ordina e riunisce
+
+function da_parola_a_chiave(parola, a, i, n, risultato)
+@{
+ n = split(parola, a, "")
+ asort(a)
+
+ for (i = 1; i <= n; i++)
+ risultato = risultato a[i]
+
+ return risultato
+@}
+@c endfile
+@end example
+
+Infine, la regola @code{END} percorre tutto il vettore e stampa
+le liste degli anagrammi. L'output @`e poi passato al
+comando di sistema @command{sort} perch@'e altrimenti gli
+anagrammi sarebbero elencati in ordine arbitrario:
+
+@example
+@c file eg/prog/anagram.awk
+END @{
+ sort = "sort"
+ for (chiave in data) @{
+ # ordina parole con la stessa chiave
+ n_parole = asorti(data[chiave], parole)
+ if (n_parole == 1)
+ continue
+
+ # e stampa. Problema minore: uno spazio extra a fine di ogni riga
+ for (j = 1; j <= n_parole; j++)
+ printf("%s ", parole[j]) | sort
+ print "" | sort
+ @}
+ close(sort)
+@}
+@c endfile
+@end example
+
+Ecco una piccola parte dell'output quando il programma @`e eseguito:
+
+@example
+$ @kbd{gawk -f anagram.awk /usr/share/dict/italian | grep '^b'}
+@dots{}
+baraste bastare serbata
+barasti basarti
+baratro tabarro
+barattoli ribaltato tribolata
+barbieri birberia
+barche brache
+barcollerei corbelleria
+bare erba
+bareremmo brameremo
+barili librai
+@dots{}
+@end example
+
+
+@node Programma signature
+@subsection E ora per qualcosa di completamente differente
+
+@cindex @code{signature}, programma
+@cindex programma @code{signature}
+@cindex Brini, Davide
+Il programma seguente @`e stato scritto da Davide Brini
+@c (@email{dave_br@@gmx.com})
+ed @`e pubblicato sul @uref{http://backreference.org/2011/02/03/obfuscated-awk/,
+suo sito web}.
+Serve come sua firma nel gruppo Usenet @code{comp.lang.awk}.
+Questi sono i termini da lui stabiliti per il copyright:
+
+@quotation
+Copyright @copyright{} 2008 Davide Brini
+
+Copying and distribution of the code published in this page, with or without
+modification, are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+@end quotation
+
+Ecco il programma:
+
+@example
+awk 'BEGIN@{O="~"~"~";o="=="=="==";o+=+o;x=O""O;while(X++<=x+o+o)c=c"%c";
+printf c,(x-O)*(x-O),x*(x-o)-o,x*(x-O)+x-O-o,+x*(x-O)-x+o,X*(o*o+O)+x-O,
+X*(X-x)-o*o,(x+X)*o*o+o,x*(X-x)-O-O,x-O+(O+o+X+x)*(o+O),X*X-X*(x-O)-x+O,
+O+X*(o*(o+O)+O),+x+O+X*o,x*(x-o),(o+X+x)*o*o-(x-O-O),O+(X-x)*(X+O),x-O@}'
+@end example
+@c genera l'email del tizio:
+@c dave_br@gmx.com
+
+@cindex Johansen, Chris
+Viene lasciato al lettore il piacere di stabilire cosa fa il programma.
+(Se si @`e sull'orlo della disperazione nel tentativo di comprensione, si veda
+la spiegazione di Chris Johansen,
+che @`e contenuta nel file sorgente Texinfo di questo @value{DOCUMENT}.)
+
+@ignore
+To: "Arnold Robbins" <arnold@skeeve.com>
+Date: Sat, 20 Aug 2011 13:50:46 -0400
+Subject: The GNU Awk User's Guide, Section 13.3.11
+From: "Chris Johansen" <johansen@main.nc.us>
+Message-ID: <op.v0iw6wlv7finx3@asusodin.thrudvang.lan>
+
+Arnold, tu non mi conosci, ma c'@`e un sottile legame tra noi. Mia moglie @`e
+Barbara A. Field, FAIA, GIT '65 (B. Arch.).
+
+Ho un paio di copie cartacee di "Effective Awk Programming" da
+anni, ed ora sto leggendo di nuovo la versione Kindle di "The GNU Awk User's
+Guide". Quando sono arrivato alla sezione 13.3.11, ho riformattato e
+brevemente commentato lo script di firma di Davide Brin per comprenderne il funzionamento.
+
+Mi pare che questo possa avere un valore pedagogico come esempio
+(sia pure imperfetto) del significato di spazi bianchi e commenti, e un
+punto di partenza per una tale discussione. Sicuramente ha aiutato _me_ a
+capire quel che succede. Se vuoi
+usarlo, com'@`e o modificato, sentiti libero di farlo (a condizione di
+rispettare i vincoli posti da Davide, naturalmente, che credo siano stati
+da me rispettati).
+
+Se dovessi includere questa spiegazione in una futura edizione, la inserirei
+a una certa distanza dalla sezione 13.3.11, diciamo come una nota o come
+un'appendice, in modo da non rivelare immediatamente la soluzione dell'enigma.
+
+Cordiali saluti,
+--
+Chris Johansen {johansen at main dot nc dot us}
+ . . . collapsing the probability wave function, sending ripples of
+certainty through the space-time continuum.
+
+
+#! /usr/bin/gawk -f
+
+# Da "13.3.11 E ora per qualcosa di completamente differente"
+# http://www.gnu.org/software/gawk/manual/html_node/Signature-Program.html#Signature-Program
+
+# Copyright © 2008 Davide Brini
+
+# Copying and distribution of the code published in this page, with
+# or without modification, are permitted in any medium without
+# royalty provided the copyright notice and this notice are preserved.
+
+BEGIN {
+ O = "~" ~ "~"; # 1
+ o = "==" == "=="; # 1
+ o += +o; # 2
+ x = O "" O; # 11
+
+
+ while ( X++ <= x + o + o ) c = c "%c";
+
+ # O vale 1
+ # o vale 2
+ # x vale 11
+ # X vale 17
+ # c vale "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
+
+ printf c,
+ ( x - O )*( x - O), # 100 d
+ x*( x - o ) - o, # 97 a
+ x*( x - O ) + x - O - o, # 118 v
+ +x*( x - O ) - x + o, # 101 e
+ X*( o*o + O ) + x - O, # 95 _
+ X*( X - x ) - o*o, # 98 b
+ ( x + X )*o*o + o, # 114 r
+ x*( X - x ) - O - O, # 64 @
+ x - O + ( O + o + X + x )*( o + O ), # 103 g
+ X*X - X*( x - O ) - x + O, # 109 m
+ O + X*( o*( o + O ) + O ), # 120 x
+ +x + O + X*o, # 46 .
+ x*( x - o), # 99 c
+ ( o + X + x )*o*o - ( x - O - O ), # 111 0
+ O + ( X - x )*( X + O ), # 109 m
+ x - O # 10 \n
+}
+@end ignore
+
+@node Sommario dei programmi
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+I programmi illustrati in questo @value{CHAPTER}
+ripropongo la tesi secondo cui leggere programmi @`e una maniera eccellente
+per imparare a fare della buona programmazione.
+
+@item
+Usare @samp{#!} per rendere i programmi @command{awk} direttamente eseguibili
+ne rende pi@`u semplice l'uso. In alternativa, si pu@`o invocare un
+programma usando @samp{awk -f @dots{}}.
+
+@item
+Reimplementare programmi POSIX standard in @command{awk} @`e un esercizio
+piacevole; il potere espressivo di @command{awk} consente di scrivere tali
+programmi usando relativamente poche righe di codice, nonostante i programmi
+risultanti siano funzionalmente completi e utilizzabili.
+
+@item
+Una delle debolezze della versione standard di @command{awk} riguarda il
+lavorare con singoli caratteri. La possibilit@`a di usare @code{split()} con
+la stringa nulla come separatore pu@`o semplificare considerevolmente tale
+compito.
+
+@item
+Gli esempi proposti dimostrano l'utilit@`a delle funzioni di libreria introdotte
+@iftex
+nel
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzioni di libreria}
+per un numero (sia pur piccolo) di programmi reali.
+
+@item
+Oltre a reinventare la ruota POSIX, altri programmi risolvono una serie di
+problemi interessanti, come trovare delle parole duplicate in un testo,
+stampare etichette per lettere, e trovare anagrammi.
+
+@end itemize
+
+@c EXCLUDE START
+@node Esercizi sui programmi
+@section Esercizi
+
+@enumerate
+@item
+Riscrivere @file{cut.awk} (@pxref{Programma cut})
+usando @code{split()} con @code{""} come separatore.
+
+@item
+@iftex
+Nella
+@end iftex
+@ifnottex
+In
+@end ifnottex
+@ref{Programma egrep}, @`e detto che @samp{egrep -i} potrebbe essere
+simulato in versioni di @command{awk} che non prevedono @code{IGNORECASE}
+usando @code{tolower()} sulla riga e nei criteri di ricerca. In una nota a
+pi@`e di pagina @`e anche detto che questa soluzione ha un problema: in output
+viene scritta la riga tradotta (a lettere minuscole), e non quella originale.
+Risolvere questo problema.
+@c Exercise: Fix this, w/array and new line as key to original line
+
+@item
+La versione POSIX di @command{id} accetta opzioni che controllano quali
+informazioni stampare. Modificare la versione @command{awk}
+(@pxref{Programma id}) per accettare gli stessi argomenti e funzionare allo
+stesso modo.
+
+@item
+Il programma @code{split.awk} (@pxref{Programma split}) presuppone che le
+lettere siano contigue nella codifica dei caratteri,
+il che non @`e vero per sistemi che usano la codifica EBCDIC.
+Risolvere questo problema.
+(Suggerimento: Considerare un modo diverso di analizzare l'alfabeto,
+senza appoggiarsi sulle funzioni @code{ord()} e @code{chr()}.)
+
+@item
+Nel programma @file{uniq.awk} (@pxref{Programma uniq}, la
+logica per scegliere quali righe stampare rappresenta una
+@dfn{macchina a stati},
+ossia ``un dispositivo che pu@`o essere in uno di un insieme di stati
+stabili, a seconda dello stato in cui si trovava in precedenza, e del
+valore corrente dei suoi
+input.''@footnote{Questo @`e la definizione trovata usando
+@code{define: state machine} come chiave di ricerca in Google.}
+Brian Kernighan suggerisce che
+``un approccio alternativo alle macchine a stati @`e di leggere tutto l'input
+e metterlo in un vettore, e quindi usare gli indici. @`E quasi sempre pi@`u
+semplice da programmare, e per la maggior parte degli input in cui si pu@`o
+usare, altrettanto veloce in esecuzione.'' Riscrivere la logica del
+programma seguendo questa indicazione.
+
+
+@item
+Perch@'e il programma @file{wc.awk} (@pxref{Programma wc}) non pu@`o
+limitarsi a usare il valore di @code{FNR} nella funziona @code{a_fine_file()}?
+Suggerimento: Esaminare il codice
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzione filetrans}.
+
+@ignore
+@command{wc} can't just use the value of @code{FNR} in
+@code{endfile()}. If you examine the code in @ref{Filetrans Function},
+you will see that @code{FNR} has already been reset by the time
+@code{endfile()} is called.
+@end ignore
+
+@item
+La manipolazione di singoli caratteri nel programma @command{translate}
+(@pxref{Programma translate}) @`e farraginosa usando le funzione standard
+@command{awk}. Poich@'e @command{gawk} pu@`o dividere stringhe in caratteri
+singoli usando come separatore @code{""}, come si potrebbe usare questa
+funzionalit@`a per semplificare il programma?
+
+@item
+Il programma @file{extract.awk} (@pxref{Programma extract}) @`e stato
+scritto prima che @command{gawk} avesse a disposizione la funzione
+@code{gensub()}. Usarla per semplificare il codice.
+
+@item
+Si confronti la velocit@`a di esecuzione del programma @file{awksed.awk}
+(@pxref{Programma sed semplice}) con il pi@`u diretto:
+
+@example
+BEGIN @{
+ stringa = ARGV[1]
+ rimpiazzo = ARGV[2]
+ ARGV[1] = ARGV[2] = ""
+@}
+
+@{ gsub(stringa, rimpiazzo); print @}
+@end example
+
+@item
+Quali sono vantaggi e svantaggi di @file{awksed.awk} rispetto al vero
+programma di utilit@`a @command{sed}?
+
+@ignore
+ Advantage: egrep regexps
+ speed (?)
+ Disadvantage: no & in replacement text
+
+Others?
+@end ignore
+
+@item
+@iftex
+Nella
+@end iftex
+@ifnottex
+In
+@end ifnottex
+@ref{Programma igawk}, si @`e detto che non tentando di salvare la riga
+letta con @code{getline} nella funzione @code{percorso()}, mentre si
+controlla l'accessibilit@`a del file da usare nel programma principale,
+semplifica notevolmente le cose. Quale problema @`e peraltro generato cos@`{@dotless{i}}
+facendo?
+@c answer, reading from "-" o /dev/stdin
+
+@cindex percorso di ricerca per file sorgente
+@cindex ricerca, percorso di, per file sorgente
+@cindex file sorgente, percorso di ricerca per
+@cindex directory, ricerca
+@item
+Come ulteriore esempio dell'idea che non sempre @`e necessario aggiungere
+nuove funzionalit@`a a un programma, si consideri l'idea di avere due file in
+una directory presente nel percorso di ricerca:
+
+@table @file
+@item default.awk
+Questo file contiene un insieme di funzioni di libreria di default, come
+@code{getopt()} e @code{assert()}.
+
+@item sito.awk
+Questo file contiene funzioni di libreria che sono specifiche di
+un sito o di un'installazione; cio@`e, funzioni sviluppate localmente.
+Mantenere due file separati consente a @file{default.awk} di essere
+modificato in seguito a nuove versioni di @command{gawk}, senza che
+l'amministratore di sistema debba ogni volta aggiornarlo aggiungendo le
+funzioni locali.
+@end table
+
+Un utente
+@c Karl Berry, karl@ileaf.com, 10/95
+ha suggerito che @command{gawk} venga modificato per leggere automaticamente
+questi file alla partenza. Piuttosto, sarebbe molto semplice
+modificare @command{igawk} per farlo. Poich@'e @command{igawk} @`e capace di
+elaborare direttive @code{@@include}
+nidificate, @file{default.awk} potrebbe contenere semplicemente la lista di
+direttive @code{@@include} con le funzioni di libreria desiderate.
+Fare questa modifica.
+
+@item
+Modificare @file{anagram.awk} (@pxref{Programma anagram}), per evitare di
+usare il programma di utilit@`a esterno @command{sort}.
+
+@end enumerate
+@c EXCLUDE END
+
+@ifnotinfo
+@part @value{PART3}Andare oltre @command{awk} con @command{gawk}
+@end ifnotinfo
+
+@ifdocbook
+La Parte III riguarda funzionalit@`a proprie di @command{gawk}.
+Contiene i seguenti capitoli:
+
+@itemize @value{BULLET}
+@item
+@ref{Funzionalit@`a avanzate}
+
+@item
+@ref{Internazionalizzazione}
+
+@item
+@ref{Debugger}
+
+@item
+@ref{Calcolo con precisione arbitraria}
+
+@item
+@ref{Estensioni dinamiche}
+@end itemize
+@end ifdocbook
+
+@node Funzionalit@`a avanzate
+@chapter Funzionalit@`a avanzate di @command{gawk}
+@cindex @command{gawk}, funzionalit@`a avanzate
+@cindex avanzate, funzionalit@`a, di @command{gawk}
+@ignore
+Contributed by: Peter Langston <pud!psl@bellcore.bellcore.com>
+
+ Found in Steve English's "signature" line:
+
+"Write documentation as if whoever reads it is a violent psychopath
+who knows where you live."
+@end ignore
+@cindex Langston, Peter
+@cindex English, Steve
+@quotation
+@i{Scrivete la documentazione supponendo che chiunque la legger@`a sia uno psicopatico
+violento, che conosce il vostro indirizzo di casa.}
+@author Steve English, citato da Peter Langston
+@end quotation
+
+Questo @value{CHAPTER} tratta delle funzionalit@`a avanzate in @command{gawk}.
+@`E un po' come un ``pacco sorpresa'' di argomenti che non sono collegati tra di
+loro in altro modo.
+Per prima cosa, vediamo un'opzione da riga di comando che consente a
+@command{gawk} di riconoscere i numeri non-decimali nei dati in input, e non
+soltanto nei programmi @command{awk}.
+Poi vengono illustrate delle funzionalit@`a speciali di @command{gawk} per
+l'ordinamento di vettori. Quindi viene trattato dettagliatamente l'I/O
+bidirezionale, di cui si @`e fatto cenno in precedenti parti di questo
+@value{DOCUMENT}, assieme ai fondamenti sulle reti TCP/IP.
+Infine, vediamo come @command{gawk}
+pu@`o tracciare il @dfn{profilo} di un programma @command{awk}, cos@`{@dotless{i}} che si
+possa ritoccarlo per migliorarne le prestazioni.
+
+@c FULLXREF ON
+Altre funzionalit@`a avanzate vengono trattate separatamente dedicando un
+@value{CHAPTER} per ciascuna di esse:
+
+@itemize @value{BULLET}
+@item
+@iftex
+Il
+@end iftex
+@ref{Internazionalizzazione}, parla di come internazionalizzare
+i propri programmi @command{awk}, in modo che parlino pi@`u lingue
+nazionali.
+
+@item
+@iftex
+Il
+@end iftex
+@ref{Debugger}, descrive il debugger dalla riga di comando disponibile
+all'interno di
+@command{gawk} per individuare errori nei programmi @command{awk}.
+
+@item
+@iftex
+Il
+@end iftex
+@ref{Calcolo con precisione arbitraria}, illustra come si pu@`o usare
+@command{gawk} per eseguire calcoli con precisione arbitraria.
+
+@item
+@iftex
+Il
+@end iftex
+@ref{Estensioni dinamiche},
+tratta della capacit@`a di aggiungere dinamicamente nuove funzioni predefinite a
+@command{gawk}.
+@end itemize
+@c FULLXREF OFF
+
+@menu
+* Dati non decimali:: Consentire dati di input non decimali.
+* Ordinamento di vettori:: Modi per controllare la visita di un vettore
+ e il suo ordinamento.
+* I/O bidirezionale:: Comunicazione bidirezionale con un altro
+ processo.
+* Reti TCP/IP:: Usare @command{gawk} per programmazione di rete.
+* Profilare:: Profilare i propri programmi @command{awk}.
+* Sommario funzionalit@`a avanzate:: Sommario delle funzionalit@`a avanzate.
+@end menu
+
+@node Dati non decimali
+@section Consentire dati di input non decimali
+@cindex opzione @option{--non-decimal-data}
+@c @cindex funzionalit@`a avanzate, dati di input non decimali
+@cindex input, dati non decimali
+@cindex costanti, non decimali
+
+Se si esegue @command{gawk} con l'opzione @option{--non-decimal-data},
+si possono avere valori in base diversa da dieci nei dati di input:
+
+@example
+$ @kbd{echo 0123 123 0x123 |}
+> @kbd{gawk --non-decimal-data '@{ printf "%d, %d, %d\n", $1, $2, $3 @}'}
+@print{} 83, 123, 291
+@end example
+
+Affinch@'e questa funzionalit@`a sia disponibile, i programmi devono essere
+scritti in modo che @command{gawk} tratti i dati come valori numerici:
+
+@example
+$ @kbd{echo 0123 123 0x123 | gawk '@{ print $1, $2, $3 @}'}
+@print{} 0123 123 0x123
+@end example
+
+@noindent
+L'istruzione @code{print} tratta le sue espressioni come se fossero stringhe.
+Sebbene i campi possano comportarsi come numeri, quando necessario,
+essi rimangono sempre stringhe, per cui @code{print} non cerca di elaborarli
+come se fossero numeri. Si deve aggiungere zero a un campo affich@'e venga
+considerato come un numero. Per esempio:
+
+@example
+$ @kbd{echo 0123 123 0x123 | gawk --non-decimal-data '}
+> @kbd{@{ print $1, $2, $3}
+> @kbd{print $1 + 0, $2 + 0, $3 + 0 @}'}
+@print{} 0123 123 0x123
+@print{} 83 123 291
+@end example
+
+Poich@'e capita comunemente di avere dati di tipo decimale con degli zeri iniziali,
+e poich@'e l'uso di questa funzionalit@`a pu@`o portare a risultati inattesi, il
+comportamento di default @`e quello lasciarla disabilitata. Se si vuole, la si
+deve richiedere esplicitamente.
+
+@cindex programmazione, convenzioni di, opzione @code{--non-decimal-data}
+@cindex @option{--non-decimal-data}, opzione, funzione @code{strtonum()} e
+@cindex @code{strtonum()}, funzione (@command{gawk}), opzione @code{--non-decimal-data} e
+@quotation ATTENZIONE
+@emph{L'uso di questa opzione non @`e consigliata.}
+Pu@`o provocare errori molto seri eseguendo vecchi programmi.
+Al suo posto @`e meglio usare la funzione @code{strtonum()} per convertire i dati
+(@pxref{Funzioni per stringhe}).
+Questo rende i programmi pi@`u facili da scrivere e pi@`u facili da leggere, e
+porta a risultati meno inattesi.
+
+Quest'opzione potrebbe sparire dalle versioni future di @command{gawk}.
+@end quotation
+
+@node Ordinamento di vettori
+@section Controllare la visita di un vettore e il suo ordinamento
+
+@command{gawk} permette di controllare l'ordine con cui un ciclo
+@samp{for (@var{indice} in @var{vettore})}
+attraversa un vettore.
+
+Inoltre, due funzioni predefinite, @code{asort()} e @code{asorti()},
+permettono di mettere in ordine i vettori sulla base, rispettivamente, dei
+valori e degli indici del vettore. Queste due funzioni danno anche il
+controllo sui criteri in base ai quali riordinare gli elementi del vettore.
+
+@menu
+* Controllare visita vettori:: Come usare PROCINFO["sorted_in"].
+* Funzioni di ordinamento di vettori:: Come usare @code{asort()} e @code{asorti()}.
+@end menu
+
+@node Controllare visita vettori
+@subsection Controllare visita vettori
+
+Per default, l'ordine secondo il quale un ciclo @samp{for (@var{indice} in
+@var{vettore})} scorre un vettore non @`e definito; in genere si basa
+sull'implementazione interna dei vettori all'interno di @command{awk}.
+
+Spesso, tuttavia, si vorrebbe poter eseguire un ciclo sugli elementi in un
+determinato ordine scelto dall'utente programmatore. Con @command{gawk}
+si pu@`o fare.
+
+@iftex
+La
+@end iftex
+@ref{Controllare visita} parla di come si possono assegnare valori speciali
+predefiniti a @code{PROCINFO["sorted_in"]} per controllare l'ordine secondo il
+quale @command{gawk} attraversa un vettore
+durante un ciclo @code{for}.
+
+Inoltre, il valore di @code{PROCINFO["sorted_in"]} pu@`o essere un nome di
+funzione.@footnote{Questo @`e il motivo per cui gli ordinamenti predefiniti
+iniziano con il carattere @samp{@@}, che non pu@`o essere usato in un
+identificatore.}
+Questo consente di scorrere un vettore sulla base di un qualsiasi criterio
+personalizzato. Gli elementi del vettore vengono ordinati in accordo col valore
+ritornato da questa funzione. La funzione che fa il confronto dovrebbe essere
+definita con almeno quattro argomenti:
+
+@example
+function confronta(i1, v1, i2, v2)
+@{
+ @var{confronta gli elementi 1 e 2 in qualche modo}
+ @var{return < 0; 0; o > 0}
+@}
+@end example
+
+Qui, @code{i1} e @code{i2} sono gli indici, e @code{v1} e @code{v2}
+sono i corrispondenti valori dei due elementi che si stanno confrontando.
+@code{v1} oppure @code{v2}, o entrambi, possono essere vettori se il vettore
+che si sta visitando contiene sottovettori come valori.
+(@xref{Vettori di vettori} per maggiori informazioni sui sottovettori.)
+I tre possibili valori di ritorno sono interpretati nel seguente modo:
+
+@table @code
+@item confronta(i1, v1, i2, v2) < 0
+L'indice @code{i1} viene prima dell'indice @code{i2} durante l'avanzamento
+del ciclo.
+
+@item confronta(i1, v1, i2, v2) == 0
+Gli indici @code{i1} e @code{i2}
+sono equivalenti, ma l'ordine tra loro non @`e definito.
+
+@item confronta(i1, v1, i2, v2) > 0
+L'indice @code{i1} viene dopo l'indice @code{i2} durante l'avanzamento del
+ciclo.
+@end table
+
+La prima funzione di confronto pu@`o essere usata per scorrere un vettore
+secondo l'ordine numerico degli indici:
+
+@example
+function cfr_ind_num(i1, v1, i2, v2)
+@{
+ # confronto di indici numerici, ordine crescente
+ return (i1 - i2)
+@}
+@end example
+
+La seconda funzione scorre un vettore secondo l'ordine delle stringhe
+dei valori degli elementi piuttosto che secondo gli indici:
+
+@example
+function cfr_val_str(i1, v1, i2, v2)
+@{
+ # confronto di valori di stringa, ordine crescente
+ v1 = v1 ""
+ v2 = v2 ""
+ if (v1 < v2)
+ return -1
+ return (v1 != v2)
+@}
+@end example
+
+La terza funzione di confronto restituisce dapprima tutti i numeri, e dopo
+questi le stringhe numeriche senza spazi iniziali o finali, durante
+l'avanzamento del ciclo:
+
+@example
+function cfr_val_num_str(i1, v1, i2, v2, n1, n2)
+@{
+ # confronto mettendo i numeri prima dei valori di stringa,
+ # ordine crescente
+ n1 = v1 + 0
+ n2 = v2 + 0
+ if (n1 == v1)
+ return (n2 == v2) ? (n1 - n2) : -1
+ else if (n2 == v2)
+ return 1
+ return (v1 < v2) ? -1 : (v1 != v2)
+@}
+@end example
+
+Qui vediamo un programma principale che mostra come @command{gawk}
+si comporta usando ciascuna delle funzioni precedenti:
+
+@example
+BEGIN @{
+ data["uno"] = 10
+ data["due"] = 20
+ data[10] = "uno"
+ data[100] = 100
+ data[20] = "due"
+
+ f[1] = "cfr_ind_num"
+ f[2] = "cfr_val_str"
+ f[3] = "cfr_val_num_str"
+ for (i = 1; i <= 3; i++) @{
+ printf("Funzione di ordinamento: %s\n", f[i])
+ PROCINFO["sorted_in"] = f[i]
+ for (j in data)
+ printf("\tdata[%s] = %s\n", j, data[j])
+ print ""
+ @}
+@}
+@end example
+
+I risultati dell'esecuzione del programma sono questi:
+
+@example
+$ @kbd{gawk -f compdemo.awk}
+@print{} Funzione di ordinamento: cfr_ind_num @ii{Ordinamento per indice numerico}
+@print{} data[uno] = 10
+@print{} data[due] = 20 @ii{Entrambe le stringhe sono numericamente zero}
+@print{} data[10] = uno
+@print{} data[20] = due
+@print{} data[100] = 100
+@print{}
+@print{} Funzione di ordinamento: cfr_val_str @ii{Ordinamento per valore degli}
+@print{} @ii{elementi come stringhe}
+@print{} data[uno] = 10
+@print{} data[100] = 100 @ii{La stringa 100 @`e minore della stringa 20}
+@print{} data[due] = 20
+@print{} data[20] = due
+@print{} data[10] = uno
+@print{}
+@print{} Funzione di ordinamento: cfr_val_num_str @ii{Ordinamento con tutti i}
+@print{} @ii{valori numerici prima di tutte le stringhe}
+@print{} data[uno] = 10
+@print{} data[due] = 20
+@print{} data[100] = 100
+@print{} data[20] = due
+@print{} data[10] = uno
+@end example
+
+Si provi a ordinare gli elementi di un file delle password del sistema GNU/Linux
+in base al nome d'accesso dell'utente. Il seguente programma ordina i record
+secondo una specifica posizione del campo e pu@`o essere usato per questo scopo:
+
+@example
+# passwd-sort.awk --- semplice programma per ordinare in base alla
+# posizione del campo
+# la posizione del campo @`e specificata dalla variabile globale POS
+
+function per_campo(i1, v1, i2, v2)
+@{
+ # confronto per valore, come stringa, e in ordine crescente
+ return v1[POS] < v2[POS] ? -1 : (v1[POS] != v2[POS])
+@}
+
+@{
+ for (i = 1; i <= NF; i++)
+ a[NR][i] = $i
+@}
+
+END @{
+ PROCINFO["sorted_in"] = "per_campo"
+ if (POS < 1 || POS > NF)
+ POS = 1
+ for (i in a) @{
+ for (j = 1; j <= NF; j++)
+ printf("%s%c", a[i][j], j < NF ? ":" : "")
+ print ""
+ @}
+@}
+@end example
+
+Il primo campo di ogni elemento del file delle password @`e il nome d'accesso
+dell'utente, e i campi sono separati tra loro da due punti.
+Ogni record definisce un sottovettore,
+con ogni campo come elemento nel sottovettore.
+L'esecuzione del programma produce
+il seguente output:
+
+@example
+$ @kbd{gawk -v POS=1 -F: -f sort.awk /etc/passwd}
+@print{} adm:x:3:4:adm:/var/adm:/sbin/nologin
+@print{} apache:x:48:48:Apache:/var/www:/sbin/nologin
+@print{} avahi:x:70:70:Avahi daemon:/:/sbin/nologin
+@dots{}
+@end example
+
+Il confronto normalmente dovrebbe restituire sempre lo stesso valore quando
+vien dato come argomento un preciso paio di elementi del vettore. Se viene
+restituito un risultato non coerente, l'ordine @`e indefinito. Questo
+comportamento pu@`o essere sfruttato per introdurre un ordinamento casuale in
+dati apparentemente ordinati:
+
+@example
+function ordina_a_caso(i1, v1, i2, v2)
+@{
+ # ordine casuale (attenzione: potrebbe non finire mai!)
+ return (2 - 4 * rand())
+@}
+@end example
+
+Come gi@`a accennato, l'ordine degli indici @`e arbitrario se due elementi
+risultano uguali. Normalmente questo non @`e un problema, ma lasciare che
+elementi di uguale valore compaiano in ordine arbitrario pu@`o essere un
+problema, specialmente quando si confrontano valori di elementi di un elenco.
+L'ordine parziale di elementi uguali pu@`o cambiare quando il vettore viene
+visitato di nuovo, se nel vettore vengono aggiunti o rimossi elementi. Un modo
+per superare l'ostacolo quando si confrontano elementi con valori uguali @`e
+quello di includere gli indici nelle regole di confronto. Si noti che questo
+potrebbe rendere meno efficiente l'attraversamento del ciclo, per cui si
+consiglia di farlo solo se necessario. Le seguenti funzioni di confronto
+impongono un ordine deterministico, e si basano sul fatto che gli indici
+(di stringa) di due elementi non sono mai uguali:
+@example
+function per_numero(i1, v1, i2, v2)
+@{
+ # confronto di valori numerici (e indici), ordine decrescente
+ return (v1 != v2) ? (v2 - v1) : (i2 - i1)
+@}
+
+function per_stringa(i1, v1, i2, v2)
+@{
+ # confronto di valori di stringa (e indici), ordine decrescente
+ v1 = v1 i1
+ v2 = v2 i2
+ return (v1 > v2) ? -1 : (v1 != v2)
+@}
+@end example
+
+@c Avoid using the term ``stable'' when describing the unpredictable behavior
+@c if two items compare equal. Usually, the goal of a "stable algorithm"
+@c is to maintain the original order of the items, which is a meaningless
+@c concept for a list constructed from a hash.
+
+Una funzione di confronto personalizzata spesso pu@`o semplificare
+l'attraversamento del
+ciclo ordinato, e il solo limite @`e il cielo, quando si va a progettare
+una funzione di questo tipo.
+
+Quando i confronti tra stringhe son fatti durante un'operazione di ordinamento,
+per valori di elementi che, uno o entrambi, non sono numeri, o per
+indici di elementi gestiti come stringhe, il valore di @code{IGNORECASE}
+(@pxref{Variabili predefinite}) controlla se
+i confronti trattano corrispondenti lettere maiuscole e minuscole
+come equivalenti o come distinte.
+
+Un'altra cosa da tenere a mente @`e che nel caso di sottovettori, i valori degli
+elementi possono essere a loro volta dei vettori; una funzione di confronto in
+produzione dovrebbe usare la funzione @code{isarray()}
+(@pxref{Funzioni per i tipi})
+per controllare ci@`o, e scegliere un ordinamento preciso per i sottovettori.
+
+Tutti gli ordinamenti basati su @code{PROCINFO["sorted_in"]}
+sono disabilitati in modalit@`a POSIX,
+perch@'e il vettore @code{PROCINFO} in questo caso non @`e speciale.
+
+Come nota a margine, si @`e visto che ordinare gli indici del vettore prima di
+scorrere il vettore porta a un incremento variabile dal 15% al 20% del tempo di
+esecuzione dei programmi @command{awk}. Per questo motivo l'attraversamento
+ordinato di vettori non @`e il default.
+
+@c The @command{gawk}
+@c maintainers believe that only the people who wish to use a
+@c feature should have to pay for it.
+
+@node Funzioni di ordinamento di vettori
+@subsection Ordinare valori e indici di un vettore con @command{gawk}
+
+@cindex vettori, ordinamento dei
+@cindexgawkfunc{asort}
+@cindex @code{asort()}, funzione (@command{gawk}), ordinamento di vettori
+@cindex funzione @code{asort()} (@command{gawk}), ordinamento di vettori
+@cindexgawkfunc{asorti}
+@cindex @code{asorti()}, funzione (@command{gawk}), ordinamento di vettori
+@cindex funzione @code{asorti()} (@command{gawk}), ordinamento di vettori
+@cindex @code{sort()}, funzione, ordinamento di vettori
+@cindex funzione @code{sort()}, ordinamento di vettori
+Nella maggior parte delle implementazioni di @command{awk}, ordinare un vettore
+richiede una funzione @code{sort()}. Questo pu@`o essere istruttivo per provare
+diversi algoritmi di ordinamento, ma normalmente non @`e questo lo scopo del
+programma. In @command{gawk} ci sono le funzioni predefinite @code{asort()} e
+@code{asorti()} (@pxref{Funzioni per stringhe}) per i vettori ordinati.
+Per esempio:
+
+@example
+@var{riempire il vettore} dati
+n = asort(dati)
+for (i = 1; i <= n; i++)
+ @var{fare qualcosa con} dati[i]
+@end example
+
+Dopo la chiamata ad @code{asort()}, il vettore @code{dati} @`e indicizzato da 1
+a @var{n}, il numero totale di elementi in @code{dati}.
+(Questo conteggio @`e il valore di ritorno di @code{asort()}).
+@code{dati[1]} @value{LEQ} @code{dati[2]} @value{LEQ} @code{dati[3]}, e cos@`{@dotless{i}}
+via. Il confronto di default @`e basato sul tipo di elementi
+(@pxref{Tipi di variabile e confronti}).
+Tutti i valori numerici vengono prima dei valori di stringa,
+che a loro volta vengono prima di tutti i sottovettori.
+
+@cindex effetti collaterali, funzione @code{asort()}
+@cindex funzione @code{asort()}, effetti collaterali
+Un effetto collaterale rilevante nel chiamare @code{asort()} @`e che
+@emph{gli indici originali del vettore vengono persi irreparabilmente}.
+Poich@'e questo non sempre @`e opportuno, @code{asort()} accetta un
+secondo argomento:
+
+@example
+@var{populate the array} orig
+n = asort(orig, dest)
+for (i = 1; i <= n; i++)
+ @var{fai qualcosaa con} dest[i]
+@end example
+
+In questo caso, @command{gawk} copia il vettore @code{orig} nel vettore
+@code{dest} e ordina @code{dest}, distruggendo i suoi indici.
+Tuttavia il vettore @code{orig} non viene modificato.
+
+Spesso, ci@`o di cui si ha bisogno @`e di ordinare per i valori degli
+@emph{indici} invece che per i valori degli elementi. Per far questo si usa la
+funzione @code{asorti()}. L'interfaccia e il comportamento sono identici a
+quelli di @code{asort()}, solo che per l'ordinamento vengono usati i valori
+degli indici, che diventano i valori del vettore risultato:
+
+@example
+@{ orig[$0] = una_funz($0) @}
+
+END @{
+ n = asorti(orig, dest)
+ for (i = 1; i <= n; i++) @{
+ @ii{Lavora direttamente con gli indici ordinati:}
+ @var{fa qualcosa con} dest[i]
+ @dots{}
+ @ii{Accede al vettore originale attraverso gli indici ordinati:}
+ @var{fa qualcosa con} orig[dest[i]]
+ @}
+@}
+@end example
+
+Fin qui, tutto bene. Ora inizia la parte interessante. Sia @code{asort()}
+che @code{asorti()} accettano un terzo argomento di stringa per controllare il
+confronto di elementi del vettore. Quando abbiamo introdotto @code{asort()} e
+@code{asorti()} nella @ref{Funzioni per stringhe}, abbiamo ignorato questo terzo
+argomento; comunque, @`e giunto il momento di descrivere come questo argomento
+influenza queste due funzioni.
+
+Fondamentalmente, il terzo argomento specifica come dev'essere ordinato il
+vettore. Ci sono due possibilit@`a. Come per @code{PROCINFO["sorted_in"]},
+quest'argomento pu@`o essere uno degli argomenti predefiniti che @command{gawk}
+fornisce (@pxref{Controllare visita}), o pu@`o essere il nome di una funzione
+definita dall'utente (@pxref{Controllare visita vettori}).
+
+Nell'ultimo caso, @emph{la funzione pu@`o confrontare gli elementi in qualunque
+modo si voglia}, prendendo in considerazione solo gli indici, solo i valori,
+o entrambi. Questo @`e estremamente potente.
+
+Una volta che il vettore @`e ordinato, @code{asort()} prende i @emph{valori} nel
+loro ordine finale e li usa per riempire il vettore risultato, mentre
+@code{asorti()} prende gli @emph{indici} nel loro ordine finale e li usa per
+riempire il vettore risultato.
+
+@cindex conteggio riferimenti, ordinamento vettori
+@quotation NOTA
+Copiare indici ed elementi non @`e dispendioso in termini di memoria.
+Internamente, @command{gawk} mantiene un @dfn{conteggio dei riferimenti} ai
+dati. Per esempio, dopo che @code{asort()} copia il primo vettore nel
+secondo, in memoria c'@`e ancora una sola copia dei dati degli elementi
+del vettore originale, ed entrambi i vettori accedono all'unica copia di
+valori che esiste in memoria.
+@end quotation
+
+@c Document It And Call It A Feature. Sigh.
+@cindex @command{gawk}, variabile @code{IGNORECASE} in
+@cindex vettori, ordinamento, variabile @code{IGNORECASE} e
+@cindex @code{IGNORECASE}, variabile, e funzioni di ordinamento dei vettori
+@cindex variabile @code{IGNORECASE}, e funzioni di ordinamento dei vettori
+Poich@'e @code{IGNORECASE} influenza i confronti tra stringhe, il valore di
+@code{IGNORECASE} influisce anche sull'ordinamento sia con @code{asort()} che
+con @code{asorti()}.
+Si noti inoltre che l'ordinamento della localizzazione @emph{non} entra in
+gioco; i confronti sono basati solamente sul valore dei
+caratteri.@footnote{Ci@`o @`e vero perch@'e il confronto basato sulla localizzazione
+avviene solo quando si @`e in modalit@`a POSIX-compatibile, e poich@'e @code{asort()}
+e @code{asorti()} sono estensioni di @command{gawk}, esse non sono disponibili
+in quel caso.}
+
+L'esempio seguente mostra l'uso di una funzione di confronto usata con
+@code{asort()}. La funzione di confronto, @code{confronta_in_minuscolo()},
+trasforma gli elementi da confrontare in lettere minuscole, in modo da avere
+confronti che non dipendono da maiuscolo/minuscolo.
+
+@example
+# confronta_in_minuscolo --- confronta stringhe ignorando maiuscolo/minuscolo
+
+function confronta_in_minuscolo(i1, v1, i2, v2, l, r)
+@{
+ l = tolower(v1)
+ r = tolower(v2)
+
+ if (l < r)
+ return -1
+ else if (l == r)
+ return 0
+ else
+ return 1
+@}
+@end example
+
+E questo programma pu@`o essere usato per provarla:
+
+@example
+# programma di test
+
+BEGIN @{
+ Letters = "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ split(Letters, data, "")
+
+ asort(data, risultato, "confronta_in_minuscolo")
+
+ j = length(risultato) # numero elementi del vettore "risultato"
+ for (i = 1; i <= j; i++) @{
+ printf("%s", risultato[i])
+ if (i % (j/2) == 0)
+ # a met@`a, la stampa del vettore va a capo
+ printf("\n")
+ else
+ printf(" ")
+ @}
+@}
+@end example
+
+Se si esegue il programma, si ottiene:
+
+@example
+$ @kbd{gawk -f confronta_in_minuscolo.awk}
+@print{} A a B b c C D d e E F f g G H h i I J j k K l L M m
+@print{} n N O o p P Q q r R S s t T u U V v w W X x y Y z Z
+@end example
+
+@node I/O bidirezionale
+@section Comunicazioni bidirezionali con un altro processo
+
+@c 8/2014. Neither Mike nor BWK saw this as relevant. Commenting it out.
+@ignore
+@cindex Brennan, Michael
+@cindex programmers, attractiveness of
+@smallexample
+@c Path: cssun.mathcs.emory.edu!gatech!newsxfer3.itd.umich.edu!news-peer.sprintlink.net!news-sea-19.sprintlink.net!news-in-west.sprintlink.net!news.sprintlink.net!Sprint!204.94.52.5!news.whidbey.com!brennan
+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
+@c Organization: WhidbeyNet
+@c Lines: 12
+Message-ID: <5s53rm$eca@@news.whidbey.com>
+@c References: <5s20dn$2e1@chronicle.concentric.net>
+@c Reply-To: brennan@whidbey.com
+@c NNTP-Posting-Host: asn202.whidbey.com
+@c X-Newsreader: slrn (0.9.4.1 UNIX)
+@c Xref: cssun.mathcs.emory.edu comp.lang.awk:5403
+
+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
+@c brennan@@whidbey.com
+@end smallexample
+@end ignore
+
+@cindex funzionalit@`a avanzate, processi@comma{} comunicare con
+@cindex processi, comunicazioni bidirezionali con
+Spesso @`e utile poter
+inviare dati a un programma separato che
+li elabori e in seguito leggere il risultato. Questo pu@`o essere sempre
+fatto con file temporanei:
+
+@example
+# Scrivere i dati per l'elaborazione
+filetemp = ("mieidati." PROCINFO["pid"])
+while (@var{non dipendente dai dati})
+ print @var{dati} | ("sottoprogramma > " filetemp)
+close("sottoprogramma > " filetemp)
+
+# Legge il risultato, rimuove filetemp quando ha finito
+while ((getline nuovidati < filetemp) > 0)
+ @var{elabora} nuovidati @var{secondo le esigenze}
+close(filetemp)
+system("rm " filetemp)
+@end example
+
+@noindent
+Questo funziona, ma non @`e elegante. Tra le altre cose, richiede che il
+programma venga eseguito in una directory che non pu@`o essere condivisa tra gli
+utenti; per esempio, @file{/tmp} non pu@`o esserlo, poich@'e potrebbe accadere che
+un altro utente stia usando un file temporaneo con lo stesso
+nome.@footnote{Michael Brennan suggerisce l'uso di @command{rand()} per
+generare @value{FNS} unici. Questo @`e un punto valido; tuttavia, i file
+temporanei rimangono pi@`u difficili da usare delle @dfn{pipe} bidirezionali.} @c 8/2014
+
+@cindex coprocessi
+@cindex input/output bidirezionale
+@cindex @code{|} (barra verticale), operatore @code{|&} (I/O)
+@cindex barra verticale (@code{|}), operatore @code{|&} (I/O)
+@cindex @command{csh}, comando, operatore @code{|&}, confronto con
+@cindex comando @command{csh}, operatore @code{|&}, confronto con
+Comunque, con @command{gawk}, @`e possibile aprire una @dfn{pipe}
+@emph{bidirezionale}
+verso un altro processo. Il secondo processo @`e chiamato @dfn{coprocesso},
+poich@'e viene eseguito in parallelo con @command{gawk}. La connessione
+bidirezionale viene creata usando l'operatore @samp{|&} (preso in prestito
+dalla shell Korn, @command{ksh}):@footnote{Questo @`e molto diverso dallo stesso
+operatore nella C shell e in Bash.}
+
+@example
+do @{
+ print @var{dati} |& "sottoprogramma"
+ "sottoprogramma" |& getline risultato
+@} while (@var{ci sono ancora dati da elaborare})
+close("sottoprogramma")
+@end example
+
+La prima volta che viene eseguita un'operazione I/O usando l'operatore
+@samp{|&},
+@command{gawk} crea una @dfn{pipeline} bidirezionale verso un processo figlio
+che esegue l'altro programma. L'output creato con @code{print} o con
+@code{printf} viene scritto nello standard input del programma, e il contenuto
+dello standard output del programma pu@`o essere letto dal programma
+@command{gawk} usando @code{getline}.
+Come accade coi processi avviati con @samp{|}, il sottoprogramma pu@`o
+essere un qualsiasi programma, o una @dfn{pipeline} di programmi, che pu@`o essere
+avviato dalla shell.
+
+Ci sono alcune avvertenze da tenere presenti:
+
+@itemize @value{BULLET}
+@item
+Per come funziona internamente @command{gawk}, lo standard error
+dei coprocessi va nello stesso posto dove va lo standard error del
+genitore @command{gawk}. Non @`e possibile leggere lo standard error del
+figlio separatamente.
+
+@cindex stalli
+@cindex abbracci mortali
+@cindex @dfn{deadlocks}, vedi stalli
+@cindex bufferizzazione, dell'input/output
+@cindex input/output, bufferizzazione
+@cindex @code{getline}, comando, stalli e
+@item
+La permanenza in memoria (bufferizzazione) dell'I/O del sottoprocesso potrebbe
+essere un problema. @command{gawk} automaticamente scrive su disco tutto
+l'output spedito tramite la @dfn{pipe} al coprocesso.
+Tuttavia, se il coprocesso non scrive su disco il suo output,
+@command{gawk} potrebbe bloccarsi mentre esegue una @code{getline} per leggere
+il risultato del coprocesso. Questo pu@`o portare a una situazione
+conosciuta come @dfn{stallo} (@dfn{deadlock}, abbraccio mortale), in cui ciascun
+processo rimane in attesa
+che l'altro processo faccia qualcosa.
+@end itemize
+
+@cindex @code{close()}, funzione, @dfn{pipe} bidirezionali e
+@cindex funzione @code{close()}, @dfn{pipe} bidirezionali e
+@`E possibile chiudere una @dfn{pipe} bidirezionale con un coprocesso solo in una
+direzione, fornendo un secondo argomento, @code{"to"} o @code{"from"}, alla
+funzione @code{close()} (@pxref{Chiusura file e @dfn{pipe}}).
+Queste stringhe dicono a @command{gawk} di chiudere la @dfn{pipe}, rispettivamente
+nella direzione che invia i dati al coprocesso e nella direzione che legge da
+esso.
+
+@cindex @command{sort}, programma di utilit@`a, coprocessi e
+@cindex programma di utilit@`a @command{sort}, coprocessi e
+Questo @`e particolarmente necessario per usare il programma di utilit@`a
+di sistema @command{sort} come parte di un coprocesso;
+@command{sort} deve leggere @emph{tutti} i dati di input
+prima di poter produrre un qualsiasi output.
+Il programma @command{sort} non riceve un'indicazione di fine-file
+(end-of-file) finch@'e @command{gawk} non chiude l'estremit@`a in scrittura della
+@dfn{pipe}.
+
+Una volta terminata la scrittura dei dati sul programma @command{sort},
+si pu@`o chiudere il lato @code{"to"} della @dfn{pipe}, e quindi iniziare a leggere
+i dati ordinati via @code{getline}.
+Per esempio:
+
+@example
+BEGIN @{
+ comando = "LC_ALL=C sort"
+ n = split("abcdefghijklmnopqrstuvwxyz", a, "")
+
+ for (i = n; i > 0; i--)
+ print a[i] |& comando
+ close(comando, "to")
+
+ while ((comando |& getline line) > 0)
+ print "ricevuto", line
+ close(comando)
+@}
+@end example
+
+Questo programma scrive le lettere dell'alfabeto in ordine inverso, uno per
+riga, attraverso la @dfn{pipe} bidirezionale verso @command{sort}. Poi chiude la
+direzione di scrittura della @dfn{pipe}, in modo che @command{sort} riceva
+un'indicazione di fine-file. Questo fa in modo che @command{sort} ordini i
+dati e scriva i dati ordinati nel programma @command{gawk}. Una volta che
+tutti i dati sono stati letti, @command{gawk} termina il coprocesso ed esce.
+
+Come nota a margine, l'assegnamento @samp{LC_ALL=C} nel comando @command{sort}
+assicura che @command{sort} usi l'ordinamento tradizionale di Unix (ASCII).
+Ci@`o non @`e strettamente necessario in questo caso, ma @`e bene sapere come farlo.
+
+Occorre prestare attenzione quando si chiude il lato @code{"from"} di una
+@dfn{pipe} bidirezionale; in tal caso @command{gawk} attende che il
+processo-figlio termini, il che pu@`o causare lo stallo del programma
+@command{awk} in esecuzione. (Per questo motivo, questa particolare
+funzionalit@`a @`e molto meno usata, in pratica, di quella che consente la
+possibilit@`a di chiudere il lato @code{"to"} della @dfn{pipe}.)
+
+@quotation ATTENZIONE
+Normalmente,
+@`e un errore fatale (che fa terminare il programma @command{awk})
+scrivere verso il lato @code{"to"} di una @dfn{pipe} bidirezionale che
+@`e stata chiusa, e lo stesso vale se si legge dal lato @code{"from"}
+di una @dfn{pipe} bidirezionale che sia stata chiusa.
+
+@`E possibile impostare @code{PROCINFO["@var{comando}", "NONFATAL"]}
+per far s@`{@dotless{i}} che tali operazioni non provochino la fine del programma
+@command{awk}. Se lo si fa, @`e necessario controllare il valore
+di @code{ERRNO} dopo ogni istruzione @code{print}, @code{printf},
+o @code{getline}.
+@xref{Continuazione dopo errori} per ulteriori informazioni.
+@end quotation
+
+@cindex @command{gawk}, vettore @code{PROCINFO} in
+@cindex @code{PROCINFO}, vettore, e comunicazioni attraverso le @dfn{pty}
+Per le comunicazioni bidirezionali si possono anche usare delle pseudo @dfn{tty}
+(@dfn{pty}) al posto delle @dfn{pipe}, se il sistema in uso le prevede.
+Questo vien fatto, a seconda del comando da usare, impostando un elemento
+speciale nel vettore @code{PROCINFO}
+(@pxref{Variabili auto-assegnate}),
+in questo modo:
+
+@example
+comando = "sort -nr" # comando, salvato in una variabile
+PROCINFO[comando, "pty"] = 1 # aggiorna PROCINFO
+print @dots{} |& comando # avvia la @dfn{pipe} bidirezionale
+@dots{}
+@end example
+
+@noindent
+Se il sistema in uso non ha le @dfn{pty}, o se tutte le @dfn{pty} del sistema
+sono in uso, @command{gawk} automaticamente torna a usare le @dfn{pipe}
+regolari.
+
+Usare le @dfn{pty} in genere evita i problemi di stallo del buffer descritti
+precedentemente, in cambio di un piccolo calo di prestazioni. Ci@`o dipende
+dal fatto che la gestione delle @dfn{tty} @`e fatta una riga per volta.
+Su sistemi che hanno il comando @command{stdbuf} (parte del pacchetto
+@uref{http://www.gnu.org/software/coreutils/coreutils.html,
+GNU Coreutils}), si pu@`o usare tale programma, invece delle @dfn{pty}.
+
+Si noti anche che le @dfn{pty} non sono completamente trasparenti.
+Alcuni codici di controllo binari, come @kbd{Ctrl-d} per indicare la
+condizione di file-file, sono interpetati dal gestore di @dfn{tty}
+e non sono passati all'applicazione.
+
+@quotation ATTENZIONE
+In ultima analisi, i coprocessi danno adito alla possibilit@`a di uno
+@dfn{stallo} (deadlock) tra @command{gawk} e il programma in esecuzione
+nel coprocesso. Ci@`o pu@`o succedere se si inviano ``troppi'' dati al
+coprocesso, prima di leggere dati inviati dallo stesso; entrambi i
+processi sono bloccati sulla scrittura dei dati, e nessuno dei due
+@`e disponibile a leggere quelli che sono gi@`a stati scritti dall'altro.
+Non c'@`e modo di evitare completamente una tale situazione; occorre una
+programmazione attenta, insieme alla conoscenza del comportamento del
+coprocesso.
+@end quotation
+
+@node Reti TCP/IP
+@section Usare @command{gawk} per la programmazione di rete
+@cindex funzionalit@`a avanzate, programmazione di rete
+@cindex avanzate, funzionalit@`a, programmazione di rete
+@cindex reti, programmazione di
+@cindex TCP/IP
+@cindex @code{/inet/@dots{}}, file speciali (in @command{gawk})
+@cindex file speciali @code{/inet/@dots{}} (in @command{gawk})
+@cindex @code{/inet4/@dots{}}, file speciali (in @command{gawk})
+@cindex file speciali @code{/inet4/@dots{}} (in @command{gawk})
+@cindex @code{/inet6/@dots{}}, file speciali (in @command{gawk})
+@cindex file speciali @code{/inet6/@dots{}} (in @command{gawk})
+@cindex @code{EMRED}
+@ifnotdocbook
+@quotation
+@code{EMRED}:@*
+@ @ @ @ @i{A host is a host from coast to coast,@*
+@ @ @ @ and nobody talks to a host that's close,@*
+@ @ @ @ unless the host that isn't close@*
+@ @ @ @ is busy, hung, or dead.}
+
+@code{EMRED}:@*
+@ @ @ @ @i{Un computer @`e un computer lontano o vicino,@*
+@ @ @ @ e nessuno parla con un computer vicino,@*
+@ @ @ @ a meno che il computer lontano@*
+@ @ @ @ sia occupato, fuori linea, o spento.}
+@author Mike O'Brien (noto anche come Mr.@: Protocol)
+@end quotation
+@end ifnotdocbook
+
+@docbook
+<blockquote>
+<attribution>Mike O'Brien (aka Mr.&nbsp;Protocol)</attribution>
+<literallayout class="normal"><literal>EMRED</literal>:
+&nbsp;&nbsp;&nbsp;&nbsp;<emphasis>A host is a host from coast to coast,</emphasis>
+&nbsp;&nbsp;&nbsp;&nbsp;<emphasis>and no-one can talk to host that's close,</emphasis>
+&nbsp;&nbsp;&nbsp;&nbsp;<emphasis>unless the host that isn't close</emphasis>
+&nbsp;&nbsp;&nbsp;&nbsp;<emphasis>is busy, hung, or dead.</emphasis></literallayout>
+</blockquote>
+@end docbook
+
+Oltre a poter aprire una @dfn{pipeline} bidirezionale verso un coprocesso
+sullo stesso sistema
+(@pxref{I/O bidirezionale}),
+@`e possibile attivare una connessione bidirezionale verso un altro processo
+o verso un altro sistema attraverso una connessione di rete IP.
+
+Si pu@`o pensare a questo semplicemente come a una @dfn{pipeline} bidirezionale
+@emph{molto lunga} verso un coprocesso.
+Il modo in cui @command{gawk} stabilisce quando usare una rete TCP/IP @`e
+mediante il riconoscimento di speciali @value{FNS} che iniziano con
+@samp{/inet/}, con @samp{/inet4/} o con @samp{/inet6/}.
+
+La sintassi completa del @value{FN} speciale @`e
+@file{/@var{tipo-rete}/@var{protocollo}/@var{porta-locale}/@var{host-remoto}/@var{porta-remota}}.
+I componenti sono:
+
+@table @var
+@item tipo-rete
+Specifica il tipo di connessione a internet da stabilire.
+Si usa @samp{/inet4/} per usare solo IPv4, e
+@samp{/inet6/} per usare solo IPv6.
+Il semplice @samp{/inet/} (che usualmente @`e l'unica opzione) usa
+il tipo di default del sistema, quasi certamente IPv4.
+
+@item protocollo
+Il protocollo da usare sull'IP. Questo dev'essere o @samp{tcp} o
+@samp{udp}, per una connessione IP rispettivamente TCP o UDP.
+TCP dovrebbe venir usato per la maggior parte delle applicazioni.
+
+@item porta-locale
+@cindex @code{getaddrinfo()}, funzione (libreria C)
+@cindex funzione @code{getaddrinfo()} (libreria C)
+Il numero di porta TCP o UDP da usare. Si usa un numero di porta di valore
+@samp{0} quando si vuole che sia il sistema a scegliere una porta.
+Questo @`e quel che si dovrebbe fare quando si scrive un'applicazione
+cliente TCP o UDP.
+Si pu@`o usare anche un nome di un servizio noto, come @samp{smtp}
+o @samp{http}, nel qual caso @command{gawk} tenta di determinare
+il numero di porta predefinito usando la funzione C @code{getaddrinfo()}.
+
+@item host-remoto
+L'indirizzo IP o il nome di dominio completamente qualificato dell'host
+internet al quale ci si vuol connettere.
+
+@item porta-remota
+Il numero di porta TCP o UDP da usare sul particolare @var{host remoto}.
+Anche in questo caso, si usi @samp{0} se non ci sono preferenze,
+o alternativamente, un nome di servizio comunemente noto.
+@end table
+
+@cindex @command{gawk}, variabile @code{ERRNO} in
+@cindex @code{ERRNO}, variabile
+@cindex variabile @code{ERRNO}
+@quotation NOTA
+Un insuccesso nell'apertura di un socket bidirezionale dar@`a luogo alla
+segnalazione di un errore non fatale al codice chiamante.
+Il valore di @code{ERRNO} indica l'errore (@pxref{Variabili auto-assegnate}).
+@end quotation
+
+Si consideri il seguente esempio molto semplice:
+
+@example
+BEGIN @{
+ Servizio = "/inet/tcp/0/localhost/daytime"
+ Servizio |& getline
+ print $0
+ close(Servizio)
+@}
+@end example
+
+Questo programma legge la data e l'ora corrente dal server @code{daytime}
+TCP del sistema locale.
+Stampa poi il risultato e chiude la connessione.
+
+Poich@'e questo tema @`e molto ampio, l'uso di @command{gawk} per
+la programmazione TCP/IP viene documentato separatamente.
+@ifinfo
+Si veda
+@inforef{Top, , General Introduction, gawkinet, @value{GAWKINETTITLE}},
+@end ifinfo
+@ifnotinfo
+Si veda
+@uref{http://www.gnu.org/software/gawk/manual/gawkinet/,
+@cite{@value{GAWKINETTITLE}}},
+che fa parte della distribuzione @command{gawk},
+@end ifnotinfo
+per una introduzione e trattazione molto pi@`u completa e con molti
+esempi.
+
+@quotation NOTA
+@command{gawk} pu@`o aprire solo socket diretti. Al momento non c'@`e alcun modo
+per accedere ai servizi disponibili su Secure Socket Layer
+(SSL); questo comprende qualsiasi servizio web il cui URL inizia con
+@samp{https://}.
+@end quotation
+
+
+@node Profilare
+@section Profilare i propri programmi @command{awk}
+@cindex @command{awk}, programmi, profilare
+@cindex profilare programmi @command{awk}
+@cindex @code{awkprof.out}, file
+@cindex file @code{awkprof.out}
+
+@`E possibile tener traccia dell'esecuzione dei propri programmi @command{awk}.
+Ci@`o si pu@`o fare passando l'opzione @option{--profile} a @command{gawk}.
+Al termine dell'esecuzione, @command{gawk} crea un profilo del programma in un
+file chiamato @file{awkprof.out}. A causa dell'attivit@`a di profilazione
+l'esecuzione del programma @`e pi@`u lenta fino al 45% rispetto al normale.
+
+@cindex @option{--profile}, opzione
+@cindex opzione @option{--profile}
+Come mostrato nel seguente esempio,
+l'opzione @option{--profile} pu@`o essere usata per cambiare il nome del file
+su cui @command{gawk} scriver@`a il profilo:
+
+@example
+gawk --profile=mioprog.prof -f mioprog.awk dati1 dati2
+@end example
+
+@noindent
+Nell'esempio precedente, @command{gawk} mette il profilo in
+@file{mioprog.prof} anzich@'e in @file{awkprof.out}.
+
+Vediamo ora una sessione d'esempio che mostra un semplice programma
+@command{awk}, i suoi dati in input, e il risultato dell'esecuzione di
+@command{gawk} con l'opzione @option{--profile}. Innanzitutto, il
+programma @command{awk}:
+
+@example
+BEGIN @{ print "Prima regola BEGIN" @}
+
+END @{ print "Prima regola END" @}
+
+/pippo/ @{
+ print "trovato /pippo/, perbacco"
+ for (i = 1; i <= 3; i++)
+ sing()
+@}
+
+@{
+ if (/pippo/)
+ print "l'if @`e vero"
+ else
+ print "l'else @`e vero"
+@}
+
+BEGIN @{ print "Seconda regola BEGIN" @}
+
+END @{ print "Seconda regola END" @}
+
+function sing( ignora)
+@{
+ print "Devo essere io!"
+@}
+@end example
+
+Questi sono i dati in input:
+
+@example
+pippo
+pluto
+paperino
+pippo
+cianfrusaglie
+@end example
+
+E questo @`e il file @file{awkprof.out} che @`e il risultato dell'esecuzione
+del profilatore di @command{gawk} su questo programma e sui dati (quest'esempio
+dimostra anche che i programmatori di @command{awk} a volte si alzano molto
+presto al mattino per lavorare):
+
+@cindex @code{BEGIN}, criterio di ricerca, e profilatura
+@cindex criterio di ricerca @code{BEGIN}, e profilatura
+@cindex @code{END}, criterio di ricerca, e profilatura
+@cindex criterio di ricerca @code{END}, e profilatura
+@example
+ # profilo gawk, creato Mon Sep 29 05:16:21 2014
+
+ # BEGIN regola(e)
+
+ BEGIN @{
+ 1 print "Prima regola BEGIN"
+ @}
+
+ BEGIN @{
+ 1 print "Seconda regola BEGIN"
+ @}
+
+ # Regola(e)
+
+ 5 /pippo/ @{ # 2
+ 2 print "trovato /pippo/, perbacco"
+ 6 for (i = 1; i <= 3; i++) @{
+ 6 sing()
+ @}
+ @}
+
+ 5 @{
+ 5 if (/pippo/) @{ # 2
+ 2 print "l'if @`e vero"
+ 3 @} else @{
+ 3 print "l'else @`e vero"
+ @}
+ @}
+
+ # END regola(e)
+
+ END @{
+ 1 print "Prima regola END"
+ @}
+
+ END @{
+ 1 print "Seconda regola END"
+ @}
+
+
+ # Funzioni, in ordine alfabetico
+
+ 6 function sing(ignora)
+ @{
+ 6 print "Devo essere io!"
+ @}
+@end example
+
+Quest'esempio illustra molte caratteristiche fondamentali dell'output
+della profilazione.
+Queste sono:
+
+@itemize @value{BULLET}
+@item
+Il programma viene stampato nell'ordine: regole @code{BEGIN},
+regole @code{BEGINFILE},
+regole criterio di ricerca--azione,
+regole @code{ENDFILE}, regole @code{END}, e funzioni, elencate
+in ordine alfabetico.
+Le regole @code{BEGIN} ed @code{END} multiple conservano le loro
+distinte identit@`a, cos@`{@dotless{i}} come le regole @code{BEGINFILE} ed @code{ENDFILE}
+multiple.
+
+@cindex criteri di ricerca, conteggi, in un profilo
+@item
+Le regole criterio di ricerca--azione hanno due conteggi.
+Il primo conteggio, a sinistra della regola, mostra quante volte
+il criterio di ricerca della regola @`e stato @emph{testato}.
+Il secondo conteggio, alla destra della parentesi graffa aperta,
+all'interno di un commento,
+mostra quante volte l'azione della regola @`e stata @emph{eseguita}.
+La differenza tra i due indica quante volte il criterio di ricerca della regola
+@`e stato valutato come falso.
+
+@item
+Analogamente,
+il conteggio per un'istruzione @code{if}-@code{else} mostra quante volte
+la condizione @`e stata testata.
+Alla destra della parentesi graffa sinistra aperta per il corpo di @code{if}
+c'@`e un conteggio che mostra quante volte la condizione @`e stata trovata vera.
+Il conteggio per @code{else} indica
+quante volte la verifica non ha avuto successo.
+
+@cindex cicli, conteggi per l'intestazione, in un profilo
+@item
+Il conteggio per un ciclo (come @code{for}
+o @code{while}) mostra quante volte il test del ciclo @`e stato eseguito.
+(Per questo motivo, non si pu@`o solamente guardare il conteggio sulla prima
+istruzione in una regola per determinare quante volte la regola @`e stata
+eseguita. Se la prima istruzione @`e un ciclo, il conteggio @`e ingannevole.)
+
+@cindex funzioni definite dall'utente, conteggi, in un profilo
+@cindex definite dall'utente, funzioni, conteggi, in un profilo
+@item
+Per le funzioni definite dall'utente, il conteggio vicino alla parola chiave
+@code{function} indica quante volte la funzione @`e stata chiamata.
+I conteggi vicino alle istruzioni nel corpo mostrano quante volte
+quelle istruzioni sono state eseguite.
+
+@cindex @code{@{@}} (parentesi graffe)
+@cindex parentesi graffe (@code{@{@}})
+@item
+L'impaginazione usa lo stile ``K&R'' con le tabulazioni.
+Le parentesi graffe sono usate dappertutto, anche dove il corpo di un
+@code{if}, di un @code{else} o di un ciclo @`e formato da un'unica istruzione.
+
+@cindex @code{()} (parentesi), in un profilo
+@cindex parentesi (@code{()}), in un profilo
+@item
+Le parentesi vengono usate solo dov'@`e necessario, come si rileva dalla
+struttura del programma e dalle regole di precedenza.
+Per esempio, @samp{(3 + 5) * 4} significa sommare tre e cinque, quindi
+moltiplicare il totale per quattro. Di contro, @samp{3 + 5 * 4} non ha
+parentesi, e significa @samp{3 + (5 * 4)}.
+
+@ignore
+@item
+All string concatenations are parenthesized too.
+(This could be made a bit smarter.)
+@end ignore
+
+@item
+Le parentesi vengono usate attorno agli argomenti di @code{print}
+e @code{printf} solo quando l'istruzione
+@code{print} o @code{printf} @`e seguita da una ridirezione.
+Similarmente, se
+l'oggetto di una ridirezione non @`e uno scalare, viene messo tra parentesi.
+
+@item
+@command{gawk} mette dei commenti iniziali
+davanti alle regole @code{BEGIN} ed @code{END},
+alle regole @code{BEGINFILE} ed @code{ENDFILE},
+alle regole criterio_di_ricerca--azione e alle funzioni.
+
+@end itemize
+
+La versione profilata del proprio programma potrebbe non apparire esattamente
+come quella scritta durante la stesura del programma. Questo perch@'e
+@command{gawk} crea la versione profilata facendo una ``stampa elegante'' della
+sua rappresentazione interna del programma. Un vantaggio di ci@`o @`e che
+@command{gawk} pu@`o produrre una rappresentazione standard.
+Inoltre, cose come:
+
+@example
+/pippo/
+@end example
+
+@noindent
+appaiono come:
+
+@example
+/pippo/ @{
+ print $0
+@}
+@end example
+
+@noindent
+che @`e corretto, ma probabilmente inatteso.
+
+@cindex profilare programmi @command{awk}, dinamicamente
+@cindex @command{gawk}, programma, profilazione dinamica
+@cindex profilazione dinamica
+Oltre a creare profili una volta completato il programma,
+@command{gawk} pu@`o generare un profilo mentre @`e in esecuzione.
+Questo @`e utile se il proprio programma @command{awk} entra in un ciclo
+infinito e si vuol vedere cosa @`e stato eseguito.
+Per usare questa funzionalit@`a, bisogna eseguire @command{gawk} con l'opzione
+@option{--profile} in background:
+
+@example
+$ @kbd{gawk --profile -f mioprog &}
+[1] 13992
+@end example
+
+@cindex @command{kill}, comando@comma{} profilazione dinamica e
+@cindex comando @command{kill}@comma{} profilazione dinamica e
+@cindex @code{USR1}, segnale, per profilazione dinamica
+@cindex @code{SIGUSR1}, segnale, per profilazione dinamica
+@cindex segnali @code{USR1}/@code{SIGUSR1}, per profilazione
+@noindent
+La shell stampa un numero di job e il numero di ID del relativo processo;
+in questo caso, 13992. Si usi il comando @command{kill} per inviare il
+segnale @code{USR1} a @command{gawk}:
+
+@example
+$ @kbd{kill -USR1 13992}
+@end example
+
+@noindent
+Come al solito, la versione profilata del programma @`e scritta nel file
+@file{awkprof.out}, o in un file differente se ne viene specificato uno
+con l'opzione @option{--profile}.
+
+Assieme al profilo regolare, come mostrato in precedenza, il file del profilo
+include una traccia di ogni funzione attiva:
+
+@example
+# `Stack' (Pila) Chiamate Funzione:
+
+# 3. paperino
+# 2. pluto
+# 1. pippo
+# -- main --
+@end example
+
+Si pu@`o inviare a @command{gawk} il segnale @code{USR1} quante volte si vuole.
+Ogni volta, il profilo e la traccia della chiamata alla funzione vengono
+aggiunte in fondo al file di profilo creato.
+
+@cindex @code{HUP}, segnale, per profilazione dinamica
+@cindex @code{SIGHUP}, segnale, per profilazione dinamica
+@cindex segnali @code{HUP}/@code{SIGHUP}, per profilazione
+Se si usa il segnale @code{HUP} invece del segnale @code{USR1}, @command{gawk}
+genera il profilo e la traccia della chiamata alla funzione ed esce.
+
+@cindex @code{INT}, segnale (MS-Windows)
+@cindex @code{SIGINT}, segnale (MS-Windows)
+@cindex segnali @code{INT}/@code{SIGINT} (MS-Windows)
+@cindex @code{QUIT}, segnale (MS-Windows)
+@cindex @code{SIGQUIT}, segnale (MS-Windows)
+@cindex segnali @code{QUIT}/@code{SIGQUIT} (MS-Windows)
+Quando @command{gawk} viene eseguito sui sistemi MS-Windows, usa i segnali
+@code{INT} e @code{QUIT} per generare il profilo, e nel
+caso del segnale @code{INT}, @command{gawk} esce. Questo perch@'e
+questi sistemi non prevedono il comando @command{kill}, per cui gli unici
+segnali che si possono trasmettere a un programma sono quelli generati dalla
+tastiera. Il segnale @code{INT} @`e generato dalle combinazioni di tasti
+@kbd{Ctrl-c} o @kbd{Ctrl-BREAK}, mentre il segnale
+@code{QUIT} @`e generato dalla combinazione di tasti @kbd{Ctrl-\}.
+
+Infine, @command{gawk} accetta anche un'altra opzione, @option{--pretty-print}.
+Quando viene chiamato in questo modo, @command{gawk} fa una ``stampa elegante''
+del programma nel file @file{awkprof.out}, senza conteggi sull'esecuzione.
+
+@quotation NOTA
+Una volta, l'opzione @option{--pretty-print} eseguiva anche il programma.
+Ora non pi@`u.
+@end quotation
+
+C'@`e una differenza significativa tra l'output creato durante la profilazione, e
+quello creato durante la stampa elegante. L'output della stampa elegante
+preserva i commenti originali che erano nel programma, anche se la loro
+posizione pu@`o non corrispondere esattamente alle posizioni originali che
+avevano nel codice sorgente.@footnote{@command{gawk} fa del suo meglio
+per mantenere la distinzione tra commenti posti dopo delle istruzioni e
+commenti su righe a s@'e stanti. Per limiti insiti nell'implementazione,
+non sempre questo pu@`o avvenire in maniera corretta, in particolare nel
+caso di istruzioni @code{switch}. I manutentori di @command{gawk}
+sperano di poter migliorare la situazione in una futura versione.}
+
+Comunque, per una precisa scelta progettuale, l'output della profilazione
+@emph{omette} i commenti del programma originale. Questo permette di
+concentrarsi sui dati del conteggio di esecuzione ed evita la tentazione di
+usare il profilatore per creare una stampa elegante.
+
+Oltre a ci@`o, l'output stampato in modo elegante non ha l'indentazione iniziale
+che ha l'output della profilazione. Questo rende agevole la stampa elegante
+del proprio codice una volta completato lo sviluppo, usando poi il risultato
+come versione finale del programma.
+
+Poich@'e la rappresentazione interna del programma @`e formattata per
+essere aderente al programma @command{awk} in questione, la profilatura
+e la formattazione graziosa (opzione @option{--pretty-print}) disabilitano
+automaticamente le optimizzazioni di default di @command{gawk}.
+
+La formattazione elegante mantiene anche il formato originale delle
+costanti numeriche; se sono stati usati dei valori ottali o esadecimali
+nel codice sorgente, questi compariranno nell'output nello stesso
+formato con cui sono stati inseriti.
+
+@node Sommario funzionalit@`a avanzate
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+L'opzione @option{--non-decimal-data} fa s@`{@dotless{i}} che @command{gawk} tratti
+i dati di input che hanno l'aspetto ottale ed esadecimale come valori ottali ed
+esadecimali. L'opzione dovrebbe essere usata con prudenza o non usata affatto;
+@`e preferibile l'uso di @code{strtonum()}.
+Si noti che quest'opzione potrebbe sparire nelle prossime versioni di
+@command{gawk}.
+
+@item
+Si pu@`o prendere il completo controllo dell'ordinamento nello scorrere il
+vettore con @samp{for (@var{indice} in @var{vettore})}, impostando
+@code{PROCINFO["sorted_in"]} al nome di una funzione definita dall'utente che
+fa il confronto tra elementi del vettore basandosi su indice e valore.
+
+@item
+Analogamente, si pu@`o fornire il nome di una funzione di confronto definita
+dall'utente come terzo argomento di @code{asort()} o di @command{asorti()} per
+controllare come queste funzioni ordinano i vettori. O si pu@`o fornire una delle
+stringhe di controllo predefinite che funzionano per
+@code{PROCINFO["sorted_in"]}.
+
+@item
+Si pu@`o usare l'operatore @samp{|&} per creare una @dfn{pipe} bidirezionale
+verso un coprocesso. Si legge dal coprocesso con @code{getline}, ci si
+scrive sopra con @code{print} o con @code{printf}. Usare @code{close()}
+per bloccare il coprocesso completamente o, se necessario, chiudere le
+comunicazioni bidirezionali in una direzione.
+
+@item
+Usando degli speciali @value{FNS} con l'operatore @samp{|&}, si pu@`o aprire una
+connessione TCP/IP (o UDP/IP) verso host remoti su internet. @command{gawk}
+supporta sia IPv4 che IPv6.
+
+@item
+Si possono generare profili del proprio programma con i conteggi del numero
+di esecuzione di ogni singola
+istruzione. Questo pu@`o essere d'aiuto nel determinare quali parti del programma
+potrebbero portar via la maggior parte del tempo, consentendo cos@`{@dotless{i}} di
+aggiustarli pi@`u agevolmente. Inviando il segnale @code{USR1} durante la
+profilazione @command{gawk} scrive il profilo, includendo la
+stack della chiamata alla funzione e prosegue nell'elaborazione.
+
+@item
+Si pu@`o anche fare solo una ``stampa elegante'' del programma.
+
+@end itemize
+@node Internazionalizzazione
+@chapter Internazionalizzazione con @command{gawk}
+
+Tanto tempo fa i produttori di computer
+scrivevano software che comunicava solo in inglese.
+Col passare del tempo, i venditori di hardware e di software si sono
+resi conto che se i loro sistemi avessero comunicato anche nelle lingue
+materne di paesi dove non si parlava inglese,
+ci@`o avrebbe avuto come risultato un incremento delle vendite.
+Per questo motivo, l'internazionalizzazione e la localizzazione
+di programmi e sistemi software @`e divenuta una pratica comune.
+
+@cindex internazionalizzazione, localizzazione
+@cindex @command{gawk}, internazionalizzazione e, si veda internazionalizzazione
+@cindex internazionalizzazione, localizzazione, @command{gawk} e
+Per molti anni la possibilit@`a di fornire l'internazionalizzazione
+era sostanzialmente limitata ai programmi scritti in C e C++.
+Questo @value{CHAPTER} descrive la libreria @dfn{ad hoc} utilizzata da
+@command{gawk}
+per l'internazionalizzazione e anche il modo in cui le funzionalit@`a che
+consentono l'internazionalizzazione sono rese disponibili da @command{gawk}
+a ogni programma scritto in @command{awk}.
+La disponibilit@`a dell'internazionalizzazione a livello di programma
+@command{awk} offre ulteriore flessibilit@`a agli sviluppatori di software:
+non sono pi@`u obbligati a scrivere in C o C++ quando l'internazionalizzazione
+@`e necessaria in un programma.
+
+@menu
+* I18N e L10N:: Internazionalizzazione e localizzazione.
+* Utilizzare @command{gettext}:: Come funziona il comando GNU @command{gettext}.
+* I18N per programmatore:: Funzionalit@`a per il programmatore.
+* I18N per traduttore:: Funzionalit@`a per il traduttore.
+* Esempio I18N:: Un semplice esempio di internazionalizzazione.
+* Gawk internazionalizzato:: Anche @command{gawk} @`e internazionalizzato.
+* Sommario I18N:: Sommario dell'internazionalizzazione.
+@end menu
+
+@node I18N e L10N
+@section Internazionalizzazione e localizzazione
+
+@cindex internazionalizzazione di programmi @command{awk}
+@cindex localizzazione, si veda internazionalizzazione@comma{} localizzazione
+@cindex localizzazione
+@dfn{Internazionalizzazione} significa scrivere (o modificare) un programma
+una volta sola,
+in maniera tale che possa usare pi@`u di una lingua senza
+bisogno di ulteriori modifiche al file sorgente.
+@dfn{Localizzazione}
+significa fornire i dati necessari perch@'e un programma
+internazionalizzato sia in grado di funzionare con una data lingua.
+Questi termini si riferiscono comunemente a funzionalit@`a quali la lingua
+usata per stampare messaggi di errore, quella usata per leggere
+risposte, e alle informazioni
+relative al modo di leggere e di stampare dati di tipo numerico o valutario.
+
+@node Utilizzare @command{gettext}
+@section Il comando GNU @command{gettext}
+
+@cindex internazionalizzare un programma
+@cindex @command{gettext}, libreria
+@cindex libreria @command{gettext}
+@command{gawk} usa il comando GNU @command{gettext} per rendere disponibili
+le proprie funzionalit@`a di internazionalizzazione.
+L'attenzione del comando GNU @command{gettext} @`e rivolta principalmente
+ai messaggi: stringhe di caratteri stampate da un programma, sia
+direttamente sia usando la formattazione prevista dalle istruzioni
+@code{printf} o @code{sprintf()}.@footnote{Per alcuni sistemi operativi,
+la relativa versione di @command{gawk}
+non supporta il comando GNU @command{gettext}.
+Per questo motivo, queste funzionalit@`a non sono disponibili nel caso
+si stia lavorando con uno di questi sistemi operativi. Siamo spiacenti.}
+
+@cindex portabilit@`a, libreria @command{gettext} e
+Quando si usa il comando GNU @command{gettext}, ogni applicazione ha il
+proprio @dfn{dominio di testo}. Questo @`e un nome unico come,
+p.es., @samp{kpilot} o @samp{gawk},
+che identifica l'applicazione.
+Un'applicazione completa pu@`o avere pi@`u componenti: programmi scritti
+in C o C++, come pure script di @command{sh} o di @command{awk}.
+Tutti i componenti usano lo stesso dominio di testo.
+
+Per andare sul concreto, si supponga di scrivere un'applicazione
+chiamata @command{guide}. L'internazionalizzazione per quest'applicazione
+pu@`o essere implementata seguendo nell'ordine i passi qui delineati:
+
+@enumerate
+@item
+Il programmatore esamina i sorgenti di tutti i componenti dell'applicazione
+@command{guide} e prende nota di ogni stringa che potrebbe aver bisogno
+di traduzione.
+Per esempio, @code{"`-F': option required"} @`e una stringa che sicuramente
+necessita di una traduzione.
+Una tabella che contenga stringhe che sono nomi di opzioni @emph{non}
+necessita di traduzione.
+(P.es., l'opzione di @command{gawk} @option{--profile}
+dovrebbe restare immutata, a prescindere dalla lingua locale).
+
+@cindex @code{textdomain()}, funzione (libreria C)
+@cindex funzione @code{textdomain()} (libreria C)
+@item
+Il programmatore indica il dominio di testo dell'applicazione
+(@command{"guide"}) alla libreria @command{gettext},
+chiamando la funzione @code{textdomain()}.
+
+@cindex @code{.pot}, file
+@cindex file @code{.pot}
+@cindex @dfn{portable object template} (.pot), file
+@cindex file, @dfn{portable object template} (.pot)
+@item
+I messaggi dell'applicazione che vanno tradotti sono estratti dal codice
+sorgente e messi in un file di tipo
+@dfn{portable object template}
+[modello di oggetto portabile]
+di nome @file{guide.pot},
+che elenca le stringhe e le relative traduzioni.
+Le traduzioni sono inizialmente vuote
+(esiste la struttura che definisce la stringa tradotta, ma la stringa
+tradotta @`e una stringa nulla).
+Il messaggio originale (normalmente in inglese) @`e utilizzato come chiave
+di riferimento per le traduzioni.
+
+@cindex @code{.po}, file
+@cindex file @code{.po}
+@cindex @dfn{portable object} file (.po)
+@cindex file, @dfn{portable object} (.po)
+@item
+Per ogni lingua per cui sia disponibile un traduttore, il file
+@file{guide.pot} @`e copiato in un file di tipo
+@dfn{portable object}
+[oggetto portabile]
+(dal suffisso @code{.po})
+e le traduzioni sono effettuate su quel file,
+che viene distribuito con l'applicazione.
+Per esempio, potrebbe esserci un file @file{it.po} per la traduzione italiana.
+
+@cindex @code{.gmo}, file
+@cindex file @code{.gmo}
+@cindex @dfn{message object} file (.mo)
+@cindex file, @dfn{message object} (.mo)
+@item
+Il file @file{.po} di ogni lingua @`e convertito in un formato binario,
+detto @dfn{message object} (file @file{.gmo}).
+Un file di tipo @dfn{message object} contiene i messaggi originali e le loro
+traduzioni in un formato binario che facilita il ritrovamento delle
+traduzioni quando l'applicazione viene eseguita.
+
+@item
+Quando @command{guide} @`e compilato e installato, i file binari contenenti le
+traduzioni sono installati in una directory standard.
+
+@cindex @code{bindtextdomain()}, funzione (libreria C)
+@cindex funzione @code{bindtextdomain()} (libreria C)
+@item
+Durante la fase di prova e sviluppo, @`e possibile chiedere a @command{gettext}
+di usare un file @file{.gmo} in una directory diversa da quella standard,
+usando la funzione @code{bindtextdomain()}.
+
+@cindex @code{.gmo}, file, specificare la directory di
+@cindex file @code{.gmo}, specificare la directory di
+@cindex @dfn{message object} file (.mo), specificare la directory di
+@cindex file, @dfn{message object} (.mo), specificare la directory di
+@item
+Quando viene eseguito, il programma @command{awk} @command{guide} cerca ogni
+stringa da tradurre facendo una chiamata a @code{gettext()}. La stringa
+ricevuta in ritorno @`e la stringa tradotta, se @`e stata trovata, o la stringa
+originale, se una traduzione non @`e disponibile.
+
+@item
+Se necessario, @`e possibile procurarsi dei messaggi tradotti da un dominio di
+testo diverso da quello proprio dell'applicazione, senza dover altalenare fra
+questo secondo dominio e quello dell'applicazione.
+@end enumerate
+
+@cindex @code{gettext()}, funzione (libreria C)
+@cindex funzione @code{gettext()} (libreria C)
+In C (o C++), la marcatura della stringa la ricerca dinamica
+della traduzione si fanno inserendo ogni stringa da tradurre in una chiamata
+a @code{gettext()}:
+
+@example
+printf("%s", gettext("Don't Panic!\n"));
+@end example
+
+Gli strumenti software che estraggono messaggi dal codice sorgente
+individuano tutte le stringhe racchiuse nelle chiamate a @code{gettext()}.
+
+@cindex @code{_} (trattino basso), macro C
+@cindex trattino basso (@code{_}), macro C
+Gli sviluppatori del comando GNU @command{gettext}, riconoscendo che
+continuare a immettere @samp{gettext(@dots{})} @`e sia faticoso che poco
+elegante da vedere, usano la macro @samp{_} (un trattino basso) per
+facilitare la cosa:
+
+@example
+/* Nel file di intestazione standard: */
+#define _(str) gettext(str)
+
+/* Nel testo del programma: */
+printf("%s", _("Don't Panic!\n"));
+@end example
+
+@cindex internazionalizzazione, localizzazione, categorie di localizzazione
+@cindex @command{gettext}, libreria, categorie di localizzazione
+@cindex libreria @command{gettext}, categorie di localizzazione
+@cindex categorie di localizzazione
+@noindent
+Questo permette di ridurre la digitazione extra a solo tre caratteri per
+ogni stringa da tradurre e inoltre migliora di molto la leggibit@`a.
+
+Ci sono @dfn{categorie} di localizzazione per tipi diversi di informazioni
+legate a una particolare localizzazione.
+Le categorie di localizzazione note a @command{gettext} sono:
+
+@table @code
+@cindex @code{LC_MESSAGES}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_MESSAGES}
+@item LC_MESSAGES
+Testo dei messaggi. Questa @`e la categoria di default usata all'interno di
+@command{gettext}, ma @`e possibile specificarne esplicitamente una differente,
+se necessario. (Questo non @`e quasi mai necessario.)
+
+@cindex ordinare caratteri in lingue differenti
+@cindex @code{LC_COLLATE}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_COLLATE}
+@item LC_COLLATE
+Informazioni sull'ordinamento alfabetico (cio@`e, come caratteri diversi e/o
+gruppi di carattere sono ordinati in un dato linguaggio).
+@c ad esempio i vari caratteri accentati in italiano, vanno ordinati
+@c insieme alla loro lettera "principale" (e @`e @'e).
+
+@cindex @code{LC_CTYPE}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_CTYPE}
+@item LC_CTYPE
+Informazioni sui singoli caratteri (alfabetico, numerico, maiuscolo
+o minuscolo, etc.), come pure sulla codifica dei caratteri.
+@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
+Quest'informazione @`e utilizzata per stabilire le classi di caratteri come
+definite nello standard POSIX, nelle espressioni regolari,
+come p. es. @code{/[[:alnum:]]/}
+(@pxref{Espressioni tra parentesi quadre}).
+
+@cindex informazioni di tipo monetario, localizzazione
+@cindex monete, simboli di, nella localizzazione
+@cindex simboli di monete, nella localizzazione
+@cindex monete, rappresentazioni di, nella localizzazione
+@cindex rappresentazioni di monete, nella localizzazione
+@cindex @code{LC_MONETARY}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_MONETARY}
+@item LC_MONETARY
+Le informazioni di tipo monetario, quali il simbolo della moneta, e se
+il simbolo va prima o dopo il valore numerico.
+
+@cindex @code{LC_NUMERIC}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_NUMERIC}
+@item LC_NUMERIC
+Informazioni di tipo numerico, quali il carattere da usare per separare le
+cifre decimali e quello per separare le migliaia.@footnote{Gli americani usano
+una virgola ogni tre cifre decimali, e un punto per separare la parte decimale
+di un numero, mentre molti europei (fra cui gli italiani) fanno esattamente
+l'opposto: 1,234.56 invece che 1.234,56.}
+
+@cindex tempo, localizzazione e
+@cindex date, informazioni relative alla localizzazione
+@cindex @code{LC_TIME}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_TIME}
+@item LC_TIME
+Informazioni relative alle date e alle ore,
+come l'uso di ore nel formato a 12 ore oppure a 24 ore, il mese stampato
+prima o dopo il giorno in una data, le abbreviazioni dei mesi nella lingua
+locale, e cos@`{@dotless{i}} via.
+
+@cindex @code{LC_ALL}, categoria di localizzazione
+@cindex categoria di localizzazione @code{LC_ALL}
+@item LC_ALL
+Tutte le categorie viste sopra. (Non molto utile nel contesto del comando
+@command{gettext}.)
+@end table
+
+@quotation NOTA
+@cindex @env{LANGUAGE}, variabile d'ambiente
+@cindex variabile d'ambiente @env{LANGUAGE}
+Come descritto in @ref{Localizzazioni}, le variabili d'ambiente
+che hanno lo stesso nome delle categorie di localizzazione
+(@env{LC_CTYPE}, @env{LC_ALL}, etc.) influenzano il comportamento di
+@command{gawk} (e quello di altri programmi di utilit@`a).
+
+Solitamente, queste variabili influenzano anche il modo con cui
+la libreria @code{gettext} trova le traduzioni. Tuttavia, la
+variabile d'ambiente @env{LANGUAGE} prevale sulle variabili
+della famiglia @env{LC_@var{xxx}}. Molti sistemi GNU/Linux possono
+aver definito questa variabile senza esplicitamente notificarlo
+all'utente, e questo potrebbe far s@`{@dotless{i}} che @command{gawk} non riesca a
+trovare le traduzioni corrette. Se si incontra questa situazione,
+occorre controllare se la variabile d'ambiente @env{LANGUAGE} @`e
+definita, e, in questo caso, va usato il comando @command{unset}
+per rimuoverla.
+@end quotation
+
+Per il test di traduzioni dei messaggi inviati da @command{gawk} stesso, si pu@`o
+impostare la variabile d'ambiente @env{GAWK_LOCALE_DIR}. Si veda la
+documentazione per la funzione C @code{bindtextdomain()}, e si veda anche
+@ref{Altre variabili d'ambiente}.
+
+@node I18N per programmatore
+@section Internazionalizzare programmi @command{awk}
+@cindex programmi @command{awk}, internazionalizzare
+@cindex internazionalizzazione di programmi @command{awk}
+
+@command{gawk} prevede le seguenti variabili per l'internazionalizzazione:
+
+@table @code
+@cindex @code{TEXTDOMAIN}, variabile
+@cindex variabile @code{TEXTDOMAIN}
+@item TEXTDOMAIN
+Questa variabile indica il dominio di testo dell'applicazione.
+Per compatibilit@`a con il comando GNU @command{gettext}, il valore di default
+@`e @code{"messages"}.
+
+@cindex internazionalizzazione, localizzazione, stringhe marcate
+@cindex stringhe, marcare per localizzazione
+@item _"questo @`e un messaggio da tradurre"
+Costanti di tipo stringa marcate con un trattino basso iniziale
+sono candidate per essere tradotte al momento dell'esecuzione del
+programma @command{gawk}.
+Costanti di tipo stringa non precedute da un trattino basso non
+verranno tradotte.
+@end table
+
+@command{gawk} fornisce le seguenti funzioni al servizio
+dell'internazionalizzazione:
+
+@table @code
+@cindexgawkfunc{dcgettext}
+@item @code{dcgettext(@var{string}} [@code{,} @var{dominio} [@code{,} @var{categoria}]]@code{)}
+Restituisce la traduzione di @var{stringa} nel
+dominio di testo @var{dominio} per la categoria di localizzazione @var{categoria}.
+Il valore di default per @var{dominio} @`e il valore corrente di @code{TEXTDOMAIN}.
+Il valore di default per @var{categoria} @`e @code{"LC_MESSAGES"}.
+
+Se si assegna un valore a @var{categoria}, dev'essere una stringa uguale a
+una delle categorie di localizzazione note, descritte
+@ifnotinfo
+nella precedente @value{SECTION}.
+@end ifnotinfo
+@ifinfo
+@ref{Utilizzare @command{gettext}}.
+@end ifinfo
+Si deve anche specificare un dominio di testo. Si usi @code{TEXTDOMAIN} se
+si desidera usare il dominio corrente.
+
+@quotation ATTENZIONE
+L'ordine degli argomenti per la versione @command{awk}
+della funzione @code{dcgettext()} @`e differente, per una scelta di progetto,
+dall'ordine degli argomenti passati alla funzione C che ha lo stesso nome.
+L'ordine della versione @command{awk} @`e stato scelto per amore di
+semplicit@`a e per consentire di avere dei valori di default per gli
+argomenti che fossero il pi@`u possibile simili, come stile, a quello di
+@command{awk}.
+@end quotation
+
+@cindexgawkfunc{dcngettext}
+@item @code{dcngettext(@var{stringa1}, @var{stringa2}, @var{numero}} [@code{,} @var{dominio} [@code{,} @var{categoria}]]@code{)}
+Restituisce la forma, singolare o plurale, da usare a seconda del valore
+di @var{numero} per la
+traduzione di @var{stringa1} e @var{stringa2} nel dominio di testo
+@var{dominio} per la categoria di localizzazione @var{categoria}.
+@var{stringa1} @`e la variante al singolare in inglese di un messaggio,
+e @var{stringa2} @`e la variante al plurale in inglese dello stesso messaggio.
+Il valore di default per @var{dominio} @`e il valore corrente di @code{TEXTDOMAIN}.
+Il valore di default per @var{categoria} @`e @code{"LC_MESSAGES"}.
+
+Valgono le stesse osservazioni riguardo all'ordine degli argomenti
+fatte a proposito della funzione @code{dcgettext()}.
+
+@cindex @code{.gmo}, file, specificare la directory di
+@cindex file @code{.gmo}, specificare la directory di
+@cindex @dfn{message object} file (.mo), specificare la directory di
+@cindex file, @dfn{message object} (.mo), specificare la directory di
+@cindexgawkfunc{bindtextdomain}
+@item @code{bindtextdomain(@var{directory}} [@code{,} @var{dominio} ]@code{)}
+Cambia la directory nella quale
+@command{gettext} va a cercare i file @file{.gmo}, per il caso in cui questi
+non possano risiedere nelle posizioni standard
+(p.es., in fase di test).
+Restituisce la directory alla quale @var{dominio} @`e ``collegato''.
+
+Il @var{dominio} di default @`e il valore di @code{TEXTDOMAIN}.
+Se l'argomento @var{directory} @`e impostato alla stringa nulla (@code{""}),
+@code{bindtextdomain()} restituisce il collegamento corrente applicabile
+al @var{dominio} specificato.
+@end table
+
+Per usare queste funzionalit@`a in un programma @command{awk},
+va seguita la procedura qui indicata:
+
+@enumerate
+@cindex @code{BEGIN}, criterio di ricerca, variabile @code{TEXTDOMAIN} e
+@cindex criterio di ricerca @code{BEGIN}, variabile @code{TEXTDOMAIN} e
+@cindex @code{TEXTDOMAIN}, variabile, criterio di ricerca @code{BEGIN} e
+@cindex variabile @code{TEXTDOMAIN}, criterio di ricerca @code{BEGIN} e
+@item
+Impostare la variabile @code{TEXTDOMAIN} al dominio di testo del
+programma. @`E meglio fare ci@`o all'interno di una regola @code{BEGIN}
+(@pxref{BEGIN/END}),
+ma si pu@`o anche fare dalla riga di comando, usando l'opzione @option{-v}
+(@pxref{Opzioni}):
+
+@example
+BEGIN @{
+ TEXTDOMAIN = "guide"
+ @dots{}
+@}
+@end example
+
+@cindex @code{_} (trattino basso), stringa traducibile
+@cindex trattino basso (@code{_}), stringa traducibile
+@item
+Marcare tutte le stringhe traducibili anteponendo loro un
+trattino basso (@samp{_}). Il trattino @emph{deve} essere adiacente ai
+doppi apici di apertura della stringa. Per esempio:
+
+@example
+print _"hello, world"
+x = _"you goofed"
+printf(_"Number of users is %d\n", nusers)
+@end example
+
+@item
+Se le stringhe da visualizzare sono create dinamicamente, @`e ancora possibile
+tradurle, usando la funzione predefinita @code{dcgettext()}:@footnote{I miei
+ringraziamenti a Bruno Haible per questo esempio.}
+
+@example
+if (assonnato)
+ messaggio = dcgettext("%d clienti mi scocciano\n", "adminprog")
+else
+ messaggio = dcgettext("mi diverto con %d clienti\n", "adminprog")
+printf(messaggio, numero_clienti)
+@end example
+
+In questo esempio, la chiamata a @code{dcgettext()} specifica un diverso
+dominio di testo (@code{"adminprog"}) in cui trovare il
+messaggio, ma usa la categoria di default @code{"LC_MESSAGES"}.
+
+Il precedente esempio funziona solo se @code{numero_clienti} @`e un numero maggiore
+di uno.
+Per questo esempio sarebbe pi@`u appropriato usare la funzione @code{dcngettext()}:
+
+@example
+if (assonnato)
+ messaggio = dcngettext("%d cliente mi scoccia\n",
+ "%d clienti mi scocciano\n",
+ numero_clienti, "adminprog")
+else
+ messaggio = dcngettext("mi diverto con %d cliente\n",
+ "mi diverto con %d clienti\n",
+ numero_clienti, "adminprog")
+printf(messaggio, numero_clienti)
+@end example
+
+
+@cindex @code{LC_MESSAGES}, categoria di localizzazione, funzione @code{bindtextdomain()} di (@command{gawk})
+@item
+In fase di sviluppo, si pu@`o scegliere di tenere il file @file{.gmo}
+in una directory a parte, solo per provarlo. Ci@`o si fa
+con la funzione predefinita @code{bindtextdomain()}:
+
+@example
+BEGIN @{
+ TEXTDOMAIN = "guide" # dominio di testo regolare
+ if (Testing) @{
+ # dove trovare il file in prova
+ bindtextdomain("testdir")
+ # joe si occupa del programma adminprog
+ bindtextdomain("../joe/testdir", "adminprog")
+ @}
+ @dots{}
+@}
+@end example
+
+@end enumerate
+
+@xref{Esempio I18N}
+per un programma di esempio che illustra i passi da seguire per creare
+e usare traduzioni nei programmi @command{awk}.
+
+@node I18N per traduttore
+@section Traduzione dei programmi @command{awk}
+
+@cindex @code{.po}, file
+@cindex file @code{.po}
+@cindex @dfn{portable object} file (.po)
+@cindex file, @dfn{portable object} (.po)
+Dopo aver marcato le stringhe che si desidera tradurre in un programma,
+queste vanno estratte per creare il file iniziale @file{.pot}.
+Durante la traduzione, @`e spesso utile modificare l'ordine nel quale
+gli argomenti passati a @code{printf} vengono stampati.
+
+L'opzione da riga di comando @option{--gen-pot} di @command{gawk} serve a
+estrarre i messaggi, ed @`e esposta qui di seguito.
+Dopo di che, verr@`a illustrata la possibilit@`a di modificare l'ordine
+in cui l'istruzione @code{printf} stampa gli argomenti che le sono passati
+in fase di esecuzione.
+
+@menu
+* Estrazione di stringhe:: Estrarre stringhe marcate.
+* Ordinamento di printf:: Riordinare argomenti @code{printf}
+* Portabilit@`a nell'I18N:: Problemi di portabilit@`a a livello di @command{awk}.
+@end menu
+
+@node Estrazione di stringhe
+@subsection Estrarre stringhe marcate
+@cindex stringhe, estrazione di
+@cindex stringhe marcate, estrazione di
+@cindex @option{--gen-pot}, opzione
+@cindex opzione @option{--gen-pot}
+@cindex opzioni sulla riga di comando, estrazione stringhe
+@cindex riga di comando, opzioni, estrazione stringhe
+@cindex stringhe marcate, estrazione di (internazionalizzazione)
+@cindex marcate, estrazione di stringhe (internazionalizzazione)
+@cindex estrazione di stringhe marcate (internazionalizzazione)
+
+@cindex @option{--gen-pot}, opzione
+@cindex opzione @option{--gen-pot}
+Una volta che il programma @command{awk} funziona, e tutte le stringhe
+sono state marcate ed @`e stato impostato (e forse fissato) il dominio di
+testo, @`e ora di preparare le traduzioni.
+Per prima cosa, usando l'opzione di riga di comando @option{--gen-pot},
+si crea il file iniziale @file{.pot}:
+
+@example
+gawk --gen-pot -f guide.awk > guide.pot
+@end example
+
+@cindex @code{xgettext}, programma di utilit@`a
+@cindex programma di utilit@`a @code{xgettext}
+Quando viene chiamato specificando @option{--gen-pot}, @command{gawk} non
+esegue il programma. Il programma viene esaminato come al solito, e tutte
+le stringhe che sono state marcate per essere tradotte vengono scritte nello
+standard output, nel formato di un file Portable Object di GNU
+@command{gettext}.
+L'output comprende anche quelle stringhe costanti che appaiono come primo
+argomento della funzione @code{dcgettext()} o come primo e secondo
+argomento della funzione @code{dcngettext()}.@footnote{Il comando di utilit@`a
+@command{xgettext} che fa parte del pacchetto distribuito come
+@command{gettext} @`e in grado di gestire i file di tipo @file{.awk}.}
+Il file @file{.pot} cos@`{@dotless{i}} generato
+andrebbe distribuito insieme al programma @command{awk}; i traduttori
+potranno eventualmente utilizzarlo per preparare delle traduzioni, le quali
+potranno a loro volta essere distribuite.
+@xref{Esempio I18N}
+per una lista esauriente dei passi necessari per creare e testare
+traduzioni per il programma @command{guide}.
+
+@node Ordinamento di printf
+@subsection Riordinare argomenti di @code{printf}
+
+@cindex @code{printf}, istruzione, specificatori di posizione
+@cindex istruzione @code{printf}, specificatori posizionali
+@cindex posizionali, specificatori, istruzione @code{printf}
+@cindex specificatori posizionali, istruzione @code{printf}
+Le stringhe di formattazione per @code{printf} e @code{sprintf()}
+(@pxref{Printf})
+hanno un problema speciale con le traduzioni.
+Si consideri il seguente esempio:@footnote{Questo esempio @`e preso in
+prestito dal manuale del comando GNU @command{gettext}.}
+
+@example
+printf(_"String `%s' has %d characters\n",
+ string, length(string)))
+@end example
+
+Una possibile traduzione in italiano di questo messaggio potrebbe essere:
+
+@example
+"%d @`e la lunghezza della stringa `%s'\n"
+@end example
+
+Il problema dovrebbe essere ovvio: l'ordine delle specifiche di
+formattazione @`e differente da quello originale!
+@code{gettext()}, che pure pu@`o restituire la stringa tradotta
+in fase di esecuzione, non @`e in grado di cambiare l'ordine degli argomenti
+nella chiamata a @code{printf}.
+
+Per risolvere questo problema, gli specificatori di formato di @code{printf}
+possono avere un elemento in pi@`u, facoltativo, detto @dfn{specificatore
+posizionale}. Per esempio:
+
+@example
+"%2$d @`e la lunghezza della stringa `%1$s'\n"
+@end example
+
+Qui, lo specificatore posizionale consiste in un numero intero, che indica
+quale argomento utilizzare, seguito da un carattere @samp{$}.
+I numeri partono da uno, e la stringa di formattazione vera e propria
+@emph{non} @`e inclusa. Quindi, nell'esempio seguente, @samp{stringa} @`e
+il primo argomento e @samp{length(stringa)} @`e il secondo:
+
+@example
+$ @kbd{gawk 'BEGIN @{}
+> @kbd{stringa = "Non v\47allarmate!"}
+> @kbd{printf "%2$d caratteri compongono \"%1$s\"\n",}
+> @kbd{stringa, length(stringa)}
+> @kbd{@}'}
+@print{} 16 caratteri compongono "Non v\47allarmate!"
+@end example
+
+Se presenti, gli specificatori posizionali precedono, nella specifica di
+formato, i flag, la larghezza del campo e/o la precisione.
+
+Gli specificatori posizionali possono essere usati anche se si specifica una
+larghezza dinamica dei campi, e della capacit@`a di precisione:
+
+@example
+$ @kbd{gawk 'BEGIN @{}
+> @kbd{printf("%*.*s\n", 10, 20, "hello")}
+> @kbd{printf("%3$*2$.*1$s\n", 20, 10, "hello")}
+> @kbd{@}'}
+@print{} hello
+@print{} hello
+@end example
+
+@quotation NOTA
+Se si usa @samp{*} con uno specificatore posizionale, il carattere @samp{*}
+viene per primo, seguito dal numero che indica la posizione, a sua volta
+seguito dal @samp{$}.
+Ci@`o pu@`o parere poco intuitivo.
+@end quotation
+
+@cindex istruzione @code{printf}, specificatori posizionali, frammisti a formati standard
+@cindex @code{printf}, istruzione, specificatori posizionali, frammisti a formati standard
+@cindex specificatori posizionali, istruzione @code{printf}, frammisti a formati standard
+@cindex formato, specificatori di, frammisti a specificatori posizionali non standard
+@cindex specificatori di formato, frammisti a specificatori posizionali non standard
+@command{gawk} non consente di mischiare specificatori di formato standard
+con altri contenenti degli specificatori posizionali in una stessa stringa di
+formato:
+
+@example
+$ @kbd{gawk 'BEGIN @{ printf "%d %3$s\n", 1, 2, "ciao" @}'}
+@error{} gawk: riga com.:1: fatale: `count$' va usato per tutti
+@error{} i formati o per nessuno
+@end example
+
+@quotation NOTA
+Ci sono alcuni casi patologici in cui @command{gawk} potrebbe non inviare
+alcun messaggio diagnostico, anche quando sarebbe necessario.
+In tali casi, l'output pu@`o non essere quello atteso.
+Rimane sempre una pessima idea quella di tentare di mischiare i formati,
+anche se @command{gawk} non riesce ad accorgersene.
+@end quotation
+
+Sebbene gli specificatori posizionali possano essere usati direttamente nei
+programmi @command{awk}, il motivo per cui sono stati introdotti @`e perch@'e
+siano d'aiuto nel produrre traduzioni corrette della stringa di
+formattazione in lingue differenti da quella nella quale il programma @`e stato
+originariamente scritto.
+
+@node Portabilit@`a nell'I18N
+@subsection Problemi di portabilit@`a a livello di @command{awk}
+
+@cindex portabilit@`a, internazionalizzazione e
+@cindex internazionalizzazione, localizzazione, portabilit@`a e
+Le funzionalit@`a di internazionalizzazione di @command{gawk} sono state
+appositamente implementate per avere il minimo impatto possibile sulla
+portabilit@`a, verso altre versioni di @command{awk}, dei programmi
+@command{awk} che ne fanno uso.
+Si consideri questo programma:
+
+@example
+BEGIN @{
+ TEXTDOMAIN = "guide"
+ if (Test_Guide) # da impostare tramite -v
+ bindtextdomain("/test/guide/messages")
+ print _"don't panic!"
+@}
+@end example
+
+@noindent
+Per il modo in cui @`e scritto, non funzioner@`a con altre versioni di
+@command{awk}.
+Tuttavia, @`e in realt@`a quasi portabile, e richiede modifiche minime:
+
+@itemize @value{BULLET}
+@cindex @code{TEXTDOMAIN}, variabile, portabilit@`a e
+@cindex variabile @code{TEXTDOMAIN}, portabilit@`a e
+@item
+Le assegnazioni di valori a @code{TEXTDOMAIN} non avranno effetto alcuno,
+perch@'e @code{TEXTDOMAIN} non @`e una variabile speciale in altre
+implementazioni di @command{awk}.
+
+@item
+Versioni Non-GNU di @command{awk} considerano le stringhe marcate
+come la concatenazione di una variabile di nome @code{_} con la stringa che
+viene subito dopo.@footnote{Questo @`e
+un buon materiale per una gara di ``Oscurit@`a @command{awk}''.}
+Tipicamente, la variabile @code{_} ha come valore la stringa nulla
+(@code{""}), il che produce come risultato la stringa
+originale.
+
+@item
+Definendo delle funzioni ``fittizie'' per sostituire @code{dcgettext()},
+@code{dcngettext()} e @code{bindtextdomain()}, il programma @command{awk}
+pu@`o essere reso eseguibile, ma
+tutti i messaggi verranno inviati nella lingua originale del programma.
+Per esempio:
+
+@cindex @code{bindtextdomain()}, funzione (@command{gawk}), portabilit@`a e
+@cindex funzione @code{bindtextdomain()} (@command{gawk}), portabilit@`a e
+@cindex @code{dcgettext()}, funzione (@command{gawk}), portabilit@`a e
+@cindex funzione @code{dcgettext()} (@command{gawk}), portabilit@`a e
+@cindex @code{dcngettext()}, funzione (@command{gawk}), portabilit@`a e
+@cindex funzione @code{dcngettext()} (@command{gawk}), portabilit@`a e
+@example
+@c file eg/lib/libintl.awk
+function bindtextdomain(dir, domain)
+@{
+ return dir
+@}
+
+function dcgettext(string, domain, category)
+@{
+ return string
+@}
+
+function dcngettext(string1, string2, number, domain, category)
+@{
+ return (number == 1 ? string1 : string2)
+@}
+@c endfile
+@end example
+
+@item
+L'uso di specificazioni posizionali in @code{printf} o
+@code{sprintf()} @emph{non} @`e portabile.
+Per supportare @code{gettext()} nella programmazione in linguaggio C,
+molte versioni C di @code{sprintf()} supportano specificatori posizionali.
+Ma la cosa funziona solo se nella chiamata di funzione sono stati specificati
+argomenti a sufficienza. Molte
+versioni di @command{awk} passano i formati e gli argomenti di @code{printf},
+senza modificarli, alla funzione di libreria in linguaggio C @code{sprintf()},
+ma solo un formato e un argomento alla volta. Quel che succede se si usa una
+specificazione posizionale resta indeterminato.
+Tuttavia, poich@'e le specificazioni posizionali sono usate principalmente
+per le stringhe di formattazione @emph{tradotte}, e poich@'e le versioni
+non-GNU di @command{awk} non utilizzano mai le stringhe tradotte, ci@`o non
+dovrebbe, in pratica, causare problemi.
+@end itemize
+
+@node Esempio I18N
+@section Un semplice esempio di internazionalizzazione.
+
+Vediamo ora un esempio dettagliato di come internazionalizzare e localizzare
+un semplice programma @command{awk}, usando come nostro programma sorgente
+originale il file @file{guide.awk}:
+
+@example
+@c file eg/prog/guide.awk
+BEGIN @{
+ TEXTDOMAIN = "guide"
+ bindtextdomain(".") # per la fase di test
+ print _"Don't Panic"
+ print _"The Answer Is", 42
+ print "Pardon me, Zaphod who?"
+@}
+@c endfile
+@end example
+
+@noindent
+Eseguire @samp{gawk --gen-pot} per creare il file @file{.pot}:
+
+@example
+$ @kbd{gawk --gen-pot -f guide.awk > guide.pot}
+@end example
+
+@noindent
+Questo produce:
+
+@example
+@c file eg/data/guide.po
+#: guide.awk:4
+msgid "Don't Panic"
+msgstr ""
+
+#: guide.awk:5
+msgid "The Answer Is"
+msgstr ""
+
+@c endfile
+@end example
+
+Questo modello di @dfn{portable object} va salvato e riutilizzato per ogni
+lingua in cui l'applicazione viene tradotta. La stringa @code{msgid} @`e
+seguita dalla stringa originale da tradurre, e la stringa @code{msgstr}
+conterr@`a la traduzione.
+
+@quotation NOTA
+Le stringhe non aventi come prefisso un trattino basso non sono inserite
+nel file @file{guide.pot}.
+@end quotation
+
+Successivamente, i messaggi devono essere tradotti.
+Questa @`e una traduzione in un ipotetico dialetto dell'inglese,
+chiamato ``Mellow'':@footnote{Forse sarebbe meglio chiamarlo
+``Hippy.'' Meglio non indagare oltre.}
+
+@example
+@group
+$ @kbd{cp guide.pot guide-mellow.po}
+@var{Aggiungere traduzioni al file} guide-mellow.po @dots{}
+@end group
+@end example
+
+@noindent
+Ecco le traduzioni:
+
+@example
+@c file eg/data/guide-mellow.po
+#: guide.awk:4
+msgid "Don't Panic"
+msgstr "Hey man, relax!"
+
+#: guide.awk:5
+msgid "The Answer Is"
+msgstr "Like, the scoop is"
+
+@c endfile
+@end example
+
+@cindex Linux
+@cindex GNU/Linux
+Il passo successivo @`e di creare la directory che contenga il file binario
+con le traduzioni dei messaggi (file .mo [message object]) e
+creare in quella directory il file @file{guide.mo}.
+Si presume che il file in questione debba essere usato nella localizzazione
+@code{en_US.UTF-8}, perch@'e si deve usare un nome di localizzazione che sia
+noto alle routine del comando C @command{gettext}.
+La disposizione delle directory qui utilizzata @`e standard per il comando
+GNU @command{gettext} sui sistemi GNU/Linux. Altre versioni di
+@command{gettext} possono usare una disposizione differente:
+
+@example
+$ @kbd{mkdir en_US.UTF-8 en_US.UTF-8/LC_MESSAGES}
+@end example
+
+@cindex @code{.po}, file, conversione in @code{.mo}
+@cindex file @code{.po}, conversione in @code{.mo}
+@cindex @code{.mo}, file, conversione da @code{.po}
+@cindex file @code{.mo}, conversione da @code{.po}
+@cindex @dfn{portable object} file (.po), conversione in @dfn{message object} file
+@cindex file, @dfn{portable object} (.po), conversione in @dfn{message object} file
+@cindex @dfn{message object} file (.mo), conversione da @dfn{portable object} file
+@cindex file, @dfn{message object} (.mo), conversione da @dfn{portable object} file
+@cindex @command{msgfmt}, programma di utilit@`a
+@cindex programma di utilit@`a @command{msgfmt}
+Il programma di utilit@`a @command{msgfmt} effettua la conversione dal file
+leggibile, in formato testo, @file{.po} nel file, in formato binario,
+@file{.mo}.
+Per default, @command{msgfmt} crea un file di nome @file{messages}.
+A questo file dev'essere assegnato un nome appropriato, e va messo nella
+directory predisposta (usando l'opzione @option{-o}) in modo che
+@command{gawk} sia in grado di trovarlo:
+
+@example
+$ @kbd{msgfmt guide-mellow.po -o en_US.UTF-8/LC_MESSAGES/guide.mo}
+@end example
+
+Infine, eseguiamo il programma per provare se funziona:
+
+@example
+$ @kbd{gawk -f guide.awk}
+@print{} Hey man, relax!
+@print{} Like, the scoop is 42
+@print{} Pardon me, Zaphod who?
+@end example
+
+Se le tre funzioni che rimpiazzano @code{dcgettext()}, @code{dcngettext()},
+e @code{bindtextdomain()}
+(@pxref{Portabilit@`a nell'I18N})
+sono contenute in un file di nome @file{libintl.awk},
+@`e possibile eseguire @file{guide.awk} senza modificarlo, nel modo seguente:
+
+@example
+$ @kbd{gawk --posix -f guide.awk -f libintl.awk}
+@print{} Don't Panic
+@print{} The Answer Is 42
+@print{} Pardon me, Zaphod who?
+@end example
+
+@node Gawk internazionalizzato
+@section @command{gawk} stesso @`e internazionalizzato
+
+Il comando @command{gawk} stesso @`e stato internazionalizzato
+usando il pacchetto GNU @command{gettext}.
+(GNU @command{gettext} @`e descritto in
+maniera esauriente in
+@ifinfo
+@inforef{Top, , GNU @command{gettext} utilities, gettext, GNU @command{gettext} utilities}.)
+@end ifinfo
+@ifnotinfo
+@uref{http://www.gnu.org/software/gettext/manual/,
+@cite{GNU @command{gettext} utilities}}.)
+@end ifnotinfo
+Al momento in cui questo libro @`e stato scritto, la versione pi@`u recente di
+GNU @command{gettext} @`e
+@uref{ftp://ftp.gnu.org/gnu/gettext/gettext-0.19.4.tar.gz,
+@value{PVERSION} 0.19.4}.
+
+Se esiste una traduzione dei messaggi di @command{gawk},
+@command{gawk} invia messaggi, avvertimenti, ed errori fatali
+utilizzando la lingua locale.
+
+@node Sommario I18N
+@section Sommario
+@itemize @value{BULLET}
+@item
+Internazionalizzazione significa scrivere un programma in modo che
+possa interagire in molte lingue senza che sia necessario cambiare il codice
+sorgente.
+Localizzazione significa fornire i dati necessari perch@'e un programma
+internazionalizzato possa interagire usando una determinata lingua.
+
+@item
+@command{gawk} usa il comando GNU @command{gettext} per consentire
+l'internazionalizzazione e la localizzazione di programmi @command{awk}.
+Un dominio di testo di un programma identifica il programma, e consente di
+raggruppare tutti i messaggi e gli altri dati del programma in un solo posto.
+
+@item
+Si marcano le stringhe in un programma da tradurre preponendo loro un
+trattino basso. Una volta fatto questo, queste stringhe sono estratte
+in un file @file{.pot}. Questo file @`e copiato, per ogni lingua, in un file
+@file{.po} e i file @file{.po} sono
+compilati in file @file{.gmo} che saranno usati in fase di
+esecuzione del programma.
+
+@item
+@`E possibile usare specificazioni posizionali con le istruzioni
+@code{sprintf()} e @code{printf} per modificare la posizione del valore
+degli argomenti nelle stringhe di formato e nell'output. Ci@`o @`e utile nella
+traduzione di stringhe di
+formattazione dei messaggi.
+
+@item
+Le funzionalit@`a di internazionalizzazione sono state progettate in modo
+da poter essere facilmente gestite in un programma @command{awk} standard.
+
+@item
+Anche il comando @command{gawk} @`e stato internazionalizzato e viene
+distribuito con traduzioni in molte lingue dei messaggi inviati in fase di
+esecuzione.
+
+@end itemize
+
+
+@node Debugger
+@chapter Effettuare il debug dei programmi @command{awk}
+@cindex debug dei programmi @command{awk}
+
+@c The original text for this chapter was contributed by Efraim Yawitz.
+@c FIXME: Add more indexing.
+
+Sarebbe bello se i programmi per il calcolatore funzionassero perfettamente la
+prima volta che vengono eseguiti, ma nella vita reale questo accade raramente,
+qualunque sia la complessit@`a dei programmi. Perci@`o la maggior parte dei
+linguaggi di programmazione hanno a disposizione degli strumenti che facilitano
+la ricerca di errori (@dfn{debugging}) nei programmi, e @command{awk} non fa
+eccezione.
+
+Il @dfn{debugger} di @command{gawk} @`e di proposito costruito sul modello del
+debugger da riga di comando
+@uref{http://www.gnu.org/software/gdb/, GNU Debugger (GDB)}.
+Se si ha familiarit@`a con GDB, sar@`a facile imparare come usare @command{gawk}
+per eseguire il debug dei propri programmi.
+
+@menu
+* Debugging:: Introduzione al debugger di @command{gawk}.
+* Esempio di sessione di debug:: Esempio di sessione di debug.
+* Lista dei comandi di debug:: Principali comandi di debug.
+* Supporto per Readline:: Supporto per Readline.
+* Limitazioni:: Limitazioni e piani per il futuro.
+* Sommario sul debug:: Sommario sul debug.
+@end menu
+
+@node Debugging
+@section Introduzione al debugger di @command{gawk}
+
+Questa @value{SECTION}, dopo un'introduzione sul debug in generale, inizia
+la trattazione del debug in @command{gawk}.
+
+@menu
+* Nozioni sul debug:: Generalit@`a sul debug.
+* Terminologia nel debug:: Ulteriori nozioni sul debug.
+* Debug di Awk:: Eseguire il debug di Awk.
+@end menu
+
+@node Nozioni sul debug
+@subsection Generalit@`a sul debug
+
+(Se si sono usati dei debugger in altri linguaggi, si pu@`o andare direttamente
+alla @ref{Debug di Awk}.)
+
+Naturalmente, un programma di debug non pu@`o correggere gli errori al posto del
+programmatore, perch@'e non pu@`o sapere quello che il programmatore o gli utenti
+considerano un ``bug'' e non una ``funzionalit@`a''. (Talvolta, anche noi umani
+abbiamo difficolt@`a nel determinarlo.)
+In quel caso, cosa ci si pu@`o aspettare da un tale strumento? La risposta
+dipende dal linguaggio su cui si effettua il debug, comunque in generale ci si
+pu@`o attendere almeno questo:
+
+@itemize @value{BULLET}
+@item
+La possibilit@`a di osservare l'esecuzione delle istruzioni di un programma una
+per una, dando al programmatore l'opportunit@`a di pensare a quel che accade a
+una scala temporale di secondi, minuti od ore, piuttosto che alla scala dei
+nanosecondi alla quale normalmente viene eseguito il codice.
+
+@item
+L'opportunit@`a, non solo di osservare passivamente le operazioni del progamma,
+ma di controllarlo e tentare diversi percorsi di esecuzione, senza dover
+modificare i file sorgenti.
+
+@item
+La possibilit@`a di vedere i valori o i dati nel programma in qualsiasi punto
+dell'esecuzione, e anche di cambiare i dati al volo, per vedere come questo
+influisca su ci@`o che accade dopo. (Questo include spesso la capacit@`a di
+esaminare le strutture interne dei dati oltre alle variabili che
+sono state effettivamente definite nel codice del programma.)
+
+@item
+La possibilit@`a di ottenere ulteriori informazioni sullo stato del programma
+o anche sulle sue strutture interne.
+@end itemize
+
+Tutti questi strumenti sono di grande aiuto e permettono di usare l'abilit@`a
+che si possiede e la comprensione che si ha degli obiettivi del programma
+per trovare dove si verificano i problemi (o, in alternativa, per
+comprendere meglio la logica di un programma funzionante, di cui si sia
+l'autore, o anche di un programma scritto da altri).
+
+@node Terminologia nel debug
+@subsection Concetti fondamentali sul debug
+
+Prima di entrare nei dettagli, dobbiamo introdurre diversi
+importanti concetti che valgono per tutti i debugger.
+La seguente lista definisce i termini usati nel resto di
+questo @value{CHAPTER}:
+
+@table @dfn
+@cindex @dfn{stack frame}
+@item Stack frame
+Durante la loro esecuzione i programmi normalmente chiamano delle funzioni.
+Una funzione pu@`o a sua volta chiamarne un'altra, o pu@`o richiamare se stessa
+(ricorsione). La
+catena di funzioni chiamate (il programma principale chiama A, che chiama B,
+che chiama C) pu@`o essere vista come una pila di funzioni in esecuzione: la
+funzione correntemente in esecuzione @`e quella in cima alla pila, e quando
+questa finisce (ritorna al chiamante),
+quella immediatamente sotto diventa la funzione
+attiva. Tale pila (@dfn{stack}) @`e chiamata @dfn{call stack} (pila delle chiamate).
+
+Per ciascuna funzione della pila delle chiamate (@dfn{call stack}), il sistema
+mantiene un'area di dati che contiene i parametri della funzione, le variabili
+locali e i valori di ritorno, e anche ogni altra informazione ``contabile''
+necessaria per gestire la pila delle chiamate. Quest'area di dati @`e chiamata
+@dfn{stack frame}.
+
+Anche @command{gawk} segue questo modello, e permette l'accesso alla pila
+delle chiamate e a ogni @dfn{stack frame}. @`E possibile esaminare la pila
+delle chiamate, e anche sapere da dove ciascuna funzione sulla pila @`e stata
+invocata. I comandi che stampano la pila delle chiamate stampano anche le
+informazioni su ogni @dfn{stack frame} (come vedremo pi@`u avanti in dettaglio).
+
+@item Punto d'interruzione
+@cindex breakpoint
+@cindex punto d'interruzione
+Durante le operazioni di debug, spesso si preferisce lasciare che il programma
+venga eseguito finch@'e non raggiunge un certo punto, e da quel punto in poi si
+continua l'esecuzione un'istruzione alla volta. Il modo per farlo @`e quello di
+impostare un @dfn{punto d'interruzione} all'interno del programma. Un punto
+d'interruzione @`e il punto dove l'esecuzione del programma dovrebbe
+interrompersi (fermarsi), in modo da assumere il controllo dell'esecuzione del
+programma. Si possono aggiungere e togliere quanti punti d'interruzione si
+vogliono.
+
+@item Punto d'osservazione
+@cindex @dfn{watchpoint}
+@cindex punto d'osservazione
+Un punto d'osservazione @`e simile a un punto d'interruzione. La differenza @`e
+che i punti d'interruzione sono orientati attorno al codice; fermano il
+programma quando viene raggiunto un certo punto nel codice. Un punto
+d'osservazione, invece, fa fermare il programma quando @`e stato
+cambiato il @emph{valore di un dato}. Questo @`e utile, poich@'e a volte succede
+che una variabile riceva un valore errato, ed @`e difficile rintracciare il punto
+dove ci@`o accade solo leggendo il codice sorgente.
+Usando un punto d'osservazione, si pu@`o fermare il programma in qualunque punto
+vi sia un'assegnazione di variabile, e di solito si individua il codice che
+genera l'errore abbastanza velocemente.
+@end table
+
+@node Debug di Awk
+@subsection Il debug di @command{awk}
+
+Il debug di un programma @command{awk} ha delle particolarit@`a proprie, che
+non sono presenti in programmi scritti in altri linguaggi.
+
+Prima di tutto, il fatto che i programmi @command{awk} ricevano generalmente
+l'input riga per riga da uno o pi@`u file e operino su tali righe usando regole
+specifiche, rende particolarmente agevole organizzare l'esame
+dell'esecuzione del programma facendo riferimento a tali regole.
+Come vedremo, ogni
+regola @command{awk} viene trattata quasi come una chiamata di funzione, col
+proprio specifico blocco di istruzioni.
+
+Inoltre, poich@'e @command{awk} @`e un linguaggio deliberatamente molto
+conciso, @`e facile perdere di vista tutto ci@`o che avviene ``dentro''
+ogni riga di codice @command{awk}. Il debugger d@`a l'opportunit@`a di
+guardare le singole istruzioni primitive la cui esecuzione @`e innescata
+dai comandi di alto livello di @command{awk}.
+
+@node Esempio di sessione di debug
+@section Esempio di sessione di debug di @command{gawk}
+@cindex esempio di sessione di debug
+@cindex debug, esempio di sessione
+
+Per illustrare l'uso di @command{gawk} come debugger, vediamo un esempio di
+sessione di debug. Come esempio verr@`a usata l'implementazione @command{awk}
+del comando POSIX @command{uniq} descritta in precedenza (@pxref{Programma
+uniq}).
+
+@menu
+* Invocazione del debugger:: Come far partire il debugger.
+* Trovare il bug:: Trovare il bug.
+@end menu
+
+@node Invocazione del debugger
+@subsection Come avviare il debugger
+@cindex avviare il debugger
+@cindex debugger, come avviarlo
+@cindex debugger, comandi del, si veda comando del debugger
+
+Per avviare il debugger in @command{gawk} si richiama il comando esattamente
+come al solito, specificando solo un'opzione aggiuntiva,
+@option{--debug}, o la corrispondente opzione breve @option{-D}.
+I file (o il file) che contengono
+il programma e ogni codice ulteriore sono immessi sulla riga di comando come
+argomenti a una o pi@`u opzioni @option{-f}. (@command{gawk} non @`e progettato per
+eseguire il debug di programmi scritti sulla riga di comando, ma solo per
+quello di programmi che risiedono su file.)
+Nel nostro caso, il debugger verr@`a invocato in questo modo:
+
+@example
+$ @kbd{gawk -D -f getopt.awk -f join.awk -f uniq.awk -1 file_di_input}
+@end example
+
+@noindent
+dove entrambi i file @file{getopt.awk} e @file{uniq.awk} sono in @env{$AWKPATH}.
+(Gli utenti esperti di GDB o debugger simili dovrebbero tener presente che
+questa sintassi @`e leggermente differente da quello che sono abituati a usare.
+Col debugger di @command{gawk}, si danno gli argomenti per eseguire il
+programma nella riga di comando al debugger piuttosto che come parte del
+comando @code{run} al prompt del debugger.)
+L'opzione @option{-1} @`e un'opzione per @file{uniq.awk}.
+
+Invece di eseguire direttamente il programma sul @file{file_di_input}, come
+@command{gawk} farebbe normalmente, il debugger semplicemente carica
+i file sorgenti del programma, li compila internamente, e poi mostra
+la riga d'invito:
+
+@example
+gawk>
+@end example
+
+@noindent
+da dove si possono impartire i comandi al debugger. Sin qui non @`e
+stato ancora eseguito nessun codice.
+
+@node Trovare il bug
+@subsection Trovare il bug
+
+Poniamo di avere un problema usando (una versione difettosa di)
+@file{uniq.awk} nella modalit@`a ``salta-campi'', perch@'e sembra che non
+catturi le righe che dovrebbero essere identiche dopo aver saltato il primo
+campo, come:
+
+@example
+awk, ecco un programma meraviglioso!
+gawk, ecco un programma meraviglioso!
+@end example
+
+Questo potrebbe accadere se noi pensassimo (come in C) che i campi in un record
+siano numerati prendendo come base lo zero, per cui, invece di scrivere:
+
+@example
+campi_ultima = join(vettore_ultima, contatore_file+1, n)
+campi_corrente = join(vettore_corrente, contatore_file+1, m)
+@end example
+
+@noindent
+abbiamo scritto:
+
+@example
+campi_ultima = join(vettore_ultima, contatore_file, n)
+campi_corrente = join(vettore_corrente, contatore_file, m)
+@end example
+
+La prima cosa da fare quando si tenta di indagare su un problema come questo @`e
+quella di mettere un punto d'interruzione (@dfn{breakpoint}) nel programma, in modo
+da poterlo vedere al lavoro e catturare quello che non va. Una posizione
+ragionevole per un punto d'interruzione in @file{uniq.awk} @`e all'inizio della
+funzione @code{se_sono_uguali()}, che confronta la riga corrente con la precedente.
+Per impostare il punto d'interruzione, usare il comando @code{b} (@dfn{breakpoint}):
+
+@example
+gawk> @kbd{b se_sono_uguali}
+@print{} Breakpoint 1 impostato al file `uniq.awk', riga 63
+@end example
+
+Il debugger mostra il file e il numero di riga dove si trova il punto
+d'interruzione. Ora bisogna immettere @samp{r} o @samp{run} e il programma
+viene eseguito fino al primo punto d'interruzione:
+
+@example
+gawk> @kbd{r}
+@print{} Partenza del programma:
+@print{} Mi fermo in Rule ...
+@print{} Breakpoint 1, se_sono_uguali(n, m, campi_ultima, campi_corrente,
+@print{} vettore_ultima, vettore_corrente)
+@print{} a `uniq.awk':63
+@print{} 63 if (contatore_file == 0 && conta_caratteri == 0)
+gawk>
+@end example
+
+Ora possiamo osservare cosa accade all'interno del nostro programma.
+Prima di tutto, vediamo come siamo arrivati a questo punto. Sulla riga di
+comando battiamo @samp{bt} (che sta per ``backtrace''), e il debugger risponde
+con un listato degli @dfn{stack frame} correnti:
+
+@example
+gawk> @kbd{bt}
+@print{} #0 se_sono_uguali(n, m, campi_ultima, campi_corrente,
+@print{} vettore_ultima, vettore_corrente)
+@print{} a `uniq.awk':63
+@print{} #1 in main() a `uniq.awk':88
+@end example
+
+Questo ci dice che la funzione @code{se_sono_uguali()} @`e stata chiamata
+dal programma principale alla riga 88 del file @file{uniq.awk}. (Questo non
+sorprende, perch@'e @`e questa l'unica chiamata a @code{se_sono_uguali()} nel
+programma, per@`o in programmi
+pi@`u complessi, sapere chi ha chiamato una funzione e con quali parametri pu@`o
+essere la chiave per trovare l'origine del problema.)
+
+Ora che siamo in @code{se_sono_uguali()}, possiamo iniziare a guardare i valori di
+alcune variabili. Immaginiamo di battere @samp{p n}
+(@code{p} sta per @dfn{print} [stampa]). Ci aspetteremo di vedere il valore di
+@code{n}, un parametro di @code{se_sono_uguali()}. In realt@`a, il debugger
+ci d@`a:
+
+@example
+gawk> @kbd{p n}
+@print{} n = untyped variable
+@end example
+
+@noindent
+In questo caso, @code{n} @`e una variabile locale non inizializzata, perch@'e la
+funzione @`e stata chiamata senza argomenti (@pxref{Chiamate di funzione}).
+
+Una variabile pi@`u utile da visualizzare potrebbe essere la seguente:
+
+@example
+gawk> @kbd{p $0}
+@print{} $0 = "gawk, ecco un programma meraviglioso!"
+@end example
+
+@noindent
+All'inizio questo potrebbe lasciare un tantino perplessi, perch@'e @`e la seconda
+riga dell'input del test. Vediamo @code{NR}:
+
+@example
+gawk> @kbd{p NR}
+@print{} NR = 2
+@end example
+
+@noindent
+Come si pu@`o vedere, @code{se_sono_uguali()} @`e stata chiamata solo per la seconda
+riga del file. Naturalmente, ci@`o accade perch@'e il nostro programma contiene
+una regola per @samp{NR == 1}:
+
+@example
+NR == 1 @{
+ ultima = $0
+ next
+@}
+@end example
+
+Bene, controlliamo che questa funzioni correttamente:
+
+@example
+gawk> @kbd{p ultima}
+@print{} ultima = "awk, ecco un programma meraviglioso!"
+@end example
+
+Tutto ci@`o che @`e stato fatto fin qui ha verificato che il programma funziona
+come previsto fino alla chiamata a @code{se_sono_uguali()} compresa; quindi
+il problema dev'essere all'interno di questa funzione. Per indagare
+ulteriormente, iniziamo a ``scorrere una ad una'' le righe di
+@code{se_sono_uguali()}. Cominciamo col battere @samp{n} (per ``next''
+[successivo]):
+
+@example
+gawk> @kbd{n}
+@print{} 66 if (contatore_file > 0) @{
+@end example
+
+Questo ci dice che @command{gawk} ora @`e pronto per eseguire la riga 66, che
+decide se assegnare alle righe il trattamento speciale ``salta-campi''
+indicato dall'opzione sulla riga di comando @option{-1}. (Si noti che abbiamo
+saltato da dov'eravamo prima, alla riga 63, a qui, perch@'e la condizione nella
+riga 63, @samp{if (contatore_file == 0 && conta_caratteri == 0)}, era falsa.)
+
+Continuando a scorrere le righe, ora raggiungiamo la divisione del record
+corrente e dell'ultimo:
+
+@example
+gawk> @kbd{n}
+@print{} 67 n = split(ultima, vettore_ultima)
+gawk> @kbd{n}
+@print{} 68 m = split($0, vettore_corrente)
+@end example
+
+A questo punto, potremmo stare a vedere in quante parti il nostro record
+@`e stato suddiviso, quindi proviamo a osservare:
+
+@example
+gawk> @kbd{p n m vettore_ultima vettore_corrente}
+@print{} n = 5
+@print{} m = untyped variable
+@print{} vettore_ultima = array, 5 elements
+@print{} vettore_corrente = untyped variable
+@end example
+
+@noindent
+(Il comando @code{p} pu@`o accettare pi@`u argomenti, analogamente
+all'istruzione di @command{awk} @code{print}.)
+
+Questo ci lascia piuttosto perplessi. Tutto ci@`o che abbiamo trovato @`e che ci
+sono cinque elementi in @code{vettore_ultima}; @code{m} e @code{vettore_corrente} non hanno valori
+perch@'e siamo alla riga 68 che non @`e ancora stata eseguita. Questa
+informazione @`e abbastanza utile (ora sappiamo che nessuna delle parole @`e stata
+lasciata fuori accidentalmente), ma sarebbe desiderabile vedere i valori
+del vettore.
+
+Una prima possibilit@`a @`e quella di usare degli indici:
+
+@example
+gawk> @kbd{p vettore_ultima[0]}
+@print{} "0" non presente nel vettore `vettore_ultima'
+@end example
+
+@noindent
+Oops!
+
+@example
+gawk> @kbd{p vettore_ultima[1]}
+@print{} vettore_ultima["1"] = "awk,"
+@end example
+
+Questo metodo sarebbe piuttosto lento per un vettore con 100 elementi, per cui
+@command{gawk} fornisce una scorciatoia (che fa venire in mente un altro
+linguaggio che non nominiamo):
+
+@example
+gawk> @kbd{p @@vettore_ultima}
+@print{} vettore_ultima["1"] = "awk,"
+@print{} vettore_ultima["2"] = "ecco"
+@print{} vettore_ultima["3"] = "un"
+@print{} vettore_ultima["4"] = "programma"
+@print{} vettore_ultima["5"] = "meraviglioso!"
+@end example
+
+Finora, sembra che tutto vada bene. Facciamo un altro passo,
+o anche due:
+
+@example
+gawk> @kbd{n}
+@print{} 69 campi_ultima = join(vettore_ultima, contatore_file, n)
+gawk> @kbd{n}
+@print{} 70 campi_corrente = join(vettore_corrente, contatore_file, m)
+@end example
+
+Bene, eccoci arrivati al nostro errore (ci spiace di aver rovinato la
+sorpresa).
+Quel che avevamo in mente era di unire i campi a partire dal secondo per
+creare il record virtuale da confrontare, e se il primo campo aveva il numero
+zero, questo avrebbe funzionato. Vediamo quel che abbiamo finora:
+
+@example
+gawk> @kbd{p campi_ultima campi_corrente}
+@print{} campi_ultima = "awk, ecco un programma meraviglioso!"
+@print{} campi_corrente = "gawk, ecco un programma meraviglioso!"
+@end example
+
+Ehi! queste frasi suonano piuttosto familiari! Sono esattamente i nostri
+record di input originali, inalterati. Pensandoci un po' (il cervello umano @`e
+ancora il miglior strumento di debug), ci si rende conto che eravamo fuori di
+uno!
+
+Usciamo dal debugger:
+
+@example
+gawk> @kbd{q}
+@print{} Il programma @`e in esecuzione. Esco comunque (y/n)? @kbd{y}
+@end example
+
+@noindent
+Quindi modifichiamo con un editore di testo:
+
+@example
+campi_ultima = join(vettore_ultima, contatore_file+1, n)
+campi_corrente = join(vettore_corrente, contatore_file+1, m)
+@end example
+
+@noindent
+e il problema @`e risolto!
+
+@node Lista dei comandi di debug
+@section I principali comandi di debug
+
+L'insieme dei comandi del debugger di @command{gawk} pu@`o essere diviso nelle
+seguenti categorie:
+
+@itemize @value{BULLET}
+
+@item
+Controllo di punti d'interruzione
+
+@item
+Controllo di esecuzione
+
+@item
+Vedere e modificare dati
+
+@item
+Lavorare con le pile
+
+@item
+Ottenere informazioni
+
+@item
+Comandi vari
+@end itemize
+
+Ciascuna di esse @`e trattata nelle sottosezioni che seguono.
+Nelle descrizioni seguenti, i comandi che possono essere abbreviati
+mostrano l'abbreviazione su una seconda riga di descrizione.
+Un nome di comando del debugger pu@`o essere anche troncato se la parte gi@`a scritta
+non @`e ambigua. Il debugger ha la capacit@`a predefinita di ripetere
+automaticamente il precedente comando semplicemente battendo @kbd{Invio}.
+Questo vale per i comandi @code{list}, @code{next}, @code{nexti},
+@code{step}, @code{stepi} e @code{continue} quando sono eseguiti senza
+argomenti.
+
+@menu
+* Controllo dei breakpoint:: Controllo dei punti d'interruzione.
+* Controllo esecuzione debugger:: Controllo di esecuzione.
+* Vedere e modificare dati:: Vedere e modificare dati.
+* Stack di esecuzione:: Lavorare con le pile.
+* Informazioni sul debugger:: Ottenere informazioni sullo stato del
+ programma e del debugger.
+* Comandi vari del debugger:: Comandi vari del debugger.
+@end menu
+
+@node Controllo dei breakpoint
+@subsection Controllo dei punti d'interruzione
+
+Come abbiamo gi@`a visto, la prima cosa che si dovrebbe fare in una sessione di
+debug @`e quella di definire dei punti d'interruzione, poich@'e altrimenti il
+programma verr@`a eseguito come se non fosse sotto il debugger. I comandi per
+controllare i punti d'interruzione sono:
+
+@table @asis
+@cindex comando del debugger, @code{b} (alias per @code{break})
+@cindex comando del debugger, @code{break}
+@cindex @code{break}, comando del debugger
+@cindex @code{b}, comando del debugger (alias per @code{break})
+@cindex impostare un punto d'interruzione
+@cindex breakpoint, impostare
+@cindex punto d'interruzione (breakpoint), impostare
+@item @code{break} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}] [@code{"@var{espressione}"}]
+@itemx @code{b} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}] [@code{"@var{espressione}"}]
+Senza argomenti, imposta un punto d'interruzione alla prossima istruzione
+da eseguire nello @dfn{stack frame} selezionato.
+Gli argomenti possono essere uno dei seguenti:
+
+@c @asis for docbook
+@c nested table
+@table @asis
+@item @var{n}
+Imposta un punto d'interruzione alla riga numero @var{n} nel file sorgente
+corrente.
+
+@item @var{nome-file}@code{:}@var{n}
+Imposta un punto d'interruzione alla riga numero @var{n} nel file sorgente
+@var{nome-file}.
+
+@item @var{funzione}
+Imposta un punto d'interruzione all'ingresso (la prima istruzione eseguibile)
+della funzione @var{funzione}.
+@end table
+
+A ogni punto d'interruzione @`e assegnato un numero che pu@`o essere usato per
+cancellarlo dalla lista dei punti d'interruzione usando il comando
+@code{delete}.
+
+Specificando un punto d'interruzione, si pu@`o fornire anche una condizione.
+Questa @`e
+un'espressione @command{awk} (racchiusa tra doppi apici) che il debugger
+valuta ogni volta che viene raggiunto quel punto d'interruzione. Se la
+condizione @`e vera, il debugger ferma l'esecuzione e rimane in attesa di un
+comando. Altrimenti, continua l'esecuzione del programma.
+
+@cindex comando del debugger, @code{clear}
+@cindex @code{clear}, comando del debugger
+@cindex cancellare punto d'interruzione da una determinata posizione
+@cindex punto d'interruzione in una determinata posizione, come cancellare
+@cindex breakpoint, come cancellare
+@item @code{clear} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}]
+Senza argomenti, cancella ogni eventuale punto d'interruzione all'istruzione
+successiva
+da eseguirsi nello @dfn{stack frame} selezionato. Se il programma si ferma in
+un punto d'interruzione, quel punto d'interruzione viene cancellato in modo
+che il programma non si fermi pi@`u in quel punto.
+Gli argomenti possono essere uno tra i seguenti:
+
+@c nested table
+@table @asis
+@item @var{n}
+Cancella il punto (o i punti) d'interruzione impostato/i alla riga @var{n} nel
+file sorgente corrente.
+
+@item @var{nome-file}@code{:}@var{n}
+Cancella il punto (o i punti) d'interruzione impostato/i alla riga @var{n} nel
+file sorgente @var{nome-file}.
+
+@item @var{funzione}
+Cancella il punto (o i punti) d'interruzione impostato/i all'ingresso della
+funzione @var{funzione}.
+@end table
+
+@cindex comando del debugger, @code{condition}
+@cindex @code{condition}, comando del debugger
+@cindex condizione dei punti d'interruzione
+@item @code{condition} @var{n} @code{"@var{espressione}"}
+Aggiunge una condizione al punto d'interruzione o al punto d'osservazione
+esistente @var{n}. La condizione @`e un'espressione @command{awk}
+@emph{racchiusa tra doppi apici} che il debugger valuta ogni volta che viene
+raggiunto il punto d'interruzione o il punto d'osservazione. Se la condizione @`e
+vera, il debugger ferma l'esecuzione e attende l'immissione di un comando.
+Altrimenti, il debugger continua l'esecuzione del programma. Se l'espressione
+della condizione non viene specificata, tutte le condizioni esistenti vengono
+rimosse (cio@`e, il punto d'interruzione o di osservazione viene considerato
+incondizionato).
+
+@cindex comando del debugger, @code{d} (alias per @code{delete})
+@cindex comando del debugger, @code{delete}
+@cindex @code{delete}, comando del debugger
+@cindex @code{d}, comando del debugger (alias per @code{delete})
+@cindex cancellare punto d'interruzione per numero
+@cindex punto d'interruzione, cancellare per numero
+@item @code{delete} [@var{n1 n2} @dots{}] [@var{n}--@var{m}]
+@itemx @code{d} [@var{n1 n2} @dots{}] [@var{n}--@var{m}]
+Cancella i punti d'interruzione specificati o un intervallo di punti
+d'interruzione. Se non vengono forniti argomenti, cancella tutti i
+punti d'interruzione esistenti.
+
+@cindex comando del debugger, @code{disable}
+@cindex @code{disable}, comando del debugger
+@cindex disabilitare punto d'interruzione
+@cindex punto d'interruzione, come disabilitare o abilitare
+@item @code{disable} [@var{n1 n2} @dots{} | @var{n}--@var{m}]
+Disabilita punti d'interruzione specificati o un intervallo di essi. Senza
+argomenti, disabilita tutti i punti d'interruzione.
+
+@cindex comando del debugger, @code{e} (alias per @code{enable})
+@cindex comando del debugger, @code{enable}
+@cindex @code{enable}, comando del debugger
+@cindex @code{e}, comando del debugger (alias per @code{enable})
+@cindex abilitare un punto d'interruzione
+@item @code{enable} [@code{del} | @code{once}] [@var{n1 n2} @dots{}] [@var{n}--@var{m}]
+@itemx @code{e} [@code{del} | @code{once}] [@var{n1 n2} @dots{}] [@var{n}--@var{m}]
+Abilita specifici punti d'interruzione o un intervallo di essi. Senza
+argomenti, abilita tutti i punti d'interruzione.
+Opzionalmente, si pu@`o specificare come abilitare i punti d'interruzione:
+
+@c nested table
+@table @code
+@item del
+Abilita dei punti d'interruzione @dfn{una tantum}, poi li cancella quando il
+programma si ferma in quel punto.
+
+@item once
+Abilita dei punti d'interruzione @dfn{una tantum}, poi li cancella quando il
+programma si ferma in quel punto.
+@end table
+
+@cindex comando del debugger, @code{ignore}
+@cindex @code{ignore}, comando del debugger
+@cindex ignorare un punto d'interruzione
+@item @code{ignore} @var{n} @var{contatore}
+Ignora il punto d'interruzione numero @var{n} le successive
+@var{contatore} volte in cui viene raggiunto.
+
+@cindex comando del debugger, @code{t} (alias per @code{tbreak})
+@cindex comando del debugger, @code{tbreak}
+@cindex @code{tbreak}, comando del debugger
+@cindex @code{t}, comando del debugger (alias per @code{tbreak})
+@cindex punto d'interruzione temporaneo
+@cindex temporaneo, punto d'interruzione
+@item @code{tbreak} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}]
+@itemx @code{t} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}]
+Imposta un punto d'interruzione temporaneo (abilitato solo per la prima volta
+che viene raggiunto). Gli argomenti sono gli stessi di @code{break}.
+@end table
+
+@node Controllo esecuzione debugger
+@subsection Controllo di esecuzione
+
+Dopo che i punti d'interruzione sono pronti, si pu@`o iniziare l'esecuzione del
+programma, osservando il suo comportamento. Ci sono pi@`u comandi per
+controllare l'esecuzione del programma di quelli visti nei precedenti esempi:
+
+@table @asis
+@cindex comando del debugger, @code{commands}
+@cindex @code{commands}, comando del debugger
+@cindex comando del debugger, @code{silent}
+@cindex @code{silent}, comando del debugger
+@cindex comando del debugger, @code{end}
+@cindex @code{end}, comando del debugger
+@cindex punto d'interruzione, comandi
+@cindex comandi da eseguire al punto d'interruzione
+@item @code{commands} [@var{n}]
+@itemx @code{silent}
+@itemx @dots{}
+@itemx @code{end}
+Imposta una lista di comandi da eseguire subito dopo l'arresto del programma in
+un punto d'interruzione o di osservazione. @var{n} @`e il numero del punto
+d'interruzione o di osservazione. Se non si specifica un numero, viene usato
+l'ultimo numero che @`e stato specificato. I comandi veri e propri seguono,
+a cominciare dalla riga successiva, e hanno termine col comando @code{end}.
+Se il comando @code{silent} @`e nella lista, i consueti messaggi sull'arresto del
+programma a un punto d'interruzione e la riga sorgente non vengono stampati.
+Qualsiasi comando nella lista che riprende l'esecuzione (p.es.,
+@code{continue}) pone fine alla lista (un @code{end} implicito), e i comandi
+successivi vengono ignorati.
+Per esempio:
+
+@example
+gawk> @kbd{commands}
+> @kbd{silent}
+> @kbd{printf "Un punto d'interruzione silenzioso; i = %d\n", i}
+> @kbd{info locals}
+> @kbd{set i = 10}
+> @kbd{continue}
+> @kbd{end}
+gawk>
+@end example
+
+@cindex comando del debugger, @code{c} (alias per @code{continue})
+@cindex comando del debugger, @code{continue}
+@cindex @code{continue}, comando del debugger
+@item @code{continue} [@var{contatore}]
+@itemx @code{c} [@var{contatore}]
+Riprende l'esecuzione del programma. Se si riparte da un punto d'interruzione
+e viene specificato @var{contatore}, il punto d'interruzione in quella
+posizione viene ignorato per le prossime @var{contatore} volte prima di
+fermarsi nuovamente.
+
+@cindex comando del debugger, @code{finish}
+@cindex @code{finish}, comando del debugger
+@item @code{finish}
+Esegue fino a quando lo stack frame selezionato completa l'esecuzione.
+Stampa il valore restituito.
+
+@cindex comando del debugger, @code{n} (alias per @code{next})
+@cindex comando del debugger, @code{next}
+@cindex @code{next}, comando del debugger
+@cindex @code{n}, comando del debugger (alias per @code{next})
+@cindex esecuzione di un solo passo, nel debugger
+@item @code{next} [@var{contatore}]
+@itemx @code{n} [@var{contatore}]
+Continua l'esecuzione alla successiva riga sorgente, saltando le chiamate di
+funzione. L'argomento @var{contatore} controlla il numero di ripetizioni
+dell'azione, come in @code{step}.
+
+@cindex comando del debugger, @code{ni} (alias per @code{nexti})
+@cindex comando del debugger, @code{nexti}
+@cindex @code{nexti}, comando del debugger
+@cindex @code{ni}, comando del debugger (alias for @code{nexti})
+@item @code{nexti} [@var{contatore}]
+@itemx @code{ni} [@var{contatore}]
+Esegue una o @var{contatore} istruzioni, comprese le chiamate di funzione.
+
+@cindex comando del debugger, @code{return}
+@cindex @code{return}, comando del debugger
+@item @code{return} [@var{valore}]
+Cancella l'esecuzione di una chiamata di funzione. Se @var{valore} (una
+stringa o un numero) viene specificato, @`e usato come valore di ritorno della
+funzione. Se usato in un frame diverso da quello pi@`u interno (la funzione
+correntemente in esecuzione; cio@`e, il frame numero 0), ignora tutti i frame
+pi@`u interni di quello selezionato, e il chiamante del frame selezionato
+diventa il frame pi@`u interno.
+
+@cindex comando del debugger, @code{r} (alias per @code{run})
+@cindex comando del debugger, @code{run}
+@cindex @code{run}, comando del debugger
+@cindex @code{r}, comando del debugger (alias per @code{run})
+@item @code{run}
+@itemx @code{r}
+Avvia/riavvia l'esecuzione del programma. Quando il programma viene riavviato,
+il debugger mantiene i punti d'interruzione e di osservazione, la cronologia
+dei comandi, la visualizzazione automatica di variabili, e le opzioni del
+debugger.
+
+@cindex comando del debugger, @code{s} (alias per @code{step})
+@cindex comando del debugger, @code{step}
+@cindex @code{step}, comando del debugger
+@cindex @code{s}, comando del debugger (alias per @code{step})
+@item @code{step} [@var{contatore}]
+@itemx @code{s} [@var{contatore}]
+Continua l'esecuzione finch@'e il controllo non raggiunge una diversa riga del
+sorgente nello @dfn{stack frame} corrente, eseguendo ogni funzione chiamata
+all'interno della riga. Se viene fornito l'argomento @var{contatore},
+esegue il numero di istruzioni specificate prima di fermarsi, a meno che non
+s'imbatta in un punto d'interruzione o di osservazione.
+
+@cindex comando del debugger, @code{si} (alias per @code{stepi})
+@cindex comando del debugger, @code{stepi}
+@cindex @code{stepi}, comando del debugger
+@cindex @code{si}, comando del debugger (alias per @code{stepi})
+@item @code{stepi} [@var{contatore}]
+@itemx @code{si} [@var{contatore}]
+Esegue una o @var{contatore} istruzioni, comprese le chiamate di funzione.
+(Per una spiegazione su cosa s'intende per ``istruzione'' in @command{gawk},
+si veda l'output mostrato sotto @code{dump} nella
+@ref{Comandi vari del debugger}.)
+
+@cindex comando del debugger, @code{u} (alias per @code{until})
+@cindex comando del debugger, @code{until}
+@cindex @code{until}, comando del debugger
+@cindex @code{u}, comando del debugger (alias per @code{until})
+@item @code{until} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}]
+@itemx @code{u} [[@var{nome-file}@code{:}]@var{n} | @var{funzione}]
+Senza argomenti, prosegue l'esecuzione finch@'e non viene raggiunta una riga
+dopo la riga corrente nello @dfn{stack frame} corrente.
+Se viene specificato un argomento,
+prosegue l'esecuzione finch@'e non viene raggiunto il punto specificato, o
+lo @dfn{stack frame} corrente non termina l'esecuzione.
+@end table
+
+@node Vedere e modificare dati
+@subsection Vedere e modificare dati
+
+I comandi per vedere e modificare variabili all'interno di @command{gawk} sono:
+
+@table @asis
+@cindex comando del debugger, @code{display}
+@cindex @code{display}, comando del debugger
+@item @code{display} [@var{var} | @code{$}@var{n}]
+Aggiunge la variabile @var{var} (o il campo @code{$@var{n}}) alla lista di
+visualizzazione. Il valore della variabile o del campo @`e visualizzato ogni
+volta che il programma s'interrompe.
+Ogni variabile aggiunta alla lista @`e identificata da un numero univoco:
+
+@example
+gawk> @kbd{display x}
+@print{} 10: x = 1
+@end example
+
+@noindent
+La riga qui sopra mostra il numero di elemento assegnato, il nome della
+variabile e il suo
+valore corrente. Se la variabile di display fa riferimento a un parametro di
+funzione, @`e cancellata silenziosamente dalla lista non appena l'esecuzione
+raggiunge un contesto dove la variabile con quel nome non esiste pi@`u.
+Senza argomenti, @code{display} mostra i valori correnti degli elementi della
+lista.
+
+@cindex comando del debugger, @code{eval}
+@cindex @code{eval}, comando del debugger
+@cindex valutare espressioni, nel debugger
+@item @code{eval "@var{istruzioni awk}"}
+Valuta @var{istruzioni awk} nel contesto del programma in esecuzione.
+Si pu@`o fare qualsiasi cosa che un programma @command{awk} farebbe: assegnare
+valori a variabili, chiamare funzioni, e cos@`{@dotless{i}} via.
+
+@item @code{eval} @var{param}, @dots{}
+@itemx @var{istruzioni awk}
+@itemx @code{end}
+Questa forma di @code{eval} @`e simile alla precedente, solo che permette di
+definire
+``variabili locali'' che esistono nel contesto delle @var{istruzioni awk},
+invece di usare variabili o parametri di funzione gi@`a definiti nel programma.
+
+@cindex comando del debugger, @code{p} (alias per @code{print})
+@cindex comando del debugger, @code{print}
+@cindex @code{print}, comando del debugger
+@cindex @code{p}, comando del debugger (alias per @code{print})
+@cindex stampare variabili, nel debugger
+@item @code{print} @var{var1}[@code{,} @var{var2} @dots{}]
+@itemx @code{p} @var{var1}[@code{,} @var{var2} @dots{}]
+Stampa i valori di una o pi@`u variabili o campi di @command{gawk}.
+I campi devono essere indicizzati usando delle costanti:
+
+@example
+gawk> @kbd{print $3}
+@end example
+
+@noindent
+Questo stampa il terzo campo del record di input (se il campo specificato non
+esiste, stampa il @samp{campo nullo}). Una variabile pu@`o essere un elemento di
+un vettore, avente come indice una
+stringa di valore costante. Per stampare
+il contenuto di un vettore, si deve anteporre il simbolo @samp{@@} al nome del
+vettore:
+
+@example
+gawk> @kbd{print @@a}
+@end example
+
+@noindent
+L'esempio stampa gli indici e i corrispondenti valori di tutti gli elementi
+del vettore @code{a}.
+
+@cindex comando del debugger, @code{printf}
+@cindex @code{printf}, comando del debugger
+@item @code{printf} @var{formato} [@code{,} @var{arg} @dots{}]
+Stampa un testo formattato. Il @var{formato} pu@`o includere sequenze di
+protezione, come @samp{\n}
+(@pxref{Sequenze di protezione}).
+Non viene stampato nessun ritorno a capo che non sia stato specificato
+esplicitamente.
+
+@cindex comando del debugger, @code{set}
+@cindex @code{set}, comando del debugger
+@cindex assegnare valori a variabili, nel debugger
+@item @code{set} @var{var}@code{=}@var{valore}
+Assegna un valore costante (numero o stringa) a una variabile o a un campo di
+@command{awk}.
+I valori di stringa devono essere racchiusi tra doppi apici
+(@code{"}@dots{}@code{"}).
+
+Si possono impostare anche delle variabili speciali di @command{awk}, come
+@code{FS}, @code{NF}, @code{NR}, e cos@`{@dotless{i}} via.
+
+@cindex comando del debugger, @code{w} (alias per @code{watch})
+@cindex comando del debugger, @code{watch}
+@cindex @code{watch}, comando del debugger
+@cindex @code{w}, comando del debugger (alias per @code{watch})
+@cindex impostare un punto d'osservazione
+@item @code{watch} @var{var} | @code{$}@var{n} [@code{"@var{espressione}"}]
+@itemx @code{w} @var{var} | @code{$}@var{n} [@code{"@var{espressione}"}]
+Aggiunge la variabile @var{var} (o il campo @code{$@var{n}}) alla lista dei
+punti d'osservazione. Il debugger quindi interrompe il programma ogni volta
+che il valore della variabile o del campo cambia. A ogni elemento osservato
+viene assegnato un numero che pu@`o essere usato per cancellarlo dalla lista
+usando il comando @code{unwatch} [non-osservare pi@`u].
+
+Definendo un punto d'osservazione, si pu@`o anche porre una condizione, che @`e
+un'espressione @command{awk} (racchiusa tra doppi apici) che il debugger valuta
+ogni volta che viene raggiunto il punto d'osservazione. Se la condizione @`e
+vera, il debugger interrompe l'esecuzione e rimane in attesa di un comando.
+Altrimenti, @command{gawk} prosegue nell'esecuzione del programma.
+
+@cindex comando del debugger, @code{undisplay}
+@cindex @code{undisplay}, comando del debugger
+@cindex interruzione visualizzazioni automatiche, nel debugger
+@item @code{undisplay} [@var{n}]
+Rimuove l'elemento numero @var{n} (o tutti gli elementi, se non vi sono
+argomenti) dalla lista delle visualizzazioni automatiche.
+
+@cindex comando del debugger, @code{unwatch}
+@cindex @code{unwatch}, comando del debugger
+@cindex cancellare punto d'osservazione
+@item @code{unwatch} [@var{n}]
+Rimuove l'elemento numero @var{n} (o tutti gli elementi, se non vi sono
+argomenti) dalla lista dei punti d'osservazione.
+
+@end table
+
+@node Stack di esecuzione
+@subsection Lavorare con lo stack
+
+Ogni volta che si esegue un programma che contiene chiamate di funzione,
+@command{gawk} mantiene una pila contenente la lista delle chiamate di funzione
+che hanno portato al punto in cui il programma si trova in ogni momento. @`E
+possibile vedere a che punto si trova il programma, e anche muoversi
+all'interno della pila per vedere qual era lo stato delle cose nelle funzioni
+che hanno chiamato quella in cui ci si trova. I comandi per far questo sono:
+
+@table @asis
+@cindex comando del debugger, @code{bt} (alias per @code{backtrace})
+@cindex comando del debugger, @code{backtrace}
+@cindex comando del debugger, @code{where} (alias per @code{backtrace})
+@cindex @code{backtrace}, comando del debugger
+@cindex @code{bt}, comando del debugger (alias per @code{backtrace})
+@cindex @code{where}, comando del debugger
+@cindex @code{where}, comando del debugger (alias per @code{backtrace})
+@cindex chiamate, @dfn{stack} (pila) delle, mostrare nel debugger
+@cindex @dfn{stack} (pila) delle chiamate, mostrare nel debugger
+@cindex pila (@dfn{stack}) delle chiamate, mostrare nel debugger
+@cindex tracciatura a ritroso, mostrare nel debugger
+@item @code{backtrace} [@var{contatore}]
+@itemx @code{bt} [@var{contatore}]
+@itemx @code{where} [@var{contatore}]
+Stampa a ritroso una traccia di tutte le chiamate di funzione (stack frame), o
+i dei @var{contatore} frame pi@`u interni se @var{contatore} > 0. Stampa i
+@var{contatore} frame pi@`u esterni se @var{contatore} < 0. La tracciatura a
+ritroso mostra il nome e gli argomenti di ciascuna funzione, il sorgente
+@value{FN}, e il numero di riga. L'alias @code{where} per @code{backtrace}
+viene mantenuto per i vecchi utenti di GDB che potrebbero essere abituati a
+quel comando.
+
+@cindex comando del debugger, @code{down}
+@cindex @code{down}, comando del debugger
+@item @code{down} [@var{contatore}]
+Sposta @var{contatore} (default 1) frame sotto la pila verso il frame pi@`u interno.
+Poi seleziona e stampa il frame.
+
+@cindex comando del debugger, @code{f} (alias per @code{frame})
+@cindex comando del debugger, @code{frame}
+@cindex @code{frame}, comando del debugger
+@cindex @code{f}, comando del debugger (alias per @code{frame})
+@item @code{frame} [@var{n}]
+@itemx @code{f} [@var{n}]
+Seleziona e stampa lo @dfn{stack frame} @var{n}. Il frame 0 @`e quello
+correntemente in esecuzione, o il frame @dfn{pi@`u interno}, (chiamata di
+funzione); il frame 1 @`e il frame che ha chiamato quello pi@`u interno. Il frame
+col numero pi@`u alto @`e quello per il programma principale. Le informazioni
+stampate comprendono il numero di frame, i nomi delle funzioni e degli
+argomenti, i file sorgenti e le righe sorgenti.
+
+@cindex comando del debugger, @code{up}
+@cindex @code{up}, comando del debugger
+@item @code{up} [@var{contatore}]
+Sposta @var{contatore} (default 1) frame sopra la pila verso il frame pi@`u
+esterno. Poi seleziona e stampa il frame.
+@end table
+
+@node Informazioni sul debugger
+@subsection Ottenere informazioni sullo stato del programma e del debugger
+
+Oltre che vedere i valori delle variabili, spesso si ha necessit@`a di ottenere
+informazioni di altro tipo sullo stato del programma e dello stesso ambiente di
+debug. Il debugger di @command{gawk} ha un comando che fornisce
+quest'informazione, chiamato convenientemente @code{info}. @code{info}
+@`e usato con uno dei tanti argomenti che dicono esattamente quel che si vuol
+sapere:
+
+@table @asis
+@cindex comando del debugger, @code{i} (alias per @code{info})
+@cindex comando del debugger, @code{info}
+@cindex @code{info}, comando del debugger
+@cindex @code{i}, comando del debugger (alias per @code{info})
+@item @code{info} @var{cosa}
+@itemx @code{i} @var{cosa}
+Il valore di @var{cosa} dovrebbe essere uno dei seguenti:
+
+@c nested table
+@table @code
+@item args
+@cindex mostrare argomenti delle funzioni, nel debugger
+@cindex debugger, mostrare argomenti delle funzioni
+Elenca gli argomenti del frame selezionato.
+
+@item break
+@cindex mostrare punti d'interruzione, nel debugger
+@cindex debugger, mostrare punti d'interruzione
+Elenca tutti i punti d'interruzione attualmente impostati.
+
+@item display
+@cindex visualizzazioni automatiche, nel debugger
+@cindex debugger, visualizzazioni automatiche
+Elenca tutti gli elementi della lista delle visualizzazioni automatiche.
+
+@item frame
+@cindex descrizione degli @dfn{stack frame} delle chiamate, nel debugger
+@cindex debugger, descrizione degli @dfn{stack frame} delle chiamate
+D@`a una descrizione degli @dfn{stack frame} selezionati.
+
+@item functions
+@cindex elencare definizioni delle funzioni, nel debugger
+@cindex debugger, elencare definizioni delle funzioni
+Elenca tutte le definizioni delle funzioni compresi i @value{FNS} e
+i numeri di riga.
+
+@item locals
+@cindex mostrare variabili locali, nel debugger
+@cindex debugger, mostrare variabili locali
+Elenca le variabili locali dei frame selezionati.
+
+@item source
+@cindex mostrare il nome del file sorgente corrente, nel debugger
+@cindex debugger, mostrare il nome del file sorgente corrente
+Stampa il nome del file sorgente corrente. Ogni volta che il programma si
+interrompe, il file sorgente corrente @`e il file che contiene l'istruzione
+corrente. Quando il debugger viene avviato per la prima volta, il file
+sorgente corrente @`e il primo file incluso attraverso l'opzione @option{-f}.
+Il comando @samp{list @var{nome-file}:@var{numero-riga}} pu@`o essere usato in
+qualsiasi momento per cambiare il sorgente corrente.
+
+@item sources
+@cindex mostrare tutti i file sorgente, nel debugger
+@cindex debugger, mostrare tutti i file sorgenti
+Elenca tutti i sorgenti del programma.
+
+@item variables
+@cindex elencare tutte le variabili locali, nel debugger
+@cindex debugger, elencare tutte le variabili locali
+Elenca tutte le variabili locali.
+
+@item watch
+@cindex mostrare i punti d'osservazione, nel debugger
+@cindex debugger, mostrare i punti d'osservazione
+Elenca tutti gli elementi della lista dei punti d'osservazione.
+@end table
+@end table
+
+Ulteriori comandi permettono di avere il controllo sul debugger, la capacit@`a di
+salvare lo stato del debugger e la capacit@`a di eseguire comandi del debugger
+da un file. I comandi sono:
+
+@table @asis
+@cindex comando del debugger, @code{o} (alias per @code{option})
+@cindex comando del debugger, @code{option}
+@cindex @code{option}, comando del debugger
+@cindex @code{o}, comando del debugger (alias per @code{option})
+@cindex visualizzare le opzioni del debugger
+@cindex debugger, opzioni del
+@item @code{option} [@var{nome}[@code{=}@var{valore}]]
+@itemx @code{o} [@var{nome}[@code{=}@var{valore}]]
+Senza argomenti, visualizza le opzioni del debugger disponibili e i loro valori
+correnti. @samp{option @var{nome}} mostra il valore corrente dell'opzione
+cos@`{@dotless{i}} denominata. @samp{option @var{nome}=@var{valore}} assegna
+un nuovo valore all'opzione.
+Le opzioni disponibili sono:
+
+@c nested table
+@c asis for docbook
+@table @asis
+@item @code{history_size}
+@cindex debugger, dimensione della cronologia
+Imposta il numero massimo di righe da mantenere nel file della cronologia
+@file{./.gawk_history}. Il valore di default @`e 100.
+
+@item @code{listsize}
+@cindex debugger, numero di righe nella lista di default
+Specifica il numero di righe che @code{list} deve stampare. Il valore di
+default @`e 15.
+
+@item @code{outfile}
+@cindex ridirezionare l'output di @command{gawk}, nel debugger
+@cindex debugger, ridirezionare l'output di @command{gawk}
+Invia l'output di @command{gawk} in un file; l'output del debugger @`e
+visualizzato comunque anche
+nello standard output. Assegnare come valore stringa vuota (@code{""})
+reimposta l'output solo allo standard output.
+
+@item @code{prompt}
+@cindex debugger, prompt
+Cambia la riga per l'immissione dei comandi del debugger. Il valore di
+default @`e @samp{@w{gawk> }}.
+
+@item @code{save_history} [@code{on} | @code{off}]
+@cindex debugger, file della cronologia
+Salva la cronologia dei comandi nel file @file{./.gawk_history}.
+L'impostazione di default @`e @code{on}.
+
+@item @code{save_options} [@code{on} | @code{off}]
+@cindex salvataggio opzioni debugger
+@cindex debugger, salvataggio opzioni
+Salva le opzioni correnti nel file @file{./.gawkrc} all'uscita.
+L'impostazione di default @`e @code{on}.
+Le opzioni sono lette di nuovo all'avvio della sessione successiva.
+
+@item @code{trace} [@code{on} | @code{off}]
+@cindex istruzioni, tener traccia delle, nel debugger
+@cindex debugger, tener traccia delle istruzioni
+Attiva o disattiva il tracciamento delle istruzioni. L'impostazione di default
+@`e @code{off}.
+@end table
+
+@item @code{save} @var{nome-file}
+Salva i comandi eseguiti nella sessione corrente nel @value{FN} indicato,
+in modo da poterli ripetere in seguito usando il comando @command{source}.
+
+@item @code{source} @var{nome-file}
+@cindex debugger, leggere comandi da un file
+Esegue comandi contenuti in un file; un errore in un comando non impedisce
+l'esecuzione dei comandi successivi. In un file di comandi sono consentiti
+i commenti (righe che iniziano con @samp{#}).
+Le righe vuote vengono ignorate; esse @emph{non}
+ripetono l'ultimo comando.
+Non si pu@`o riavviare il programma mettendo pi@`u di un comando @code{run}
+nel file. Inoltre, la lista dei comandi pu@`o includere altri comandi
+@code{source}; in ogni caso, il debugger di @command{gawk} non richiama lo
+stesso file pi@`u di una volta per evitare ricorsioni infinite.
+
+Oltre al comando @code{source}, o al posto di esso, si possono usare le opzioni
+sulla riga di comando @option{-D @var{file}} o @option{--debug=@var{file}}
+per eseguire comandi da un file in maniera non interattiva
+(@pxref{Opzioni}).
+@end table
+
+@node Comandi vari del debugger
+@subsection Comandi vari del debugger
+
+Ci sono alcuni altri comandi che non rientrano nelle precedenti categorie,
+come i seguenti:
+
+@table @asis
+@cindex comando del debugger, @code{dump}
+@cindex @code{dump}, comando del debugger
+@item @code{dump} [@var{nome-file}]
+Riversa il @dfn{byte code} del programma nello standard output o nel file
+definito in @var{nome-file}. Questo stampa una rappresentazione delle
+istruzioni interne che @command{gawk} esegue per implementare i comandi
+@command{awk} in un programma. Ci@`o pu@`o essere molto istruttivo, come
+dimostra il seguente riversamento parziale del codice offuscato di
+Davide Brini (@pxref{Programma signature}):
+
+@c FIXME: This will need updating if num-handler branch is ever merged in.
+@smallexample
+gawk> @kbd{dump}
+@print{} # BEGIN
+@print{}
+@print{} [ 1:0xfcd340] Op_rule : [in_rule = BEGIN] [source_file = brini.awk]
+@print{} [ 1:0xfcc240] Op_push_i : "~" [MALLOC|STRING|STRCUR]
+@print{} [ 1:0xfcc2a0] Op_push_i : "~" [MALLOC|STRING|STRCUR]
+@print{} [ 1:0xfcc280] Op_match :
+@print{} [ 1:0xfcc1e0] Op_store_var : O
+@print{} [ 1:0xfcc2e0] Op_push_i : "==" [MALLOC|STRING|STRCUR]
+@print{} [ 1:0xfcc340] Op_push_i : "==" [MALLOC|STRING|STRCUR]
+@print{} [ 1:0xfcc320] Op_equal :
+@print{} [ 1:0xfcc200] Op_store_var : o
+@print{} [ 1:0xfcc380] Op_push : o
+@print{} [ 1:0xfcc360] Op_plus_i : 0 [MALLOC|NUMCUR|NUMBER]
+@print{} [ 1:0xfcc220] Op_push_lhs : o [do_reference = true]
+@print{} [ 1:0xfcc300] Op_assign_plus :
+@print{} [ :0xfcc2c0] Op_pop :
+@print{} [ 1:0xfcc400] Op_push : O
+@print{} [ 1:0xfcc420] Op_push_i : "" [MALLOC|STRING|STRCUR]
+@print{} [ :0xfcc4a0] Op_no_op :
+@print{} [ 1:0xfcc480] Op_push : O
+@print{} [ :0xfcc4c0] Op_concat : [expr_count = 3] [concat_flag = 0]
+@print{} [ 1:0xfcc3c0] Op_store_var : x
+@print{} [ 1:0xfcc440] Op_push_lhs : X [do_reference = true]
+@print{} [ 1:0xfcc3a0] Op_postincrement :
+@print{} [ 1:0xfcc4e0] Op_push : x
+@print{} [ 1:0xfcc540] Op_push : o
+@print{} [ 1:0xfcc500] Op_plus :
+@print{} [ 1:0xfcc580] Op_push : o
+@print{} [ 1:0xfcc560] Op_plus :
+@print{} [ 1:0xfcc460] Op_leq :
+@print{} [ :0xfcc5c0] Op_jmp_false : [target_jmp = 0xfcc5e0]
+@print{} [ 1:0xfcc600] Op_push_i : "%c" [MALLOC|STRING|STRCUR]
+@print{} [ :0xfcc660] Op_no_op :
+@print{} [ 1:0xfcc520] Op_assign_concat : c
+@print{} [ :0xfcc620] Op_jmp : [target_jmp = 0xfcc440]
+@print{}
+@dots{}
+@print{}
+@print{} [ 2:0xfcc5a0] Op_K_printf : [expr_count = 17] [redir_type = ""]
+@print{} [ :0xfcc140] Op_no_op :
+@print{} [ :0xfcc1c0] Op_atexit :
+@print{} [ :0xfcc640] Op_stop :
+@print{} [ :0xfcc180] Op_no_op :
+@print{} [ :0xfcd150] Op_after_beginfile :
+@print{} [ :0xfcc160] Op_no_op :
+@print{} [ :0xfcc1a0] Op_after_endfile :
+gawk>
+@end smallexample
+
+@cindex comando del debugger, @code{exit}
+@cindex @code{exit}, comando del debugger
+@cindex uscire dal debugger
+@cindex debugger, uscire dal
+@item @code{exit}
+Esce dal debugger.
+Si veda la voce @samp{quit}, pi@`u avanti in quest'elenco.
+
+@cindex comando del debugger, @code{h} (alias per @code{help})
+@cindex comando del debugger, @code{help}
+@cindex @code{help}, comando del debugger
+@cindex @code{h}, comando del debugger (alias per @code{help})
+@item @code{help}
+@itemx @code{h}
+Stampa una lista di tutti i comandi del debugger di @command{gawk} con un breve
+sommario su come usarli. @samp{help @var{comando}} stampa l'informazione sul
+comando @var{comando}.
+
+@cindex comando del debugger, @code{l} (alias per @code{list})
+@cindex comando del debugger, @code{list}
+@cindex @code{list}, comando del debugger
+@cindex @code{l}, comando del debugger (alias per @code{list})
+@item @code{list} [@code{-} | @code{+} | @var{n} | @var{nome-file}@code{:}@var{n} | @var{n}--@var{m} | @var{funzione}]
+@itemx @code{l} [@code{-} | @code{+} | @var{n} | @var{nome-file}@code{:}@var{n} | @var{n}--@var{m} | @var{funzione}]
+Stampa le righe specificate (per default 15) dal file sorgente corrente
+o il file chiamato @var{nome-file}. I possibili argomenti di @code{list}
+sono i seguenti:
+
+@c nested table
+@table @asis
+@item @code{-} (Meno)
+Stampa righe prima delle ultime righe stampate.
+
+@item @code{+}
+Stampa righe dopo le ultime righe stampate.
+@code{list} senza argomenti fa la stessa cosa.
+
+@item @var{n}
+Stampa righe centrate attorno alla riga numero @var{n}.
+
+@item @var{n}--@var{m}
+Stampa righe dalla numero @var{n} alla numero @var{m}.
+
+@item @var{nome-file}@code{:}@var{n}
+Stampa righe centrate attorno alla riga numero @var{n} nel file sorgente
+@var{nome-file}. Questo comando pu@`o cambiare il file sorgente corrente.
+
+@item @var{funzione}
+Stampa righe centrate attorno all'inizio della funzione @var{function}.
+Questo comando pu@`o cambiare il file sorgente corrente.
+@end table
+
+@cindex comando del debugger, @code{q} (alias per @code{quit})
+@cindex comando del debugger, @code{quit}
+@cindex @code{quit}, comando del debugger
+@cindex @code{q}, comando del debugger (alias per @code{quit})
+@cindex uscire dal debugger
+@cindex debugger, uscire dal
+@item @code{quit}
+@itemx @code{q}
+Esce dal debugger. Fare il debug @`e divertente, ma noi tutti a volte
+dobbiamo far fronte ad altri impegni nella vita, e talvolta troviamo il bug
+e possiamo tranquillamente passare a quello successivo! Come abbiamo visto
+prima, se si sta eseguendo un programma, il debugger avverte quando si batte
+@samp{q} o @samp{quit}, in modo da essere sicuri di voler realmente abbandonare
+il debug.
+
+@cindex comando del debugger, @code{trace}
+@cindex @code{trace}, comando del debugger
+@item @code{trace} [@code{on} | @code{off}]
+Abilita o disabilita la stampa continua delle istruzioni che si stanno per
+eseguire, assieme alle righe di @command{awk} che implementano.
+L'impostazione di default @`e @code{off}.
+
+@`E auspicabile che la maggior parte dei ``codici operativi'' (o ``opcode'')
+in queste istruzioni siano sufficientemente autoesplicativi, e l'uso di
+@code{stepi} e @code{nexti} mentre @code{trace} @`e abilitato li render@`a
+familiari.
+
+@end table
+
+@node Supporto per Readline
+@section Supporto per Readline
+@cindex completamento dei comandi nel debugger
+@cindex espansione della cronologia, nel debugger
+@cindex debugger, completamento dei comandi nel
+
+Se @command{gawk} @`e compilato con
+@uref{http://cnswww.cns.cwru.edu/php/chet/readline/readline.html, la libreria
+GNU Readline}, ci si pu@`o avvantaggiare delle sue funzionalit@`a riguardanti il
+completamento dei comandi della libreria e l'espansione della cronologia. Sono
+disponibili i seguenti tipi di completamento:
+
+@table @asis
+@item Completamentto dei comandi
+Nomi dei comandi.
+
+@item Completamento del @value{FN} del sorgente
+@value{FFNS} dei sorgenti. I relativi comandi sono
+@code{break},
+@code{clear},
+@code{list},
+@code{tbreak}
+e
+@code{until}.
+
+@item Completamento di argomento
+Argomenti di un comando non numerici.
+I relativi comandi sono @code{enable} e @code{info}.
+
+@item Completamento del nome di variabile
+Interessa i nomi delle variabili globali, e gli argomenti di funzione nel
+contesto corrente se
+il programma @`e in esecuzione. I relativi comandi sono
+@code{display},
+@code{print},
+@code{set}
+e
+@code{watch}.
+
+@end table
+
+@node Limitazioni
+@section Limitazioni
+
+Si spera che il lettore trovi il debugger di @command{gawk} utile e piacevole
+da usare, ma come accade per ogni programma, specialmente nelle sue prime
+versioni, ha ancora delle limitazioni. Quelle di cui @`e bene essere al corrente sono:
+
+@itemize @value{BULLET}
+@item
+Nella versione presente, il debugger non d@`a una spiegazione dettagliata
+dell'errore che
+si @`e commesso quando si immette qualcosa che il debugger ritiene sbagliato.
+La risposta invece @`e solamente @samp{syntax error}. Quando si arriva a capire
+l'errore commesso, tuttavia, ci si sentir@`a come un vero guru.
+
+@item
+@c NOTE: no comma after the ref{} on purpose, due to following
+@c parenthetical remark.
+Se si studiano i ``dump'' dei codici operativi
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Comandi vari del debugger}
+(o se si ha gi@`a familiarit@`a con i comandi interni di @command{gawk}),
+ci si render@`a conto che gran parte della manipolaziona interna di dati
+in @command{gawk}, cos@`{@dotless{i}} come in molti interpreti, @`e fatta su di una pila.
+@code{Op_push}, @code{Op_pop}, e simili sono il pane quotidiano di
+gran parte del codice di @command{gawk}.
+
+Sfortunatamente, al momento, il debugger di @command{gawk} non consente
+di esaminare i contenuti della pila.
+Cio@`e, i risultati intermedi della valutazione delle espressioni sono sulla
+pila, ma non @`e possibile stamparli. Invece, possono essere stampate solo
+quelle variabili che sono state definite nel programma. Naturalmente, un
+espediente per cercare di rimediare @`e di usare pi@`u variabili esplicite in
+fase di debug e
+poi cambiarle di nuovo per ottenere un codice forse pi@`u difficile da
+comprendere, ma pi@`u ottimizzato.
+
+@item
+Non c'@`e alcun modo per guardare ``dentro'' al processo della compilazione delle
+espressioni regolari per vedere se corrispondono a quel che si intendeva.
+Come programmatore
+di @command{awk}, ci si aspetta che chi legge conosca il significato di
+@code{/[^[:alnum:][:blank:]]/}.
+
+@item
+Il debugger di @command{gawk} @`e progettato per essere usato eseguendo un
+programma (con tutti i suoi parametri) dalla riga di comando, come descritto
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Invocazione del debugger}. Non c'@`e alcun modo (al momento) di modificare
+o di ``entrare dentro'' l'esecuzione di un programma.
+Questo sembra ragionevole per un linguaggio che @`e usato principalmente per
+eseguire programmi piccoli e che non richiedono molto tempo di esecuzione.
+
+@item
+Il debugger di @command{gawk} accetta solo codice sorgente fornito con
+l'opzione @option{-f}.
+@end itemize
+
+@ignore
+@c 11/2016: This no longer applies after all the type cleanup work that's been done.
+C'@`e un altro punto che vale la pena di trattare. I debugger convenzionali
+vengono eseguiti in un processo (e quindi in una parte di memoria)
+separato dal programma su cui eseguono il debug (il @dfn{debuggato}, se
+si vuole).
+
+Il debugger di @command{gawk} @`e diverso; @`e parte integrante di @command{gawk}.
+Ci@`o rende possibile, in rari casi, che @command{gawk} diventi un eccellente
+dimostratore del principio d'indeterminazione di Heisenberg, secondo il quale
+il solo atto di osservare una cosa pu@`o modificarla. Si consideri il seguente
+esempio:@footnote{Grazie a Hermann Peifer per quest'esempio.}
+
+@example
+$ @kbd{cat test.awk}
+@print{} @{ print typeof($1), typeof($2) @}
+$ @kbd{cat test.data}
+@print{} abc 123
+$ @kbd{gawk -f test.awk test.data}
+@print{} strnum strnum
+@end example
+
+Questo @`e quel che ci si aspetta: il campo data ha l'attributo STRNUM
+(@pxref{Tipi di variabile}). Ora vediamo cosa accade quando questo programma
+viene eseguito sotto il debugger:
+
+@example
+$ @kbd{gawk -D -f test.awk test.data}
+gawk> @kbd{w $1} @ii{Imposta un punto d'osservazione su} $1
+@print{} Watchpoint 1: $1
+gawk> @kbd{w $2} @ii{Imposta il punto d'osservazione su} $2
+@print{} Watchpoint 2: $2
+gawk> @kbd{r} @ii{Avvia il programma}
+@print{} Partenza del programma:
+@print{} Mi fermo in Rule ...
+@print{} Watchpoint 1: $1 @ii{Scatta punto d'osservazione}
+@print{} Old value: ""
+@print{} New value: "abc"
+@print{} main() a `test.awk':1
+@print{} 1 @{ print typeof($1), typeof($2) @}
+gawk> @kbd{n} @ii{Prosegui @dots{}}
+@print{} Watchpoint 2: $2 @ii{Scatta punto d'osservazione}
+@print{} Old value: ""
+@print{} New value: "123"
+@print{} main() a `test.awk':1
+@print{} 1 @{ print typeof($1), typeof($2) @}
+gawk> @kbd{n} @ii{Prende il risultato da} typeof()
+@print{} strnum number @ii{Il risultato per} $2 @ii{non @`e corretto}
+@c "normally" o "abnormally" @`e in inglese senza possibilit@`a di modifiche.
+@print{} Programma completato normally, valore in uscita: 0
+gawk> @kbd{quit}
+@end example
+
+In questo caso, la richiesta di confrontare il nuovo valore di @code{$2}
+con quello vecchio ha richiesto che @command{gawk} lo valutasse e
+stabilisse che era proprio un numero, e questo @`e riflesso nel risultato di
+@code{typeof()}.
+
+Casi come questi in cui il debugger non @`e trasparente rispetto all'esecuzione
+del programma dovrebbero essere rari. Nel caso che se ne trovi uno, si
+prega di segnalarlo (@pxref{Bug}).
+@end ignore
+
+@ignore
+Look forward to a future release when these and other missing features may
+be added, and of course feel free to try to add them yourself!
+@end ignore
+
+@node Sommario sul debug
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+Raramente i programmi funzionano bene al primo colpo. Trovare gli errori
+che contengono
+viene chiamato @dfn{debugging}, e un programma che aiuta a trovarli @`e un
+@dfn{debugger}. @command{gawk} ha un debugger incorporato che funziona in
+modo molto simile al debugger GNU, GDB.
+
+@item
+I debugger possono eseguire il programma un'istruzione per volta, esaminare e
+cambiare i
+valori delle variabili e dei vettori, e fanno tante altre cose per
+permettere di comprendere cosa sta facendo effettivamente il programma in un
+dato momento (a differenza del comportamento atteso).
+
+@item
+Come la maggior parte dei debugger, il debugger di @command{gawk} funziona in
+termini di stack frame, e si possono inserire sia punti d'interruzione
+(interruzioni a un certo punto del codice) sia punti d'osservazione
+(interruzioni quando il valore di un dato cambia).
+
+@item
+La serie di comandi del debugger @`e abbastanza completa, e permette di
+monitorare i
+punti d'interruzione, l'esecuzione, la visualizzazione e la
+modifica dei dati, di lavorare con le pile, ottenere informazioni, e di
+svolgere altri compiti.
+
+@item
+Se la libreria GNU Readline @`e disponibile al momento della compilazione di
+@command{gawk}, viene usata dal debugger per fornire la cronologia della riga
+di comando e delle modifiche apportate durante il debug.
+
+@item
+Normalmente, il debugger non influenza il programma che sta controllando,
+ma questo pu@`o succedere occasionalmente.
+
+@end itemize
+
+@node Calcolo con precisione arbitraria
+@chapter Calcolo con precisione arbitraria con @command{gawk}
+@cindex precisione arbitraria
+@cindex precisione multipla
+@cindex precisione infinita
+@cindex virgola mobile, numeri in@comma{} precisione arbitraria
+
+In questo @value{CHAPTER} si introducono alcuni concetti base su come i
+computer
+eseguono i calcoli e si definiscono alcuni termini importanti.
+Si continua poi descrivendo il calcolo in virgola mobile,
+che @`e quello che @command{awk} usa per tutte le sue operazioni aritmetiche,
+e si prosegue con
+una trattazione del calcolo in virgola mobile con precisione arbitraria,
+una funzionalit@`a disponibile solo in @command{gawk}. Si passa poi a
+illustrare i numeri interi a precisione arbitraria e si conclude con una
+descrizione di alcuni punti sui quali @command{gawk} e lo standard POSIX non
+sono esattamente in accordo.
+
+@quotation NOTA
+La maggior parte degli utenti di @command{gawk} pu@`o saltare senza patemi
+d'animo
+questo capitolo. Tuttavia, se si vogliono eseguire calcoli scientifici con
+@command{gawk}, questo @`e il luogo adatto per imparare a farlo.
+@end quotation
+
+@menu
+* Aritmetica del computer:: Una rapida introduzione alla matematica del
+ computer.
+* Definizioni matematiche:: Definizione dei termini usati.
+* Funzionalit@`a MPFR:: Funzionalit@`a MPFR in @command{gawk}.
+* Cautela col calcolo in VM:: Cose da sapere.
+* Interi a precisione arbitraria:: Calcolo con numeri interi a precisione
+ arbitraria con @command{gawk}.
+* Problemi virgola mobile POSIX:: Confronto tra standard e uso corrente.
+* Sommario virgola mobile:: Sommario della trattazione della
+ virgola mobile.
+@end menu
+
+@node Aritmetica del computer
+@section Una descrizione generale dell'aritmetica del computer
+
+Sinora, abbiamo avuto a che fare con dati come numeri o stringhe. Ultimamente,
+comunque, i computer rappresentano ogni cosa in termini di @dfn{cifre binarie},
+o @dfn{bit}. Una cifra decimale pu@`o assumere uno di 10 valori: da zero a
+nove. Una cifra binaria pu@`o assumere uno di due valori: zero o uno. Usando
+il sistema binario, i computer (e i programmi per computer) possono
+rappresentare e manipolare dati numerici e dati costituiti da caratteri. In
+generale, tanti pi@`u bit @`e possibile usare per rappresentare una determinata
+cosa, tanto maggiore sar@`a l'intervallo dei possibili valori che essa potr@`a
+assumere.
+
+I moderni calcolatori possono eseguire calcoli numerici in almeno due modi, e
+spesso anche di pi@`u. Ogni tipo di calcolo usa una diversa rappresentazione
+(organizzazione dei bit) dei numeri. Le modalit@`a di calcolo che ci interessano
+sono:
+
+@table @asis
+@item Calcolo decimale
+Questo @`e il tipo di calcolo che s'impara alle scuole elementari, usando
+carta e penna (o anche una calcolatrice). In teoria, i numeri possono avere un
+numero arbitrario di cifre su ambo i lati del separatore decimale, e il
+risultato di un'operazione @`e sempre esatto.
+
+Alcuni sistemi moderni possono eseguire calcoli decimali direttamente,
+tramite apposite istruzioni disponibili
+nell'hardware dell'elaboratore, ma normalmente si ha necessit@`a di una speciale
+libreria software che consenta di effettuare le operazioni desiderate.
+Ci sono anche librerie che svolgono i calcoli decimali interamente
+per via software.
+
+Anche se alcuni utenti si aspettano che @command{gawk} effettui delle
+operazioni usando numeri in base decimale,@footnote{Non sappiamo perch@'e se
+lo aspettino, ma @`e cos@`{@dotless{i}}.} non @`e questo quello che succede.
+
+@item La matematica coi numeri interi
+A scuola ci hanno insegnato che i valori interi erano quei numeri privi di una
+parte frazionaria, come 1, 42, o @minus{}17.
+Il vantaggio dei numeri interi @`e che essi rappresentano dei valori in maniera
+esatta. Lo svantaggio @`e che i numeri rappresentabili sono limitati.
+
+@cindex senza segno, interi
+@cindex segno, interi senza
+@cindex interi senza segno
+Nei calcolatori, i valori interi sono di due tipi: @dfn{con segno} e
+@dfn{senza segno}. I valori con segno possono essere negativi o positivi,
+mentre i valori senza segno sono sempre maggiori o uguali a zero.
+
+Nei sistemi informatici, il calcolo con valori interi @`e esatto, ma il possibile
+campo di variazione dei valori @`e limitato. L'elaborazione con numeri interi @`e
+pi@`u veloce di quella con numeri a virgola mobile.
+
+@item La matematica coi numeri a virgola mobile
+I numeri a virgola mobile rappresentano quelli che a scuola sono chiamati
+numeri ``reali'' (cio@`e, quelli che hanno una parte frazionaria, come
+3.1415927). Il vantaggio dei numeri a virgola mobile @`e che essi possono
+rappresentare uno spettro di valori molto pi@`u ampio di quello rappresentato dai
+numeri interi. Lo svantaggio @`e che ci sono numeri che essi non possono
+rappresentare in modo esatto.
+
+I computer moderni possono eseguire calcoli su valori a virgola mobile
+nell'hardware dell'elaboratore, entro un intervallo di valori limitato.
+Ci sono inoltre librerie di programmi che consentono calcoli, usando numeri a
+virgola mobile, di precisione arbitraria.
+
+POSIX @command{awk} usa numeri a virgola mobile a @dfn{doppia precisione},
+che possono gestire pi@`u cifre rispetto ai numeri a virgola mobile a
+@dfn{singola precisione}. @command{gawk} ha inoltre funzionalit@`a, descritte
+in dettaglio pi@`u sotto, che lo mettono in grado di eseguire
+calcoli con i numeri a virgola mobile con precisione arbitraria.
+@end table
+
+I calcolatori operano con valori interi e a virgola mobile su diversi
+intervalli. I valori interi normalmente hanno una dimensione di 32 bit o 64 bit.
+I valori a virgola mobile a singola precisione occupano 32 bit, mentre i
+valori a virgola mobile a doppia precisione occupano 64 bit. I valori a
+virgola mobile sono sempre con segno. Il possibile campo di variazione dei
+valori @`e mostrato in @ref{table-numeric-ranges}.
+
+@float Tabella,table-numeric-ranges
+@caption{Intervalli dei valori per diverse rappresentazioni numeriche}
+@multitable @columnfractions .34 .33 .33
+@headitem Rappresentazione numerica @tab Valore minimo @tab Valore massimo
+@item Interi con segno a 32-bit @tab @minus{}2.147.483.648 @tab 2.147.483.647
+@item Interi senza segno a 32-bit @tab 0 @tab 4.294.967.295
+@item Interi con segno a 64-bit @tab @minus{}9.223.372.036.854.775.808 @tab 9.223.372.036.854.775.807
+@item Interi senza segno a 64-bit @tab 0 @tab 18.446.744.073.709.551.615
+@iftex
+@item Virgola mobile, singola precisione (circa) @tab @math{1,175494^{-38}} @tab @math{3,402823^{38}}
+@item Virgola mobile, doppia precisione (circa) @tab @math{2,225074^{-308}} @tab @math{1,797693^{308}}
+@end iftex
+@ifinfo
+@item Virgola mobile, singola precisione (circa) @tab 1,175494e-38 @tab 3,402823e38
+@item Virgola mobile, doppia precisione (circa) @tab 2,225074e-308 @tab 1,797693e308
+@end ifinfo
+@ifnottex
+@ifnotinfo
+@item Virgola mobile, singola precisione (circa) @tab 1,175494@sup{-38} @tab 3,402823@sup{38}
+@item Virgola mobile, singola precisione (circa) @tab 2,225074@sup{-308} @tab 1,797693@sup{308}
+@end ifnotinfo
+@end ifnottex
+@end multitable
+@end float
+
+@node Definizioni matematiche
+@section Altre cose da sapere
+
+Il resto di questo @value{CHAPTER} usa un certo numero di termini. Di seguito
+vengono date alcune definizioni informali che dovrebbero essere utili
+per la lettura di questo documento:
+
+@table @dfn
+@item Accuratezza
+L'accuratezza del calcolo sui numeri a virgola mobile indica di quanto si
+avvicina il calcolo al valore reale (calcolato con carta e penna).
+
+@item Errore
+La differenza tra quello che il risultato di un calcolo ``dovrebbe dare''
+e quello che effettivamente d@`a. @`E meglio minimizzare l'errore quanto pi@`u
+possibile.
+
+@item Esponente
+L'ordine di grandezza di un valore;
+alcuni bit in un valore a virgola mobile contengono l'esponente.
+
+@item Inf
+Un valore speciale che rappresenta l'infinito. Le operazioni tra un qualsiasi
+numero e l'infinito danno infinito.
+
+@item Mantissa
+Un valore a virgola mobile @`e formato dalla mantissa moltiplicata per 10
+alla potenza dell'esponente. Per esempio, in @code{1,2345e67},
+la mantissa @`e @code{1,2345}.
+
+@item Modalit@`a di arrotondamento
+Come i numeri vanno arrotondati, per eccesso o per difetto, quando necessario.
+Maggiori dettagli verranno forniti in seguito.
+
+@item NaN
+``Not a number'' (Non un Numero).@footnote{Grazie a Michael
+Brennan per questa descrizione, che abbiamo parafrasato, e per gli esempi.} Un
+valore speciale che risulta da un calcolo che non ha risposta come numero
+reale. In tal caso, i programmi possono o ricevere un'eccezione di virgola
+mobile, o restituire @code{NaN} come risultato. Lo standard IEEE 754
+consiglia che i sistemi restituiscano @code{NaN}. Alcuni esempi:
+
+@table @code
+@item sqrt(-1)
+La radice quadrata di @minus{}1 ha senso nell'insieme dei numeri complessi,
+ma non nell'insieme dei numeri reali,
+per cui il risultato @`e @code{NaN}.
+
+@item log(-8)
+Il logaritmo di @minus{}8 @`e fuori dal dominio di @code{log()},
+per cui il risultato @`e @code{NaN}.
+@end table
+
+@item Normalizzato (formato)
+Come la mantissa (vedi oltre in questa lista) @`e usualmente memorizzata. Il
+valore viene aggiustato in modo che il primo bit sia sempre uno,
+e in questo modo l'uno iniziale @`e supposto presente (per come viene
+generato il numero), ma non @`e memorizzato fisicamente.
+Questo fornisce un bit di precisione in pi@`u.
+
+@item Precisione
+Il numero di bit usati per rappresentare un numero a virgola mobile.
+Pi@`u sono i bit, e maggiore @`e l'intervallo di cifre che si possono
+rappresentare.
+Le precisioni binaria e decimale sono legate in modo approssimativo, secondo
+la formula:
+
+@display
+@iftex
+@math{prec = 3.322 @cdot dps}
+@end iftex
+@ifnottex
+@ifnotdocbook
+@var{prec} = 3.322 * @var{dps}
+@end ifnotdocbook
+@end ifnottex
+@docbook
+<emphasis>prec</emphasis> = 3.322 &sdot; <emphasis>dps</emphasis>
+@end docbook
+@end display
+
+@noindent
+Qui, @emph{prec} indica la precisione binaria
+(misurata in bit) e @emph{dps} (abbreviazione di "decimal places")
+indica le cifre decimali.
+
+@item Stabilit@`a
+Dal@uref{http://en.wikipedia.org/wiki/Numerical_stability,
+l'articolo di Wikipedia sulla stabilit@`a numerica}:
+``I calcoli per i quali si pu@`o dimostrare che non amplificano gli errori di
+approssimazione sono chiamati @dfn{numericamente stabili}.''
+@end table
+
+Si veda @uref{http://en.wikipedia.org/wiki/Accuracy_and_precision,
+l'articolo di Wikipedia su accuratezza e precisione} per maggiori informazioni
+su questi due termini.
+
+Sui computer moderni, l'unit@`a di calcolo in virgola mobile usa la
+rappresentazione e le operazioni definite dallo standard IEEE 754.
+Tre dei tipi definiti nello standard IEEE 754 sono:
+32-bit singola precisione,
+64-bit doppia precisione e
+128-bit quadrupla precisione.
+Lo standard specifica anche formati a precisione estesa
+per consentire una maggiore precisione e campi di variazione degli esponenti
+pi@`u ampi. (@command{awk} usa solo il formato a 64-bit doppia precisione.)
+
+@ref{table-ieee-formats} elenca la precisione e i valori di campo
+dell'esponente per i principali formati binari IEEE 754.
+
+@float Tabella,table-ieee-formats
+@caption{Valori per i principali formati IEEE}
+@multitable @columnfractions .20 .20 .20 .20 .20
+@headitem Nome @tab Bit totali @tab Precisione @tab Esponente minimo @tab Esponente massimo
+@item Singola @tab 32 @tab 24 @tab @minus{}126 @tab +127
+@item Doppia @tab 64 @tab 53 @tab @minus{}1022 @tab +1023
+@item Quadrupla @tab 128 @tab 113 @tab @minus{}16382 @tab +16383
+@end multitable
+@end float
+
+@quotation NOTA
+I numeri che descrivono la precisione includono la cifra 1 iniziale
+implicita, il che equivale ad avere un bit in pi@`u nella mantissa.
+@end quotation
+
+@node Funzionalit@`a MPFR
+@section Funzionalit@`a per il calcolo a precisione arbitraria in @command{gawk}
+
+Per default, @command{gawk} usa i valori in virgola mobile a doppia precisione
+disponibili nell'hardware del sistema su cui viene eseguito.
+Tuttavia, se @`e stato compilato in modo da includere questa funzionalit@`a
+ed @`e stata specificata
+l'opzione da riga di comando @option{-M}, @command{gawk} usa le librerie
+@uref{http://www.mpfr.org, GNU MPFR} e @uref{http://gmplib.org, GNU MP} (GMP)
+per effettuare calcoli sui numeri con una precisione arbitraria.
+Si pu@`o verificare se il supporto a MPFR @`e disponibile in questo modo:
+
+@example
+$ @kbd{gawk --version}
+@print{} GNU Awk 4.1.2, API: 1.1 (GNU MPFR 3.1.0-p3, GNU MP 5.0.2)
+@print{} Copyright (C) 1989, 1991-2015 Free Software Foundation.
+@dots{}
+@end example
+
+@noindent
+(I numeri di versione visualizzati possono essere diversi. Non importa;
+l'importante @`e che siano presenti GNU MPFR e GNU MP
+nel testo restituito.)
+
+Inoltre, ci sono alcuni elementi disponibili nel vettore @code{PROCINFO}
+per fornire informazioni sulle librerie MPFR e GMP
+(@pxref{Variabili auto-assegnate}).
+
+La libreria MPFR d@`a un controllo accurato sulle precisioni e sulle modalit@`a di
+arrotondamento, e d@`a risultati correttamente arrotondati, riproducibili e
+indipendenti dalla piattaforma. Con l'opzione da riga di comando @option{-M},
+tutti gli operatori aritmetici e le funzioni in virgola mobile possono
+produrre risultati a ogni livello di precisione supportato da MPFR.
+
+Due variabili predefinite, @code{PREC} e @code{ROUNDMODE},
+danno il controllo sulla precisione di elaborazione e sulla modalit@`a di
+arrotondamento. La precisione e la modalit@`a di arrotondamento sono impostate
+a livello globale per ogni operazione da eseguire.
+@xref{Impostare la precisione} e
+@iftex
+la
+@end iftex
+@ref{Impostare modi di arrotondare}
+per maggiori informazioni.
+
+@node Cautela col calcolo in VM
+@section Calcolo in virgola mobile: @dfn{Caveat Emptor}!
+
+@quotation
+@i{L'ora di matematica @`e ostica!}
+@author Teen Talk Barbie, luglio 1992
+@end quotation
+
+Questa @value{SECTION} fornisce un quadro dettagliato dei problemi che
+si presentano quando si eseguono molti calcoli in virgola
+mobile.@footnote{C'@`e un saggio molto bello
+@uref{http://www.validlab.com/goldberg/paper.pdf, sul calcolo in
+virgola mobile} di David Goldberg, ``What Every Computer Scientist Should Know
+About Floating-Point Arithmetic,''
+@cite{ACM Computing Surveys} @strong{23}, 1 (1991-03): 5-48. Vale la pena di
+leggerlo, se si @`e interessati a scendere nei dettagli, per@`o richiede delle
+conoscenze informatiche.}
+Le spiegazioni fornite valgono sia per il calcolo in virgola mobile
+effettuato direttamente dall'hardware del computer, sia per quello
+ottenuto tramite il software per la precisione arbitraria.
+
+@quotation ATTENZIONE
+Le informazioni fornite in questa sede sono deliberatamente di tipo generale.
+Se si devono eseguire calcoli complessi col computer, si dovrebbero prima
+ottenere ulteriori informazioni, e non basarsi solo su quanto qui detto.
+@end quotation
+
+@menu
+* Inesattezza nei calcoli:: La matematica in virgola mobile non @`e
+ esatta.
+* Ottenere la precisione:: Ottenere pi@`u precisione richiede qualche
+ sforzo.
+* Tentare di arrotondare:: Aggiungere cifre di precisione e arrotondare.
+* Impostare la precisione:: Come impostare la precisione.
+* Impostare modi di arrotondare:: Impostare le modalit@`a di arrotondamento.
+@end menu
+
+@node Inesattezza nei calcoli
+@subsection La matematica in virgola mobile non @`e esatta
+
+Le rappresentazioni e i calcoli con numeri a virgola mobile binari sono
+inesatti. Semplici valori come 0,1 non possono essere rappresentati in modo
+preciso usando numeri a virgola mobile binari, e la limitata precisione dei
+numeri a virgola mobile significa che piccoli cambiamenti nell'ordine delle
+operazioni o la precisione di memorizzazione di operazioni
+intermedie pu@`o cambiare il
+risultato. Per rendere la situazione pi@`u difficile, nel calcolo in virgola
+mobile con precisione arbitraria, si pu@`o impostare la precisione prima di
+eseguire un calcolo, per@`o non si pu@`o sapere con certezza quale sar@`a
+il numero di cifre decimali esatte nel risultato finale.
+
+@menu
+* Rappresentazioni inesatte:: I numeri non sono rappresentati esattamente.
+* Confronti tra valori in VM:: Come confrontare valori in virgola mobile.
+* Gli errori si sommano:: Gli errori diventano sempre maggiori.
+@end menu
+
+@node Rappresentazioni inesatte
+@subsubsection Molti numeri non possono essere rappresentati esattamente
+
+Perci@`o, prima di iniziare a scrivere del codice, si dovrebbe pensare
+al risultato che si vuole effettivamente ottenere e a cosa realmente accade.
+Si considerino i due numeri nel seguente esempio:
+
+@example
+x = 0.875 # 1/2 + 1/4 + 1/8
+y = 0.425
+@end example
+
+Diversamente dal numero in @code{y}, il numero memorizzato in @code{x}
+@`e rappresentabile esattamente nel formato binario, perch@'e pu@`o essere
+scritto come somma finita di una o pi@`u frazioni i cui denominatori sono tutti
+multipli di due.
+Quando @command{gawk} legge un numero a virgola mobile dal sorgente di un
+programma, arrotonda automaticamente quel numero alla precisione, quale che
+sia, supportata dal computer in uso. Se si tenta di stampare il contenuto
+numerico di una variabile usando una stringa di formato in uscita di
+@code{"%.17g"}, il valore restituito pu@`o non essere lo stesso numero assegnato
+a quella variabile:
+
+@example
+$ @kbd{gawk 'BEGIN @{ x = 0.875; y = 0.425}
+> @kbd{ printf("%0.17g, %0.17g\n", x, y) @}'}
+@print{} 0.875, 0.42499999999999999
+@end example
+
+Spesso l'errore @`e talmente piccolo da non essere neppure notato, e se @`e stato
+notato, si pu@`o sempre specificare il grado di precisione si vuole nell'output.
+In genere questo @`e una stringa di formato come @code{"%.15g"} che, se usata
+nell'esempio precedente, d@`a luogo a un output identico all'input.
+
+@node Confronti tra valori in VM
+@subsubsection Fare attenzione quando si confrontano valori
+
+Poich@'e la rappresentazione interna del computer
+pu@`o discostarsi, sia pur di poco, dal valore
+esatto, confrontare dei valori a virgola mobile per vedere se sono esattamente
+uguali @`e generalmente una pessima idea. Questo @`e un esempio in cui tale
+confronto non funziona come dovrebbe:
+
+@example
+$ @kbd{gawk 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'}
+@print{} 0
+@end example
+
+Il metodo generalmente seguito per confrontare valori a virgola mobile
+consiste nel controllare se la differenza tra loro @`e minore di un certo valore
+(chiamato @dfn{delta}, o @dfn{tolleranza}). Quel che si deve decidere @`e qual
+@`e il valore minimo di delta
+adeguato. Il codice per far ci@`o @`e qualcosa del genere:
+
+@example
+delta = 0.00001 # per esempio
+differenza = abs(a) - abs(b) # sottrazione dei due valori
+if (differenza < delta)
+ # va bene
+else
+ # non va bene
+@end example
+
+@noindent
+(Si presuppone che sia stata definita in qualche parte del programma una
+semplice funzione che restituisce il valore assoluto di un numero,
+chiamata @code{abs()}.)
+
+@node Gli errori si sommano
+@subsubsection Gli errori diventano sempre maggiori
+
+La perdita di accuratezza in un singolo calcolo con numeri a virgola mobile
+generalmente non dovrebbe destare preoccupazione. Tuttavia, se si calcola un
+valore che @`e una sequenza di operazioni in virgola mobile, l'errore si pu@`o
+accumulare e influire sensibilmente sul risultato del calcolo stesso.
+Qui sotto vediamo un tentativo di calcolare il valore di @value{PI} usando
+una delle sue rappresentazioni
+come somma di una serie di numeri:
+
+@example
+BEGIN @{
+ x = 1.0 / sqrt(3.0)
+ n = 6
+ for (i = 1; i < 30; i++) @{
+ n = n * 2.0
+ x = (sqrt(x * x + 1) - 1) / x
+ printf("%.15f\n", n * x)
+ @}
+@}
+@end example
+
+Quando viene eseguito, gli errori iniziali si propagano nei calcoli
+successivi, facendo terminare il ciclo prematuramente dopo un tentativo di
+divisione per zero:
+
+@example
+$ @kbd{gawk -f pi.awk}
+@print{} 3.215390309173475
+@print{} 3.159659942097510
+@print{} 3.146086215131467
+@print{} 3.142714599645573
+@dots{}
+@print{} 3.224515243534819
+@print{} 2.791117213058638
+@print{} 0.000000000000000
+@error{} gawk: pi.awk:6: fatale: tentativo di dividere per zero
+@end example
+
+Ecco un altro esempio in cui l'inaccuratezza nelle rappresentazioni interne
+porta a un risultato inatteso:
+
+@example
+$ @kbd{gawk 'BEGIN @{}
+> @kbd{for (d = 1.1; d <= 1.5; d += 0.1) # esegue il ciclo cinque volte (?)}
+> @kbd{i++}
+> @kbd{print i}
+> @kbd{@}'}
+@print{} 4
+@end example
+
+@node Ottenere la precisione
+@subsection Ottenere la precisione voluta
+
+Pu@`o il calcolo con precisione arbitraria dare risultati esatti? Non ci sono
+risposte facili. Le regole standard dell'algebra spesso non valgono
+nei calcoli con precisione arbitraria.
+Tra le altre cose, le leggi distributiva e associativa non sono rispettate
+completamente, e l'ordine dell'operazione pu@`o essere importante per
+il calcolo.
+Errori di arrotondamento, perdite di precisione che si accumulano, e
+valori molto vicini allo zero sono spesso causa di problemi.
+
+Quando @command{gawk} verifica l'eguaglianza delle espressioni
+@samp{0.1 + 12.2} e @samp{12.3} usando l'aritmetica a doppia precisione della
+macchina, decide che non sono uguali! (@xref{Confronti tra valori in VM}.)
+Si pu@`o ottenere il risultato cercato aumentando la precisione; 56 bit in
+questo caso sono sufficienti:
+
+@example
+$ @kbd{gawk -M -v PREC=56 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'}
+@print{} 1
+@end example
+
+Se aggiungere pi@`u bit @`e una buona cosa, aggiungerne ancora di pi@`u
+@`e meglio?
+Ecco cosa succede se si usa un valore di @code{PREC} ancora pi@`u alto:
+
+@example
+$ @kbd{gawk -M -v PREC=201 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'}
+@print{} 0
+@end example
+
+Non @`e un bug di @command{gawk} o della libreria MPFR.
+@`E facile dimenticare che il numero finito di bit usato per memorizzare il
+valore spesso @`e solo un'approssimazione dopo un opportuno arrotondamento. Il
+test di uguaglianza riesce se e solo se @emph{tutti} i bit dei due operandi
+sono esattamente gli stessi. Poich@'e questo non @`e necessariamente vero dopo un
+calcolo in virgola mobile con una determinata precisione e con una modalit@`a di
+arrotondamento valida, un test di eguaglianza convenzionale potrebbe non
+riuscire. Invece, il test riesce confrontando i due numeri per vedere se la
+differenza tra di loro rientra in un delta accettabile.
+
+In applicazioni dove sono sufficienti fino a 15 cifre decimali,
+il calcolo in doppia precisione eseguito dall'hardware del computer
+pu@`o essere una buona soluzione,
+e in genere @`e pi@`u veloce. Per@`o bisogna tener presente che ogni operazione in
+virgola mobile pu@`o subire un nuovo errore di arrotondamento con conseguenze
+catastrofiche, come si @`e visto nel precedente tentativo di calcolare il valore
+di @value{PI}.
+In tali casi una precisione supplementare pu@`o aumentare la stabilit@`a e
+l'accuratezza del calcolo.
+
+Oltre a ci@`o, bisogna tenere conto del fatto che
+addizioni ripetute non sono necessariamente equivalenti a una moltiplicazione
+nell'aritmetica in virgola mobile. Nell'esempio visto in
+@ref{Gli errori si sommano}:
+
+@example
+$ @kbd{gawk 'BEGIN @{}
+> @kbd{for (d = 1.1; d <= 1.5; d += 0.1) # ciclo eseguito cinque volte (?)}
+> @kbd{i++}
+> @kbd{print i}
+> @kbd{@}'}
+@print{} 4
+@end example
+
+@noindent
+non @`e detto che, scegliendo per @code{PREC} un valore arbitrariamente alto, si
+riesca a ottenere il risultato corretto. La riformulazione del problema in
+questione @`e spesso il modo corretto di comportari in tali situazioni.
+
+@node Tentare di arrotondare
+@subsection Tentare di aggiungere bit di precisione e arrotondare
+
+Invece dell'aritmetica in virgola mobile con precisione arbitraria,
+spesso tutto ci@`o di cui si ha bisogno @`e un aggiustamento della logica
+o di un diverso ordine delle operazioni nei calcoli.
+La stabilit@`a e l'accuratezza del calcolo di @value{PI}
+nel primo esempio possono essere migliorata usando la seguente semplice
+trasformazione algebrica:
+
+@example
+(sqrt(x * x + 1) - 1) / x @equiv{} x / (sqrt(x * x + 1) + 1)
+@end example
+
+@noindent
+Dopo aver fatto questo cambiamento, il programma converge verso
+@value{PI} in meno di 30 iterazioni:
+
+@example
+$ @kbd{gawk -f pi2.awk}
+@print{} 3.215390309173473
+@print{} 3.159659942097501
+@print{} 3.146086215131436
+@print{} 3.142714599645370
+@print{} 3.141873049979825
+@dots{}
+@print{} 3.141592653589797
+@print{} 3.141592653589797
+@end example
+
+@node Impostare la precisione
+@subsection Impostare la precisione
+
+@command{gawk} usa una precisione di lavoro a livello globale; non tiene
+traccia della precisione e accuratezza dei singoli numeri. Eseguendo
+un'operazione aritmetica o chiamando una funzione predefinita, il risultato
+viene arrotondato alla precisione di lavoro. La precisione di lavoro di default
+@`e di 53 bit, modificabile usando la variabile predefinita @code{PREC}. Si pu@`o
+anche impostare il valore a una delle stringhe predefinite (non importa se
+scritte in maiuscolo o minuscolo) elencate in
+@ref{table-predefined-precision-strings},
+per emulare un formato binario che segue lo standard IEEE 754.
+
+@float Tabella,table-predefined-precision-strings
+@caption{Stringhe di precisione predefinita per @code{PREC}}
+@multitable {@code{"double"}} {12345678901234567890123456789012345}
+@headitem @code{PREC} @tab formato binario IEEE 754
+@item @code{"half"} @tab 16-bit mezza precisione
+@item @code{"single"} @tab 32-bit singole precisione di base
+@item @code{"double"} @tab 64-bit doppia precisione di base
+@item @code{"quad"} @tab 128-bit quadrupla precisione di base
+@item @code{"oct"} @tab 256-bit ottupla precisione
+@end multitable
+@end float
+
+Il seguente esempio illustra gli effetti del cambiamento di precisione
+sulle operazioni aritmetiche:
+
+@example
+$ @kbd{gawk -M -v PREC=100 'BEGIN @{ x = 1.0e-400; print x + 0}
+> @kbd{PREC = "double"; print x + 0 @}'}
+@print{} 1e-400
+@print{} 0
+@end example
+
+@quotation ATTENZIONE
+Diffidare delle costanti in virgola mobile! Quando si legge una costante in
+virgola mobile dal codice sorgente di un programma, @command{gawk} usa la
+precisione di default (quella del formato @code{double} di C), a meno che non
+venga richiesto, tramite la variabile speciale @code{PREC} fornita
+sulla riga di comando, di memorizzarla internamente come un numero MPFR.
+Cambiare la precisione tramite @code{PREC} nel testo del programma @emph{non}
+cambia la precisione di una costante.
+
+Se si deve rappresentare una costante in virgola mobile con una precisione
+maggiore di quella di default e non @`e possibile usare un assegnamento a
+@code{PREC} da riga di comando, si dovrebbe definire la costante o come
+stringa, o come numero razionale, ove possibile. L'esempio seguente illustra le
+differenze tra i diversi modi di stampare una costante in virgola mobile:
+
+@example
+$ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", 0.1) @}'}
+@print{} 0.1000000000000000055511151
+$ @kbd{gawk -M -v PREC=113 'BEGIN @{ printf("%0.25f\n", 0.1) @}'}
+@print{} 0.1000000000000000000000000
+$ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", "0.1") @}'}
+@print{} 0.1000000000000000000000000
+$ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", 1/10) @}'}
+@print{} 0.1000000000000000000000000
+@end example
+@end quotation
+
+@node Impostare modi di arrotondare
+@subsection Impostare la modalit@`a di arrotondamento
+
+La variabile @code{ROUNDMODE} permette di controllare a livello di programma
+la modalit@`a di arrotondamento.
+La corrispondenza tra @code{ROUNDMODE} e le modalit@`a di arrotondamento IEEE
+@`e mostrata in @ref{table-gawk-rounding-modes}.
+
+@float Tabella,table-gawk-rounding-modes
+@caption{Modalit@`a di arrotondamento in @command{gawk} }
+@multitable @columnfractions .45 .30 .25
+@headitem Modalit@`a di arrotondamento @tab Nome IEEE @tab @code{ROUNDMODE}
+@item Arrotonda al pi@`u vicino, o a un numero pari @tab @code{roundTiesToEven} @tab @code{"N"} o @code{"n"}
+@item Arrotonda verso infinito @tab @code{roundTowardPositive} @tab @code{"U"} o @code{"u"}
+@item Arrotonda verso meno infinito @tab @code{roundTowardNegative} @tab @code{"D"} o @code{"d"}
+@item Arrotonda verso zero (troncamento) @tab @code{roundTowardZero} @tab @code{"Z"} o @code{"z"}
+@item Arrotonda al pi@`u vicino, o per eccesso @tab @code{roundTiesToAway} @tab @code{"A"} o @code{"a"}
+@end multitable
+@end float
+
+@code{ROUNDMODE} ha @code{"N"} come valore di default, ovvero si usa la
+modalit@`a di arrotondamento IEEE 754 @code{roundTiesToEven}.
+In @ref{table-gawk-rounding-modes}, il valore @code{"A"} seleziona
+@code{roundTiesToAway}. Questo @`e applicabile solo se la versione in uso
+della libreria MPFR lo supporta; altrimenti, l'impostazione di @code{ROUNDMODE}
+ad @code{"A"} non ha alcun effetto.
+
+La modalit@`a di default @code{roundTiesToEven} @`e la pi@`u preferita, ma allo
+stesso tempo
+la meno intuitiva. Questo metodo fa la cosa ovvia per la maggior parte dei
+valori, arrotondandoli per eccesso o per difetto alla cifra pi@`u prossima.
+Per esempio, arrotondando 1.132 alle due cifre decimali si ottiene 1.13,
+e 1.157 viene arrotondato a 1.16.
+
+Tuttavia, se si deve arrotondare un valore posto esattamente a met@`a strada,
+le cose non funzionano come probabilmente si insegna a scuola.
+In questo caso, il numero @`e arrotondato alla cifra @emph{pari} pi@`u prossima.
+Cos@`{@dotless{i}} arrotondando 0.125 alle due cifre si arrotonda per difetto a 0.12,
+ma arrotondando 0.6875 alle tre cifre si arrotonda per eccesso a 0.688.
+Probabilmente ci si @`e gi@`a imbattuti in questa modalit@`a di arrotondamento
+usando @code{printf} per formattare numeri a virgola mobile.
+Per esempio:
+
+@example
+BEGIN @{
+ x = -4.5
+ for (i = 1; i < 10; i++) @{
+ x += 1.0
+ printf("%4.1f => %2.0f\n", x, x)
+ @}
+@}
+@end example
+
+@noindent
+produce il seguente output quando viene eseguito sul sistema
+dell'autore:@footnote{@`E possibile che l'output sia completamente diverso, se la
+libreria C presente nel sistema in uso non si conforma, per @code{printf},
+alla regola IEEE 754
+di arrotondamento al valore pari in caso di equidistanza.}
+
+@example
+-3.5 => -4
+-2.5 => -2
+-1.5 => -2
+-0.5 => 0
+ 0.5 => 0
+ 1.5 => 2
+ 2.5 => 2
+ 3.5 => 4
+ 4.5 => 4
+@end example
+
+La teoria che sta dietro alla regola
+@code{roundTiesToEven} @`e che gli arrotondamenti di
+valori equidistanti in eccesso e in difetto si distribuiscono pi@`u o meno
+uniformemente, con la possibile conseguenza che errori di arrotondamento
+ripetuti tendono ad annullarsi a vicenda. Questa @`e la modalit@`a di
+arrotondamento di default per funzioni e operatori di calcolo secondo IEEE 754.
+
+Le altre modalit@`a di arrotondamento sono usate raramente. Gli arrotondamenti
+verso l'infinito (@code{roundTowardPositive}) e verso il meno infinito
+(@code{roundTowardNegative}) vengono spesso usati per eseguire calcoli su
+intervalli, dove si adotta questa modalit@`a di arrotondamento per calcolare
+i limiti superiore e inferiore per l'intervallo di valori in uscita.
+La modalit@`a
+@code{roundTowardZero} pu@`o essere usata per convertire numeri a virgola mobile
+in numeri interi. La modalit@`a di arrotondamento @code{roundTiesToAway}
+arrotonda il risultato al numero pi@`u vicino, e in caso di equidistanza
+arrotonda per eccesso.
+
+Qualche esperto di analisi numerica dir@`a che la scelta dello stile di
+arrotondamento ha un grandissimo impatto sul risultato finale, e consiglier@`a
+di attendere sino al risultato finale dopo ogni arrotondamento. Invece,
+spesso si possono evitare problemi legati a errori di arrotondamento
+impostando all'inizio la precisione a un valore sufficientemente maggiore
+della precisione desiderata, in modo che il cumulo degli errori di
+arrotondamento non influisca sul
+risultato finale. Se si ha il dubbio che i risultati del calcolo contengano
+un'accumulazione di errori di arrotondamento, occorre, per accertare la cosa,
+controllare se si verifica una differenza significativa nell'output
+cambiando la modalit@`a di arrotondamento.
+
+@node Interi a precisione arbitraria
+@section Aritmetica dei numeri interi a precisione arbitraria con @command{gawk}
+@cindex numeri interi a precisione arbitraria
+@cindex interi a precisione arbitraria
+@cindex precisione arbitraria, interi a
+
+Quando viene specificata l'opzione @option{-M},
+@command{gawk} esegue tutti i calcoli sui numeri interi usando gli interi a
+precisione arbitraria della libreria GMP. Qualsiasi numero che appaia come un
+intero in un sorgente o in un @value{DF} @`e memorizzato come intero a precisione
+arbitraria. La dimensione del numero intero ha come limite solo la memoria
+disponibile. Per esempio, il seguente programma calcola
+@iftex
+@math{5^{4^{3^{2}}}},
+@end iftex
+@ifinfo
+5^4^3^2,
+@end ifinfo
+@ifnottex
+@ifnotinfo
+5@sup{4@sup{3@sup{2}}},
+@end ifnotinfo
+@end ifnottex
+il cui risultato @`e oltre i limiti degli ordinari valori a virgola mobile a
+doppia precisione dei processori:
+
+@example
+$ @kbd{gawk -M 'BEGIN @{}
+> @kbd{x = 5^4^3^2}
+> @kbd{print "numero di cifre =", length(x)}
+> @kbd{print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20)}
+> @kbd{@}'}
+@print{} numero di cifre = 183231
+@print{} 62060698786608744707 ... 92256259918212890625
+@end example
+
+Se invece si dovesse calcolare lo stesso valore usando valori a virgola mobile
+con precisione arbitraria, la precisione necessaria per il risultato corretto
+(usando
+la formula
+@iftex
+@math{prec = 3.322 @cdot dps})
+sarebbe @math{3.322 @cdot 183231},
+@end iftex
+@ifnottex
+@ifnotdocbook
+@samp{prec = 3.322 * dps})
+sarebbe 3.322 x 183231,
+@end ifnotdocbook
+@end ifnottex
+@docbook
+<emphasis>prec</emphasis> = 3.322 &sdot; <emphasis>dps</emphasis>)
+would be
+<emphasis>prec</emphasis> = 3.322 &sdot; 183231,
+@end docbook
+o 608693.
+
+Il risultato di un'operazione aritmetica tra un intero e un valore a virgola
+mobile @`e un valore a virgola mobile con precisione uguale alla precisione di
+lavoro. Il seguente programma calcola l'ottavo termine nella successione di
+Sylvester@footnote{Weisstein, Eric W.
+@cite{Sylvester's Sequence}. From MathWorld---A Wolfram Web Resource
+@w{(@url{http://mathworld.wolfram.com/SylvestersSequence.html}).}}
+usando una ricorrenza:
+
+@example
+$ @kbd{gawk -M 'BEGIN @{}
+> @kbd{s = 2.0}
+> @kbd{for (i = 1; i <= 7; i++)}
+> @kbd{s = s * (s - 1) + 1}
+> @kbd{print s}
+> @kbd{@}'}
+@print{} 113423713055421845118910464
+@end example
+
+Il risultato mostrato differisce dal numero effettivo,
+113.423.713.055.421.844.361.000.443,
+perch@'e la precisione di default di 53 bit non @`e suffciente per rappresentare
+esattamente il risultato in virgola mobile. Si pu@`o o aumentare la precisione
+(in questo caso bastano 100 bit), o sostituire la costante in virgola mobile
+@samp{2.0} con un intero, per eseguire tutti i calcoli usando l'aritmetica con
+gli interi per ottenere l'output corretto.
+
+A volte @command{gawk} deve convertire implicitamente un intero con precisione
+arbitraria in un valore a virgola mobile con precisione arbitraria.
+Ci@`o si rende necessario
+principalmente perch@'e la libreria MPFR non sempre prevede l'interfaccia
+necessaria per elaborare interi a precisione arbitraria o numeri di tipo
+eterogeneo come richiesto da un'operazione o funzione. In tal caso, la
+precisione viene impostata al minimo valore necessario per una conversione
+esatta, e non viene usata la precisione di lavoro. Se
+questo non @`e quello di cui si ha bisogno o che si vuole, si pu@`o ricorrere a un
+sotterfugio e convertire preventivamente l'intero in un valore a virgola
+mobile, come qui di seguito:
+
+@example
+gawk -M 'BEGIN @{ n = 13; print (n + 0.0) % 2.0 @}'
+@end example
+
+Si pu@`o evitare completamente questo passaggio specificando il numero come
+valore a virgola mobile fin dall'inizio:
+
+@example
+gawk -M 'BEGIN @{ n = 13.0; print n % 2.0 @}'
+@end example
+
+Si noti che, per questo specifico esempio, probabilmente @`e meglio
+semplicemente specificare:
+
+@example
+gawk -M 'BEGIN @{ n = 13; print n % 2 @}'
+@end example
+
+Dividendo due interi a precisione arbitraria con @samp{/} o con @samp{%}, il
+risultato @`e tipicamente un valore a virgola mobile con precisione arbitraria
+(a meno che il risultato non sia un numero intero esatto).
+Per eseguire divisioni intere o calcolare moduli con interi a precisione
+arbitraria, usare la funzione predefinita
+@code{intdiv()} (@pxref{Funzioni numeriche}).
+
+Si pu@`o simulare la funzione @code{intdiv()} in @command{awk} standard
+usando questa funzione definita dall'utente:
+
+@example
+@c file eg/lib/intdiv.awk
+# intdiv --- fa una divisione intera
+
+@c endfile
+@ignore
+@c file eg/lib/intdiv.awk
+#
+# Arnold Robbins, arnold@@skeeve.com, Public Domain
+# July, 2014
+#
+# Name changed from div() to intdiv()
+# April, 2015
+
+@c endfile
+
+@end ignore
+@c file eg/lib/intdiv.awk
+function intdiv(numerator, denominator, result)
+@{
+ split("", result)
+
+ numerator = int(numerator)
+ denominator = int(denominator)
+ result["quotient"] = int(numerator / denominator)
+ result["remainder"] = int(numerator % denominator)
+
+ return 0.0
+@}
+@c endfile
+@end example
+
+Il seguente programma d'esempio, proposto da Katie Wasserman,
+usa @code{intdiv()} per
+calcolare le cifre di @value{PI} al numero di cifre significative
+che si @`e scelto di impostare:
+
+@example
+@c file eg/prog/pi.awk
+# pi.awk --- calcola le cifre di pi
+@c endfile
+@c endfile
+@ignore
+@c file eg/prog/pi.awk
+#
+# Katie Wasserman, katie@@wass.net
+# August 2014
+@c endfile
+@end ignore
+@c file eg/prog/pi.awk
+
+BEGIN @{
+ cifre = 100000
+ due = 2 * 10 ^ cifre
+ pi = due
+ for (m = cifre * 4; m > 0; --m) @{
+ d = m * 2 + 1
+ x = pi * m
+ intdiv(x, d, risultato)
+ pi = risultato["quotient"]
+ pi = pi + due
+ @}
+ print pi
+@}
+@c endfile
+@end example
+
+@ignore
+Date: Wed, 20 Aug 2014 10:19:11 -0400
+To: arnold@skeeve.com
+From: Katherine Wasserman <katie@wass.net>
+Subject: Re: computation of digits of pi?
+
+Arnold,
+
+>The program that you sent to compute the digits of pi using div(). Is
+>that some standard algorithm that every math student knows? If so,
+>what's it called?
+
+It's not that well known but it's not that obscure either
+
+It's Euler's modification to Newton's method for calculating pi.
+
+Take a look at lines (23) - (25) here: http://mathworld.wolfram.com/PiFormulas.htm
+
+The algorithm I wrote simply expands the multiply by 2 and works from the innermost expression outwards. I used this to program HP calculators because it's quite easy to modify for tiny memory devices with smallish word sizes.
+
+http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899
+
+-Katie
+@end ignore
+
+Quando gli fu chiesto dell'algoritmo usato, Katie rispose:
+
+@quotation
+Non @`e quello pi@`u noto ma nemmeno quello pi@`u incomprensibile.
+@`E la variante di Eulero al metodo di Newton per il calcolo del Pi greco.
+Si vedano le righe (23) - (25) nel sito:
+@uref{http://mathworld.wolfram.com/PiFormulas.html}.
+
+L'algoritmo che ho scritto semplicemente espande il moltiplicare per 2 e
+lavora dall'espressione pi@`u interna verso l'esterno. Ho usato questo per
+programmare delle calcolatrici HP perch@'e @`e piuttosto facile da adattare ai
+dispositivi di scarsa memoria con dimensioni di parola piuttosto piccole.
+Si veda
+@uref{http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899}.
+@end quotation
+
+@node Problemi virgola mobile POSIX
+@section Confronto tra standard e uso corrente
+
+Per diverso tempo, @command{awk} ha convertito le stringhe dall'aspetto non
+numerico nel valore numerico zero, quando richiesto. Per di pi@`u, la
+definizione originaria del linguaggio e lo standard POSIX originale prevedevano
+che @command{awk} riconoscesse solo i numeri decimali (base 10), e non i numeri
+ottali (base 8) o esadecimali (base 16).
+
+Le modifiche nel linguaggio degli standard POSIX 2001 e 2004 possono essere
+interpretate nel senso che @command{awk} debba fornire delle funzionalit@`a
+aggiuntive. Queste sono:
+
+@itemize @value{BULLET}
+@item
+Interpretazione del valore dei dati a virgola mobile specificati in notazione
+esadecimale (p.es., @code{0xDEADBEEF}). (Da notare: valore dei dati letti,
+@emph{non} costanti facenti parte del codice sorgente.)
+
+@item
+Supporto per i valori a virgola mobile speciali IEEE 754 ``not a number''
+(NaN), pi@`u infinito (``inf'') e meno infinito (``@minus{}inf'').
+In particolare, il formato per questi valori @`e quello specificato dallo
+standard C ISO 1999, che non distingue maiuscole/minuscole e pu@`o consentire
+caratteri aggiuntivi dipendenti dall'implementazione dopo il @samp{nan}, e
+consentire o @samp{inf} o @samp{infinity}.
+@end itemize
+
+Il primo problema @`e che entrambe le modifiche sono deviazioni evidenti
+dalla prassi consolidata:
+
+@itemize @value{BULLET}
+@item
+Il manutentore di @command{gawk} crede che supportare i valori a virgola mobile
+esadecimali, nello specifico, sia sbagliato, e che non sia mai stata intenzione
+dell'autore originale di introdurlo nel linguaggio.
+
+@item
+Consentire che stringhe completamente alfabetiche abbiano valori numerici
+validi @`e anch'essa una deviazione molto marcata dalla prassi consolidata.
+@end itemize
+
+Il secondo problema @`e che il manutentore di @command{gawk} crede che questa
+interpretazione dello standard, che richiede una certa dimestichezza col
+linguaggio giuridico per essere compresa, non sempre @`e stata
+colta dai normali sviluppatori. In altre parole, ``Sappiamo come siete
+arrivati sin qui, ma non pensiamo che questo sia il posto dove volete essere.''
+
+Recependo queste argomentazioni, e cercando nel contempo di assicurare la
+compatibilit@`a con le versioni precedenti dello standard, lo standard POSIX 2008
+ha aggiunto delle formulazioni esplicite per consentire l'uso da parte di
+@command{awk}, solo a richiesta, dei valori a virgola mobile esadecimali e
+dei valori speciali
+``@dfn{not a number}'' e infinito.
+
+Sebbene il manutentore di @command{gawk} continui a credere che introdurre
+queste funzionalit@`a sia sconsigliabile, ci@`o nonostante, sui sistemi che
+supportano i valori in virgola mobile IEEE, sembra giusto fornire
+@emph{qualche}
+possibilit@`a di usare i valori NaN e infinito. La soluzione implementata
+in @command{gawk} @`e questa:
+
+@itemize @value{BULLET}
+@item
+Se @`e stata specificata l'opzione da riga di comando @option{--posix},
+@command{gawk} non
+interviene. I valori di stringa sono passati direttamente alla funzione
+@code{strtod()} della libreria di sistema, e se quest'ultima restituisce
+senza errori un valore numerico,
+esso viene usato.@footnote{L'avete voluto, tenetevelo.}
+Per definizione, i risultati non sono portabili su diversi sistemi;
+e sono anche piuttosto sorprendenti:
+
+@example
+$ @kbd{echo nanny | gawk --posix '@{ print $1 + 0 @}'}
+@print{} nan
+$ @kbd{echo 0xDeadBeef | gawk --posix '@{ print $1 + 0 @}'}
+@print{} 3735928559
+@end example
+
+@item
+Senza l'opzione @option{--posix}, @command{gawk} interpreta i quattro valori di stringa
+@samp{+inf},
+@samp{-inf},
+@samp{+nan}
+e
+@samp{-nan}
+in modo speciale, producendo i corrispondenti valori numerici speciali.
+Il segno iniziale serve per segnalare a @command{gawk} (e all'utente)
+che il valore @`e realmente numerico. I numeri a virgola mobile esadecimali
+non sono consentiti (a meno di non usare anche @option{--non-decimal-data},
+che @emph{non} @`e consigliabile). Per esempio:
+
+@example
+$ @kbd{echo nanny | gawk '@{ print $1 + 0 @}'}
+@print{} 0
+$ @kbd{echo +nan | gawk '@{ print $1 + 0 @}'}
+@print{} nan
+$ @kbd{echo 0xDeadBeef | gawk '@{ print $1 + 0 @}'}
+@print{} 0
+@end example
+
+@command{gawk} ignora la distinzione maiuscole/minuscole nei quattro valori
+speciali. Cos@`{@dotless{i}}, @samp{+nan} e @samp{+NaN} sono la stessa cosa.
+@end itemize
+
+@node Sommario virgola mobile
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+La maggior parte dell'aritmetica al calcolatore @`e fatta usando numeri interi
+oppure
+valori a virgola mobile. L'@command{awk} standard usa valori a virgola mobile
+a doppia precisione.
+
+@item
+Nei primi anni '90 Barbie disse erroneamente, ``L'ora di matematica @`e
+ostica!'' Sebbene la matematica non sia ostica, l'aritmetica a virgola
+mobile non @`e proprio come la
+matematica ``carta e penna'', e bisogna prestare attenzione:
+
+@c nested list
+@itemize @value{MINUS}
+@item
+Non tutti i numeri possono essere rappresentati in modo esatto.
+
+@item
+Per confrontare dei valori bisognerebbe usare un delta, invece di farlo
+direttamente con @samp{==} e @samp{!=}.
+
+@item
+Gli errori si accumulano.
+
+@item
+Le operazioni non sempre sono esattamente associative o distributive.
+@end itemize
+
+@item
+Aumentare l'accuratezza pu@`o essere d'aiuto, ma non @`e una panacea.
+
+@item
+Spesso, aumentare la precisione e poi arrotondare al numero di cifre
+desiderato produce risultati soddisfacenti.
+
+@item
+Specificare l'opzione @option{-M} (o @option{--bignum}) per abilitare
+il calcolo MPFR.
+Usare @code{PREC} per impostare la precisione in bit, e
+@code{ROUNDMODE} per impostare la modalit@`a di arrotondamento tra quelle
+previste nello standard IEEE 754.
+
+@item
+Specificando l'opzione @option{-M}, @command{gawk} esegue calcoli su interi a precisione
+arbitraria usando la libreria GMP. In tal modo si ha una maggiore velocit@`a e
+una pi@`u efficiente allocazione dello spazio rispetto all'uso di MPFR per
+eseguire gli stessi calcoli.
+
+@item
+Ci sono diverse aree per quanto attiene ai numeri a virgola mobile in cui
+@command{gawk} @`e in disaccordo con lo standard POSIX.
+@`E importante averlo ben presente.
+
+@item
+In generale, non vi @`e alcun bisogno di essere eccessivamente diffidenti verso i
+risultati del calcolo in virgola mobile. La lezione da ricordare @`e che
+il calcolo in virgola mobile @`e sempre pi@`u complesso di quello che si fa con
+carta e penna. Per trarre vantaggio dalla potenza del calcolo in virgola
+mobile, bisogna conoscere i suoi limiti e stare all'interno di essi.
+Per la maggior parte degli usi occasionali del calcolo in virgola mobile, si
+possono ottenere i risultati attesi semplicemente arrotondando la
+visualizzazione dei risultati finali al giusto numero di cifre decimali
+significative.
+
+@item
+Come consiglio generale, evitare di rappresentare dati numerici in maniera
+tale da far sembrare che la precisione sia maggiore di quella effettivamente
+necessaria.
+
+@end itemize
+
+@node Estensioni dinamiche
+@chapter Scrivere estensioni per @command{gawk}
+@cindex estensioni caricate dinamicamente
+@cindex dinamiche, estensioni
+
+@`E possibile aggiungere nuove funzioni, scritte in C o C++, a @command{gawk}
+usando librerie caricate dinamicamente. Questa funzionalit@`a @`e disponibile
+su sistemi che supportano le funzioni C @code{dlopen()} e @code{dlsym()}.
+Questo @value{CHAPTER} descrive come creare estensioni usando codice scritto
+in C o C++.
+
+Chi @`e completamente digiuno di programmazione in C pu@`o tranquillamente
+saltare questo @value{CHAPTER}, ma potrebbe valer la pena di dare un'occhiata
+alla documentazione sulle estensioni che sono installate insieme a
+@command{gawk} (@pxref{Esempi di estensione}),
+e alle informazioni sul progetto @code{gawkextlib} (@pxref{gawkextlib}).
+Gli esempi di estensione sono automaticamente compilati e installati quando
+si installa @command{gawk}.
+
+@quotation NOTA
+Se si specifica l'opzione @option{--sandbox}, le estensioni non sono
+disponibili
+(@pxref{Opzioni}).
+@end quotation
+
+@menu
+* Introduzione alle estensioni:: Cos'@`e un'estensione.
+* Licenza delle estensioni:: Una nota riguardo al tipo di licenza.
+* Panoramica sul meccanismo delle estensioni:: Una panoramica sul meccanismo
+ delle estensioni.
+* Descrizione dell'API delle estensioni:: Una descrizione completa dell'API.
+* Trovare le estensioni:: Come @command{gawk} trova le estensioni
+ compilate.
+* Esempio di estensione:: Esempio di codice C di un'estensione.
+* Esempi di estensione:: Le estensioni di esempio incluse con
+ @command{gawk}.
+* gawkextlib:: Il progetto @code{gawkextlib}.
+* Sommario delle estensioni:: Sommario delle estensioni.
+* Esercizi sulle estensioni:: Esercizi.
+@end menu
+
+@node Introduzione alle estensioni
+@section Cos'@`e un'estensione
+
+@cindex plug-in
+Un'@dfn{estensione} (talora chiamata @dfn{plug-in}) @`e un frammento di codice
+compilato esternamente che @command{gawk} pu@`o caricare in fase di esecuzione
+per ottenere funzionalit@`a ulteriori, che vanno ad aggiungersi a quelle di
+@command{gawk} descritte nel resto di questo @value{DOCUMENT}.
+
+Le estensioni sono utili perch@'e consentono (ovviamente) di estendere le
+funzionalit@`a di @command{gawk}. Per esempio, possono permettere l'uso di
+@dfn{chiamate di sistema} (come @code{chdir()} per cambiare directory)
+e di altre routine di libreria C potenzialmente utili. Come per la maggior
+parte del software, ``il cielo @`e il limite''; se si riesce a immaginare
+qualcosa che si vuol fare e che @`e possibile programmare in C o C++,
+si pu@`o scrivere un'estensione che lo faccia!
+
+Le estensioni sono scritte in C o C++, usando l'API (@dfn{Application
+Programming Interface}) definita per questo scopo dagli sviluppatori di
+@command{gawk}. Il resto di questo @value{CHAPTER} descrive
+le possibilit@`a offerte dall'API e come usarle,
+e illustra una piccola estensione di esempio. Inoltre, sono documentati
+gli esempi di estensione inclusi nella distribuzione di @command{gawk}
+e viene descritto il progetto @code{gawkextlib}.
+@ifclear FOR_PRINT
+@xref{Progetto delle estensioni}, per una disamina degli obiettivi e del
+progetto del meccanismo delle estensioni.
+@end ifclear
+@ifset FOR_PRINT
+Si veda @uref{http://www.gnu.org/software/gawk/manual/html_node/estensione-Design.html}
+per una disamina degli obiettivi e del
+progetto del meccanismo delle estensioni.
+@end ifset
+
+@node Licenza delle estensioni
+@section Tipo di licenza delle estensioni
+
+Ogni estensione dinamica dev'essere distribuita in base a una licenza che sia
+compatibile con la licenza GNU GPL (@pxref{Copia}).
+
+Per far sapere a @command{gawk} che la licenza @`e quella corretta,
+l'estensione deve definire il simbolo globale
+@code{plugin_is_GPL_compatibile}. Se tale simbolo non @`e stato definito,
+@command{gawk} termina con un messaggio di errore fatale al momento del
+caricamente dell'estensione.
+
+Il tipo dichiarato per il suddetto simbolo dev'essere @code{int}. Esso non
+deve tuttavia essere presente in ogni sezione allocata.
+Il controllo in essere si limita a constatare che quel simbolo esiste a
+livello globale.
+Qualcosa del genere pu@`o essere sufficiente:
+
+@example
+int plugin_is_GPL_compatible;
+@end example
+
+@node Panoramica sul meccanismo delle estensioni
+@section Una panoramica sul funzionamento ad alto livello
+
+La comunicazione tra
+@command{gawk} e un'estensione @`e bidirezionale. Dapprima, quando
+un'estensione @`e caricata, @command{gawk} le passa un puntatore a una struttura
+(@code{struct}) i cui campi sono dei puntatori di funzione.
+@ifnotdocbook
+Questo si pu@`o vedere in @ref{figura-carica-estensione}.
+@end ifnotdocbook
+@ifdocbook
+Questo si pu@`o vedere in @inlineraw{docbook, <xref linkend="figura-carica-estensione"/>}.
+@end ifdocbook
+
+@ifnotdocbook
+@float Figura,figura-carica-estensione
+@caption{Caricamento dell'estensione}
+@ifclear SMALLPRINT
+@center @image{api-figura1, , , Caricamento dell'estensione}
+@end ifclear
+@ifset SMALLPRINT
+@center @image{api-figura1, 11cm, , Caricamento dell'estensione}
+@end ifset
+
+@end float
+@end ifnotdocbook
+
+@docbook
+<figure id="figura-carica-estensione" float="0">
+<title>Caricamento dell'estensione</title>
+<mediaobject>
+<imageobject role="web"><imagedata fileref="api-figura1.png" format="PNG"/></imageobject>
+</mediaobject>
+</figure>
+@end docbook
+
+L'estensione @`e in grado di chiamare funzioni all'interno di @command{gawk}
+utilizzando questi puntatori a funzione, in fase di esecuzione, senza aver
+bisogno di accedere (in fase di compilazione), ai simboli di @command{gawk}.
+Uno di questi puntatori a funzione punta a una funzione che serve per
+``registrare'' nuove funzioni.
+@ifnotdocbook
+Questo @`e mostrato in @ref{figura-registrare-una-nuova-funzione}.
+@end ifnotdocbook
+@ifdocbook
+Questo @`e shown in @inlineraw{docbook, <xref linkend="figura-registrare-una-nuova-funzione"/>}.
+@end ifdocbook
+
+@ifnotdocbook
+@float Figura,figura-registrare-una-nuova-funzione
+@caption{Registrare una nuova funzione}
+@ifclear SMALLPRINT
+@center @image{api-figura2, , , Registrare una nuova funzione}
+@end ifclear
+@ifset SMALLPRINT
+@center @image{api-figura2, 11cm , , Registrare una nuova funzione}
+@end ifset
+@end float
+@end ifnotdocbook
+
+@docbook
+<figure id="figura-registrare-una-nuova-funzione" float="0">
+<title>Registering a new function</title>
+<mediaobject>
+<imageobject role="web"><imagedata fileref="api-figura2.png" format="PNG"/></imageobject>
+</mediaobject>
+</figure>
+@end docbook
+
+Nella direzione opposta, l'estensione registra le sue nuove funzioni
+con @command{gawk} passando dei puntatori che puntano alle funzioni che
+implementano la nuova funzionalit@`a, (p.es. @code{do_chdir()}). @command{gawk}
+associa il puntatore a funzione con un nome ed @`e in grado di chiamarlo in
+seguito, usando una convenzione di chiamata predefinita.
+@ifnotdocbook
+Questo @`e mostrato in @ref{figura-chiamata-nuova-funzione}.
+@end ifnotdocbook
+@ifdocbook
+Questo @`e mostrato in @inlineraw{docbook, <xref linkend="figura-chiamata-nuova-funzione"/>}.
+@end ifdocbook
+
+@ifnotdocbook
+@float Figura,figura-chiamata-nuova-funzione
+@caption{Chiamata della nuova funzione}
+@ifclear SMALLPRINT
+@center @image{api-figura3, , , Chiamata della nuova funzione}
+@end ifclear
+@ifset SMALLPRINT
+@center @image{api-figura3,11cm , , Chiamata della nuova funzione}
+@end ifset
+@end float
+@end ifnotdocbook
+
+@docbook
+<figure id="figura-chiamata-nuova-funzione" float="0">
+<title>Chiamata della nuova funzione</title>
+<mediaobject>
+<imageobject role="web"><imagedata fileref="api-figura3.png" format="PNG"/></imageobject>
+</mediaobject>
+</figure>
+@end docbook
+
+La funzione @code{do_@var{xxx}()}, a sua volta, utilizza i puntatori a
+funzione nella struttura (@code{struct}) API per svolgere il proprio compito,
+come aggiornare variabili o vettori, stampare messaggi, impostare la
+variabile @code{ERRNO}, e cos@`{@dotless{i}} via.
+
+Delle macro di servizio rendono la chiamata effettuata utilizzando
+i puntatori simile a quella delle funzioni normali, in modo che il codice
+sorgente delle estensioni rimanga sufficientemente leggibile e comprensibile.
+
+Sebbene tutto ci@`o possa sembrare piuttosto complesso, il risultato @`e che il
+codice sorgente dell'estensione @`e abbastanza intuitivo da scrivere e da
+leggere. Lo si pu@`o constatare nell'estensione di esempio
+@file{filefuncs.c}
+(@pxref{Esempio di estensione}), come pure nel codice @file{testext.c},
+che testa l'interfaccia di programmazione (API).
+
+Ecco alcuni ulteriori dettagli:
+
+@itemize @value{BULLET}
+@item
+L'API fornisce accesso ai valori delle variabili @command{gawk}
+@code{do_@var{xxx}}, che memorizzano opzioni della riga di comando come
+@code{do_lint}, @code{do_profiling}, e cos@`{@dotless{i}} via (@pxref{Variabili dell'estensione API}).
+Questi valori sono solo informativi: un'estensione non pu@`o modificarli
+all'interno di @command{gawk}. Oltre a ci@`o, il tentativo di assegnare loro
+dei valori produce un errore quando l'estensione viene compilata.
+
+@item
+L'API fornisce anche i numeri che identificano la specifica versione di
+@command{gawk}, in modo che un'estensione possa controllare se il
+comando @command{gawk} che l'ha caricata @`e in grado di supportare le
+funzionalit@`a utilizzate nell'estensione. (Discrepanze tra le versioni
+``non dovrebbero'' accadere, ma si sa come vanno @emph{queste} cose.)
+@xref{Versione dell'estensione} per ulteriori dettagli.
+@end itemize
+
+@node Descrizione dell'API delle estensioni
+@section Una descrizione completa dell'API
+@cindex estensioni, API delle
+@cindex API, delle estensioni
+
+Il codice sorgente scritto in C o C++ per un'estensione deve includere il
+file di intestazione
+@file{gawkapi.h}, che dichiara le funzioni e definisce i tipi di dati
+usati per comunicare con @command{gawk}.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+(non breve) @value{SECTION} descrive l'API in detttaglio.
+
+@menu
+* Intro funzioni API delle estensioni:: Introduzione alle funzioni dell'API.
+* Tipi di dati generali:: I tipi di dati.
+* Funzioni di allocazione memoria:: Funzioni per allocare memoria.
+* Funzioni di costruzione:: Funzioni per creare valori.
+* Funzioni di registrazione:: Funzioni per registrare cose con
+ @command{gawk}.
+* Stampare messaggi:: Funzioni per stampare messaggi.
+* Aggiornare @code{ERRNO}:: Funzioni per aggiornare @code{ERRNO}.
+* Richiedere valori:: Come ottenere un valore.
+* Accedere ai parametri:: Funzioni per accedere ai parametri.
+* Accedere alla tabella simboli:: Funzioni per accedere alle variabili
+ globali
+* Manipolazione di vettori:: Funzioni per lavorare coi vettori.
+* Ridirezione API:: Come accedere alla ridirezioni e
+ modificarle.
+* Variabili dell'estensione API:: Variabili fornite dall'API.
+* Codice predefinito di un'estensione API:: Codice predefinito di
+ interfaccia API.
+* Modifiche dalla versione API 1:: Modifiche dalla versione 1 dell'API.
+@end menu
+
+@node Intro funzioni API delle estensioni
+@subsection Introduzione alle funzioni dell'API
+
+L'accesso a funzionalit@`a interne a @command{gawk} @`e effettuato
+con una chiamata che usa i puntatori a funzione resi disponibili
+all'estensione.
+
+Puntatori a funzioni API sono previsti per i seguenti tipi di operazioni:
+
+@itemize @value{BULLET}
+@item
+Allocare, riallocare e liberare memoria.
+
+@item
+Registrare funzioni. Si possono registrare:
+
+@c nested list
+@itemize @value{MINUS}
+@item
+Funzioni di estensione
+@item
+Funzioni ausiliarie di pulizia (@dfn{callbacks})
+@item
+Una stringa di caratteri che identifica la versione
+@item
+Funzioni per analizzare l'input
+@item
+Funzioni per modificare l'output
+@item
+Processori bidirezionali
+@end itemize
+
+Tutti questi elementi sono spiegati dettagliatamente nel resto di questo @value{CHAPTER}.
+
+@item
+Stampare messaggi fatali, di avvertimento e quelli generati dall'opzione
+``lint''.
+
+@item
+Modificare @code{ERRNO} o annullarne il valore.
+
+@item
+Accedere a parametri, compresa la possibilit@`a di definire come vettore
+un parametro ancora indefinito.
+
+@item
+Accedere alla "tabella dei simboli": procurarsi il valore di una variabile
+globale, crearne una nuova o modificarne una gi@`a esistente.
+
+@item
+Creare ed eliminare valori nascosti; ci@`o rende possibile usare un
+particolare valore per pi@`u di una variabile, e pu@`o migliorare parecchio
+le prestazioni.
+
+@item
+Manipolare vettori:
+
+@itemize @value{MINUS}
+@item
+Ritrovare il valore di elementi del vettore, aggiungerne di nuovi,
+cancellare e modificare elementi esistenti.
+
+@item
+Ottenere il numero di elementi presenti in un vettore
+
+@item
+Creare un nuovo vettore
+
+@item
+Cancellare un intero vettore
+
+@item
+Appiattire un vettore per poter facilmente eseguire un ciclo, in stile C,
+su tutti i suoi indici ed elementi
+@end itemize
+
+@item
+Accedere a ridirezioni e manipolarle.
+
+@end itemize
+
+Alcune osservazioni riguardo all'uso dell'API:
+
+@itemize @value{BULLET}
+@item
+I seguenti tipi di variabili, macro e/o funzioni sono resi disponibili
+nel file @file{gawkapi.h}. Perch@'e siano utilizzabili, i rispettivi file di
+intestazione standard indicati devono essere stati specificati @emph{prima}
+di includere @file{gawkapi.h}:
+
+@c FIXME: Make this as a float at some point.
+@multitable {@code{memset()}, @code{memcpy()}} {@code{<sys/types.h>}}
+@headitem Elemento C @tab File d'intestazione
+@item @code{EOF} @tab @code{<stdio.h>}
+@item valori di @code{errno} @tab @code{<errno.h>}
+@item @code{FILE} @tab @code{<stdio.h>}
+@item @code{NULL} @tab @code{<stddef.h>}
+@item @code{memcpy()} @tab @code{<string.h>}
+@item @code{memset()} @tab @code{<string.h>}
+@item @code{size_t} @tab @code{<sys/types.h>}
+@item @code{struct stat} @tab @code{<sys/stat.h>}
+@end multitable
+
+Per ragioni di portabilit@`a, specialmente per sistemi
+che non sono interamente aderenti agli standard, occorre assicurarsi di
+includere i file corretti nel modo corretto. Questa richiesta mira
+a mantenere il file @file{gawkapi.h} ordinato, invece che farlo diventare
+un'accozzaglia di problemi di portabilit@`a, quale si pu@`o vedere in alcune
+parti del codice sorgente di @command{gawk}.
+
+@item
+Il file @file{gawkapi.h} pu@`o essere incluso pi@`u volte, senza conseguenze
+negative. Tuttavia sarebbe meglio evitare di farlo, per uno
+stile di programmazione migliore.
+
+@item
+Sebbene l'API usi solo funzionalit@`a ISO C 90, c'@`e un'eccezione; le funzione
+``costruttrici'' usano la parola chiave @code{inline}. Se il compilatore in
+uso non supporta questa parola chiave, si dovrebbe specificare sulla
+riga di comando il parametro @samp{-Dinline=''} oppure usare gli strumenti
+Autotools GNU e includere un file
+@file{config.h} nel codice sorgente delle estensioni.
+
+@item
+Tutti i puntatori messi a disposizione da @command{gawk} puntano ad aree
+di memoria gestite da @command{gawk} e dovrebbero essere trattati
+dall'estensione come in sola lettura. Le aree di memoria che contengono @emph{tutte} le stringhe passate a
+@command{gawk} dall'estensione @emph{devono} provenire da una chiamata a
+@code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()},
+e sono gestite da @command{gawk} da quel punto in avanti.
+
+@item
+L'API definisce parecchie semplici @code{struct} che mappano dei valori
+come sono visti da @command{awk}. Un valore pu@`o essere un numero @code{double}
+(a virgola mobile, in doppia precisione), una stringa o un
+vettore (come @`e il caso per i vettori multidimensionali o nella creazione di
+un nuovo vettore).
+
+I valori di tipo stringa sono costituiti da un puntatore e da una lunghezza,
+poich@'e nella stringa possono essere presenti dei caratteri @sc{nul}
+(zeri binari, che normalmente marcano la fine di una stringa).
+
+@quotation NOTA
+Di proposito, @command{gawk} immagazzina le stringhe usando la codifica
+multibyte correntemente in uso (come definita dalle variabili d'ambiente
+@env{LC_@var{xxx}}) e non usando dei caratteri larghi (ovvero due byte per
+ogni carattere). Ci@`o riflette il modo con cui @command{gawk} memorizza le
+stringhe internamente, e anche il modo in cui i caratteri sono
+verosimilmente letti dai file in input e scritti nei file in output.
+@end quotation
+
+@quotation NOTA
+I valori di una stringa passati a un'estensione da @command{gawk} hanno
+sempre un carattere @sc{nul} alla fine (come delimitatore). Quindi @`e
+possibile usare senza inconvenienti tali valori di stringa per chiamare
+funzioni di libreria standard e routine di sistema. Tuttavia, poich@'e
+@command{gawk} consente che all'interno di una stringa di dati possano
+essere presenti caratteri @sc{nul}, si dovrebbe controllare che la
+lunghezza di ogni stringa passata un'estensione coincida con il valore
+restituito dalla funzione @code{strlen()} per la stringa stessa.
+@end quotation
+
+@item
+Per ottenere un valore (p.es. quello di un parametro o quello di una
+variabile globale, oppure di un elemento di un vettore), l'estensione chiede
+un tipo specifico di variabile (numero, stringa,
+scalare, @dfn{value cookie} [si veda pi@`u avanti], vettore o ``undefined'').
+Quando la richiesta @`e
+``undefined,'' il valore restituito sar@`a quello originale della variabile in
+questione.
+
+In ogni caso, se la richiesta e il tipo effettivo della variabile non
+corrispondono, la funzione di accesso restituisce ``false'' e fornisce il
+tipo proprio della variabile, in modo che l'estensione possa, p.es.,
+stampare un messaggio di errore
+(del tipo ``ricevuto uno scalare, invece del vettore previsto'').
+
+@c This is documented in the header file and needs some expanding upon.
+@c The table there should be presented here
+@end itemize
+
+Si possono chiamare le funzioni dell'API usando i puntatori a funzione
+direttamente, ma l'interfaccia non @`e molto elegante. Per permettere al
+codice sorgente delle estensioni di assomigliare di pi@`u a un codice normale,
+il file di intestazione @file{gawkapi.h} definisce parecchie
+macro da usare nel codice sorgente dell'estensione.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} presenta le macro come se si trattasse di funzioni.
+
+@node Tipi di dati generali
+@subsection I tipi di dati di impiego generale
+
+@cindex Robbins, Arnold
+@cindex Ramey, Chet
+@quotation
+@i{Ho un vero rapporto di amore/odio con le @dfn{unioni}.}
+@author Arnold Robbins
+@end quotation
+
+@quotation
+@i{Questo @`e ci@`o che contraddistingue le @dfn{unioni}: il compilatore @`e
+in grado di accomodare le cose in modo da far coesistere amore e odio.}
+@author Chet Ramey
+@end quotation
+
+L'estensione API definisce un certo numero di semplici tipi di dato e
+strutture di uso generale. Ulteriori strutture di dati, pi@`u specializzate,
+saranno introdotte
+@ifnotinfo
+nelle successive
+@end ifnotinfo
+@ifinfo
+nei successivi
+@end ifinfo
+@value{SECTIONS}, insieme alle funzioni che ne fanno uso.
+
+I tipi di dati e le strutture di uso generale sono le seguenti:
+
+@table @code
+@item typedef void *awk_ext_id_t;
+Un valore di questo tipo @`e trasmesso da @command{gawk} a un'estensione nel
+momento in cui viene caricata. Tale valore dev'essere restituito
+a @command{gawk} come primo parametro di ogni funzione API.
+
+@item #define awk_const @dots{}
+Questa macro genera delle @samp{costanti} nel momento in cui si compila
+un'estensione, e non genera nulla quando si compila il comando @command{gawk}
+vero e proprio. Ci@`o rende alcuni
+campi nelle strutture dei dati dell'API non alterabili dal codice sorgente
+dell'estensione, ma consente al comando @command{gawk} di usarle secondo
+necessit@`a.
+
+@item typedef enum awk_bool @{
+@itemx @ @ @ @ awk_false = 0,
+@itemx @ @ @ @ awk_true
+@itemx @} awk_bool_t;
+Un semplice tipo di variabile booleana.
+
+@item typedef struct awk_string @{
+@itemx @ @ @ @ char *str;@ @ @ @ @ /* dati veri e propri */
+@itemx @ @ @ @ size_t len;@ @ @ @ /* lunghezza degli stessi, in caratteri */
+@itemx @} awk_string_t;
+Questo rappresenta una stringa modificabile. @command{gawk} @`e responsabile
+per la gestione della memoria utilizzata, se ha fornito il valore della
+stringa. Altrimenti, assume il possesso della memoria in questione.
+@emph{Questa memoria dev'essere resa disponibile chiamando una delle funzioni
+@code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()}!}
+
+Come gi@`a detto, la rappresentazione delle stringhe in memoria usa la codifica
+multibyte corrente.
+
+@item typedef enum @{
+@itemx @ @ @ @ AWK_UNDEFINED,
+@itemx @ @ @ @ AWK_NUMBER,
+@itemx @ @ @ @ AWK_STRING,
+@itemx @ @ @ @ AWK_REGEX,
+@itemx @ @ @ @ AWK_STRNUM,
+@itemx @ @ @ @ AWK_ARRAY,
+@itemx @ @ @ @ AWK_SCALAR,@ @ @ @ @ @ @ @ @ /* accesso opaco a una variabile */
+@itemx @ @ @ @ AWK_VALUE_COOKIE@ @ @ @ /* per aggiornare un valore
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ gi@`a creato */
+@itemx @} awk_valtype_t;
+L'elenco @code{enum} indica di che tipo @`e un certo valore.
+@`E usato nella seguente struttura @code{struct}.
+
+@item typedef struct awk_value @{
+@itemx @ @ @ @ awk_valtype_t val_type;
+@itemx @ @ @ @ union @{
+@itemx @ @ @ @ @ @ @ @ awk_string_t@ @ @ @ @ @ @ s;
+@itemx @ @ @ @ @ @ @ @ double@ @ @ @ @ @ @ @ @ @ @ @ @ d;
+@itemx @ @ @ @ @ @ @ @ awk_array_t@ @ @ @ @ @ @ @ a;
+@itemx @ @ @ @ @ @ @ @ awk_scalar_t@ @ @ @ @ @ @ scl;
+@itemx @ @ @ @ @ @ @ @ awk_value_cookie_t@ vc;
+@itemx @ @ @ @ @} u;
+@itemx @} awk_value_t;
+Un ``valore di @command{awk}''.
+Il campo @code{val_type} indica che tipo di valore @code{union} contiene,
+e ogni campo @`e del tipo appropriato.
+
+@item #define str_value@ @ @ @ @ @ u.s
+@itemx #define strnum_value@ @ @ str_value
+@itemx #define regex_value@ @ @ @ str_value
+@itemx #define num_value@ @ @ @ @ @ u.d
+@itemx #define array_cookie@ @ @ u.a
+@itemx #define scalar_cookie@ @ u.scl
+@itemx #define value_cookie@ @ @ u.vc
+L'uso di queste macro rende pi@`u facile da seguire l'accesso ai campi di
+@code{awk_value_t}.
+
+@item typedef void *awk_scalar_t;
+La variabili scalari possono essere rappresentate da un tipo opaco. Questi
+valori sono ottenuti da @command{gawk} e in seguito gli vengono restituiti.
+Questo argomento @`e discusso in maniera generale nel testo che segue questa
+lista, e pi@`u in dettaglio
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Tabella simboli tramite cookie}.
+
+@item typedef void *awk_value_cookie_t;
+Un ``@dfn{value cookie}'' @`e un tipo di variabile opaca, e
+rappresenta un valore nascosto.
+Anche questo argomento @`e discusso in maniera generale nel testo che segue
+questa lista, e pi@`u in dettaglio
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Valori nascosti}.
+
+@end table
+
+I valori di tipo scalare in @command{awk} sono numeri, stringhe, @dfn{strnum}
+o @dfn{regexp} fortemente tipizzate.
+La struttura @code{awk_value_t} rappresenta valori.
+Il campo @code{val_type} indica cosa contiene @code{union}.
+
+Rappresentare numeri @`e facile: l'API usa una variabile C di tipo
+@code{double}. Le stringhe richiedono
+uno sforzo maggiore. Poich@'e
+@command{gawk} consente che le stringhe contengano dei byte @sc{nul}
+(a zeri binari) nel valore di una stringa, una stringa dev'essere
+rappresentata da una coppia di campi che contengono il puntatore al dato vero
+e proprio e la lunghezza della stringa.
+@`E questo @`e il tipo @code{awk_string_t}.
+
+Un valore di tipo @dfn{strnum} (stringa numerica) @`e rappresentato come una
+stringa e consiste di dati in input forniti dall'utente che appaiono essere
+numerici.
+Quando una funzione di estensione crea un valore di tipo @dfn{strnum}, il
+risultato @`e una stringa che viene marcata come immessa dall'utente. La
+successiva analisi da parte di @command{gawk} servir@`a poi a determinare se
+la stringa appare essere un numero, e va quindi trattata come @dfn{strnum},
+invece che come una normale stringa di caratteri.
+
+Ci@`o @`e utile nei casi un cui una funzione di estensione desideri fare qualcosa
+di paragonabile alla funzione @code{split}, la quale imposta l'attributo
+di @dfn{strnum} agli elementi di vettore che crea.
+Per esempio, un'estensione che implementi la divisione di record CSV
+(Comma Separated Values, i cui elementi sono delimitati da virgole)
+potrebbe voler usare questa funzionalit@`a. Un'altra situazione in cui ci@`o
+@`e utile @`e quello di una funzione che richieda campi-dati ad una banca di
+dati. La funzione @code{PQgetvalue()} della banca dati PostgreSQ, per
+esempio, restituisce una stringa che pu@`o essere numerica o di tipo carattere,
+a seconda del contesto.
+
+I valori di @dfn{regexp} fortemente tipizzate
+(@pxref{Costanti @dfn{regexp} forti} non sono molto utili nelle funzioni di
+estensione. Le funzioni di estensione possono stabilire di averli ricevuti,
+e crearne, attribuendo valori di tipo scalare. In alternativa, @`e possibile
+esaminare il testo della @dfn{regexp} utilizzando campi @code{regex_value.str}
+e @code{regex_value.len}.
+
+Identificativi (cio@`e, nomi di variabili globali) possono essere
+associati sia a valori scalari che a vettori. Inoltre, @command{gawk}
+consente veri vettori di vettori, in cui ogni singolo elemento di un vettore
+pu@`o a sua volta essere un vettore. La spiegazione dei vettori @`e rinviata
+@iftex
+alla
+@end iftex
+@ifnottex
+a
+@end ifnottex
+@ref{Manipolazione di vettori}.
+
+La varie macro sopra elencate facilitano l'uso degli elementi delle
+@code{union} come se
+fossero campi in una @code{struct}; @`e questa una pratica comunemente adottata
+nella scrittura di programmi in C. Questo tipo di codice @`e pi@`u semplice da
+scrivere e da leggere, ma resta una responsabilit@`a @emph{del programmatore}
+assicurarsi che il campo @code{val_type} rifletta correttamente il tipo
+del valore contenuto nella struttura @code{awk_value_t}.
+
+Dal punti di vista concettuale, i primi tre campi dell'@code{union} (numero,
+stringa, e vettore) sono sufficienti per lavorare con i valori @command{awk}.
+Tuttavia, poich@'e l'API fornisce routine per ottenere e modificare
+il valore di una variabile scalare globale usando solo il nome della
+variabile, si ha qui una perdita di efficienza: @command{gawk} deve cercare
+la variabile ogni volta che questa @`e utilizzata e modificata. Questo
+@`e un probelma reale, non solo un problema teorico.
+
+Per questo motivo, se si sa che una certa estensione passer@`a molto tempo
+a leggere e/o modificare il valore di una o pi@`u variabili scalari, si pu@`o
+ottenere uno @dfn{scalar cookie}@footnote{Si veda
+@uref{http://catb.org/jargon/html/C/cookie.html, la voce ``cookie''
+nello Jargon file}
+per una definizione di @dfn{cookie}, e
+@uref{http://catb.org/jargon/html/M/magic-cookie.html, la voce ``magic cookie''
+sempre nello Jargon file} per un bell'esempio.
+@ifclear FOR_PRINT
+Si veda anche la voce ``Cookie'' nel @ref{Glossario}.
+@end ifclear
+[@uref{http://jhanc.altervista.org/jargon/Intro.html, @`E disponibile in rete
+anche una traduzione italiana dello Jargon file}]
+}
+per quella variabile, e poi usare
+il @dfn{cookie} per ottenere il valore della variabile o per modificarne il
+valore.
+Il tipo @code{awk_scalar_t} contiene uno @dfn{scalar cookie}, e la macro
+@code{scalar_cookie} fornisce accesso al valore di quel tipo
+nella struttura @code{awk_value_t}.
+Dato uno @dfn{scalar cookie}, @command{gawk} pu@`o trovare o modificare
+direttamente il valore, come richiesto, senza bisogno di andarlo
+a cercare ogni volta.
+
+Il tipo @code{awk_value_cookie_t} e la macro @code{value_cookie} sono simili.
+Se si pensa di dover usare
+lo stesso @emph{valore} numerico o la stessa @emph{stringa} per una o pi@`u
+variabili, si pu@`o creare il valore una volta per tutte, mettendo da parte un
+@dfn{@dfn{value cookie}} per quel valore, e in seguito specificare quel
+@dfn{value cookie} quando si desidera impostare il valore di una variabile.
+Ci@`o consente di risparmiare spazio in memoria all'interno del processo
+di @command{gawk} e riduce il tempo richiesto per creare il valore.
+
+@node Funzioni di allocazione memoria
+@subsection Funzioni per allocare memoria e macro di servizio
+@cindex allocare memoria per estensioni
+@cindex memoria, allocare per estensioni
+@cindex estensioni, allocare memoria per
+
+L'API fornisce alcune funzioni per effettuare @dfn{allocazioni di memoria}
+che possono essere passate a @command{gawk}, e anche un certo numero di
+macro che possono tornare utili.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SUBSECTION} le presenta come prototipi di funzione, nel modo
+con cui il codice dell'estensione potrebbe usarle:
+
+@table @code
+@item void *gawk_malloc(size_t size);
+Chiama la versione corretta di @code{malloc()} per allocare memoria,
+che pu@`o in seguito essere messa a disposizione di @command{gawk}.
+
+@item void *gawk_calloc(size_t nmemb, size_t size);
+Chiama la versione corretta di @code{calloc()} per allocare memoria che
+che pu@`o in seguito essere messa a disposizione di @command{gawk}.
+
+@item void *gawk_realloc(void *ptr, size_t size);
+Chiama la versione corretta di @code{realloc()} per allocare memoria
+che pu@`o in seguito essere messa a disposizione di @command{gawk}.
+
+@item void gawk_free(void *ptr);
+Chiama la versione corretta di @code{free()} per liberare memoria che
+era stata allocata con
+@code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()}.
+@end table
+
+L'API deve fornire queste funzioni perch@'e @`e possibile
+che un'estensione sia stata compilata e costruita usando una versione
+diversa della libreria C rispetto a quella usata per il programma eseguibile
+@command{gawk}.@footnote{Questo succede pi@`u spesso nei sistemi MS-Windows,
+ma pu@`o capitare anche in sistemi di tipo Unix.}
+Se @command{gawk} usasse la propria versione di @code{free()} per liberare
+della memoria acquisita tramite una differente versione di @code{malloc()},
+il risultato sarebbe molto probabilmente differente da quello atteso.
+
+Due macro di utilit@`a possono essere usate per allocare memoria
+tramite @code{gawk_malloc()} e
+@code{gawk_realloc()}. Se l'allocazione non riesce, @command{gawk}
+termina l'esecuzione con un messaggio di errore fatale.
+Queste macro dovrebbero essere usate come se fossero dei richiami a
+procedure che non restituiscono un codice di ritorno:
+
+@table @code
+@item #define emalloc(pointer, type, size, message) @dots{}
+Gli argomenti per questa macro sono i seguenti:
+
+@c nested table
+@table @code
+@item pointer
+La variabile di tipo puntatore che punter@`a alla memoria allocata.
+
+@item type
+Il tipo della variabile puntatore. Questo @`e usato per definire il tipo
+quando si chiama @code{gawk_malloc()}.
+
+@item size
+Il numero totale di byte da allocare.
+
+@item message
+Un messaggio da anteporre all'eventuale messaggio di errore fatale.
+Questo @`e solitamente il nome della funzione che sta usando la macro.
+@end table
+
+@noindent
+Per esempio, si potrebbe allocare il valore di una stringa cos@`{@dotless{i}}:
+
+@example
+awk_value_t risultato;
+char *message;
+const char greet[] = "non v'allarmate!";
+
+emalloc(message, char *, sizeof(greet), "myfunc");
+strcpy(message, greet);
+make_malloced_string(message, strlen(message), & risultato);
+@end example
+
+@item #define erealloc(pointer, type, size, message) @dots{}
+Questo @`e simile a @code{emalloc()}, ma chiama @code{gawk_realloc()}
+invece che @code{gawk_malloc()}.
+Gli argomenti sono gli stessi della macro @code{emalloc()}.
+@end table
+
+@node Funzioni di costruzione
+@subsection Funzioni per creare valori
+
+L'API fornisce varie funzioni di @dfn{costruzione} per creare
+valori di tipo stringa e di tipo numerico, e anche varie macro di utilit@`a.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SUBSECTION} le presenta tutte come prototipi di funzione, nel
+modo in cui il codice sorgente di
+un'estensione le userebbe:
+
+@table @code
+@item static inline awk_value_t *
+@itemx make_const_string(const char *stringa, size_t lunghezza, awk_value_t *risultato);
+Questa funzione mette il valore di una stringa nella variabile
+@code{awk_value_t} puntata da @code{risultato}. La funzione presuppone che
+@code{stringa} sia una costante stringa C
+(o altri dati che formano una stringa), e automaticamente crea una
+@emph{copia} dei dati che sar@`a immagazzinata in @code{risultato}.
+Viene restituito il puntatore @code{risultato}.
+
+@item static inline awk_value_t *
+@itemx make_malloced_string(const char *stringa, size_t lunghezza, awk_value_t *risultato);
+Questa funzione mette il valore di una stringa nella variabile
+@code{awk_value_t} puntata da @code{risultato}. Si presuppone che
+@code{stringa} sia un valore @samp{char *}
+che punta a dati ottenuti in precedenza per mezzo di
+@code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()}.
+L'idea @`e che questi dati siano comunicati direttamente a @command{gawk},
+che se ne assume la responsabilit@`a.
+Viene restituito il puntatore @code{risultato}.
+
+@item static inline awk_value_t *
+@itemx make_null_string(awk_value_t *risultato);
+Questa funzione specializzata crea una stringa nulla (il valore ``undefined'')
+nella variabile @code{awk_value_t} puntata da @code{risultato}.
+Viene restituito il puntatore @code{risultato}.
+
+@item static inline awk_value_t *
+@itemx make_number(double num, awk_value_t *risultato);
+Questa funzione crea semplicemente un valore numerico nella variabile
+@code{awk_value_t}, puntata da @code{risultato}.
+
+@item static inline awk_value_t *
+@itemx make_const_user_input(const char *stringa, size_t lunghezza, awk_value_t *risultato);
+Questa funzione @`e identica a @code{make_const_string()}, ma la stringa @`e
+marcata come input dell'utente, che dovr@`a essere trattata come @dfn{strnum}
+se il contenuto della stringa appare essere numerico.
+
+@item static inline awk_value_t *
+@itemx make_malloced_user_input(const char *stringa, size_t lunghezza, awk_value_t *risultato);
+Questa funzione @`e identica a @code{make_malloced_string()}, ma la stringa @`e
+marcata come input dell'utente, che dovr@`a essere trattata come @dfn{strnum}
+se il contenuto della stringa appare essere numerico.
+
+@item static inline awk_value_t *
+@itemx make_const_regex(const char *stringa, size_t lunghezza, awk_value_t *risultato);
+Questa funzione crea un valore di @dfn{regexp} fortemente tipizzata, allocando una
+copia della stringa.
+@code{stringa} @`e l'espressione regolare, di lunghezza @code{lunghezza}.
+
+@item static inline awk_value_t *
+@itemx make_malloced_regex(const char *stringa, size_t lunghezza, awk_value_t *risultato);
+Questa funzione crea un valore di @dfn{regexp} fortemente tipizzata.
+@code{stringa} @`e l'espressione regolare, di lunghezza @code{lunghezza}.
+Si aspetta che @code{stringa} sia un valore di tipo @samp{char *} che punta a
+dati ottenuti in precedenza tramite una chiamata a
+@code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()}.
+
+@end table
+
+@node Funzioni di registrazione
+@subsection Funzioni di registrazione
+@cindex registrazione di estensione
+@cindex estensione, registrazione di
+
+Questa @value{SECTION} descrive le funzioni dell'API per
+registrare parti di un'estensione con @command{gawk}.
+
+@menu
+* Funzioni di estensione:: Registrare funzioni di estensione.
+* Funzioni di exit callback:: Registrare una exit di callback.
+* Stringa di versione Estensioni:: Registrare una stringa di versione.
+* Analizzatori di input:: Registrare un analizzatore di input.
+* Processori di output:: Registrare un processore di output.
+* Processori bidirezionali:: Registrare un processore bidirezionale.
+@end menu
+
+@node Funzioni di estensione
+@subsubsection Registrare funzioni di estensione
+
+Le funzioni di estensione sono descritte dal seguente tracciato record:
+
+@example
+typedef struct awk_ext_func @{
+@ @ @ @ const char *name;
+@ @ @ @ awk_value_t *(*const function)(int num_actual_args,
+@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *risultato,
+@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo);
+@ @ @ @ const size_t max_expected_args;
+@ @ @ @ const size_t min_required_args;
+@ @ @ @ awk_bool_t suppress_lint;
+@ @ @ @ void *data; /* puntatore di tipo opaco
+@ @ @ @ a ogni informazione ulteriore */
+@} awk_ext_func_t;
+@end example
+
+I campi sono:
+
+@table @code
+@item const char *name;
+Il nome della nuova funzione.
+Il codice sorgente a livello di @command{awk} richiama la funzione usando
+questo nome.
+Il nome @`e una normale stringa di caratteri del linguaggio C.
+
+I nomi di funzione devono rispettare le stesse regole che valgono per gli
+identificativi @command{awk}.
+Cio@`e, devono iniziare o con una lettera dell'alfabeto inglese o con un
+trattino basso, che possono essere seguiti da un numero qualsiasi di
+lettere, cifre o trattini bassi.
+L'uso di maiuscolo/minuscolo @`e significativo.
+
+@item awk_value_t *(*const function)(int num_actual_args,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *risultato,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct awk_ext_func *finfo);
+Questo @`e un puntatore alla funzione C che fornisce la funzionalit@`a per cui
+@`e stata scritta l'estensione.
+La funzione deve riempire l'area di memoria puntata da @code{*risultato} con
+un numero, con una stringa, oppure con una @dfn{regexp}.
+@command{gawk} diventa il proprietario di tutte le stringhe di memoria.
+Come gi@`a detto sopra, la stringa di memoria @emph{deve} essere stata ottenuta
+usando @code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()}.
+
+L'argomento @code{num_actual_args} dice alla funzione scritta in C quanti
+parametri sono stati effettivamente passati dal codice chiamante all'interno
+di @command{awk}.
+
+La funzione deve restituire il valore di @code{risultato}.
+Questo @`e per utilit@`a del codice chiamante all'interno di
+@command{gawk}.
+
+@item size_t max_expected_args;
+Questo @`e il massimo numero di argomenti che la funzione si aspetta di
+ricevere.
+Se chiamata con un numero di argomenti maggiore di questo, e se @`e stato
+richiesto il controllo @dfn{lint}, @command{gawk} stampa un messaggio di
+avvertimento. Per ulteriori informazioni, si veda la descrizione di
+@code{suppress_lint}, pi@`u avanti in questa lista.
+
+@item const size_t min_required_args;
+Questo @`e il minimo numero di argomenti che la funzione si aspetta di
+ricevere.
+Se @`e chiamata con un numero inferiore di argomenti, @command{gawk}
+stampa un messaggio di errore fatale ed esce.
+
+@item awk_bool_t suppress_lint;
+Questo @dfn{flag} dice a @command{gawk} di non stampare un messaggio
+@dfn{lint} se @`e stato richiesto un controllo @dfn{lint} e se sono stati
+forniti pi@`u argomenti di quelli attesi. Una funzione di estensione pu@`o
+stabilire se @command{gawk} ha gi@`a stampato almeno uno di tali messaggi
+controllando se @samp{num_actual_args > finfo->max_expected_args}.
+In tal caso, se la funzione non desidera la stampa di ulteriori messaggi,
+dovrebbe impostare @code{finfo->suppress_lint} a @code{awk_true}.
+
+@item void *data;
+Questo @`e un puntatore di tipo opaco a tutti quei dati che una funzione
+di estensione desidera avere disponibili al momento della chiamata.
+Passando alla funzione di estensione la struttura @code{awk_ext_func_t}
+e avendo al suo interno questo puntatore disponibile, rende possibile
+scrivere un'unica funzione C o C++ che implementa pi@`u di una funzione
+di estensione a livello @command{awk}.
+@end table
+
+Una volta preparato un record che descrive l'estensione, la funzione di
+estensione va registrata con @command{gawk} usando questa funzione dell'API:
+
+@table @code
+@item awk_bool_t add_ext_func(const char *namespace, awk_ext_func_t *func);
+Questa funzione restituisce il valore @dfn{true} se ha successo,
+oppure @dfn{false} in caso contrario.
+Il parametro @code{namespace} non @`e usato per ora; dovrebbe puntare a una
+stringa vuota (@code{""}). Il puntatore @code{func} @`e l'indirizzo di una
+@code{struct} che rappresenta la funzione stessa, come descritto sopra.
+
+@command{gawk} non modifica ci@`o che @`e puntato da @code{func}, ma la
+funzione di estensione stessa riceve questo puntatore e pu@`o modificarlo
+e farlo puntare altrove, quindi il puntatore non @`e stato dichiarato
+di tipo costante (@code{const}).
+@end table
+
+La combinazione di @code{min_required_args}, @code{max_expected_args},
+e @code{suppress_lint} pu@`o ingenerare confusione. Ecco delle linee-guida
+sul da farsi.
+
+@table @asis
+@item Un numero qualsiasi di argomenti @`e valido
+Impostare @code{min_required_args} and @code{max_expected_args} a zero e
+impostare @code{suppress_lint} ad @code{awk_true}.
+
+@item Un numero minimo di argomenti @`e richiesto, ma non c'@`e un limite al numero massimo
+Impostare @code{min_required_args} al minimo richiesto.
+Impostare @code{max_expected_args} a zero e
+impostare @code{suppress_lint} ad @code{awk_true}.
+
+@item Un numero minino di argomenti @`e richiesto, ma c'@`e un limite al numero massimo
+Impostare @code{min_required_args} al minimo richiesto.
+Impostare @code{max_expected_args} al massimo atteso.
+Impostare @code{suppress_lint} ad @code{awk_false}.
+
+@item Un numero minino di argomenti @`e richiesto, ma c'@`e un numero massimo non superabile
+Impostare @code{min_required_args} al minimo richiesto.
+Impostare @code{max_expected_args} al massimo atteso.
+Impostare @code{suppress_lint} ad @code{awk_false}.
+Nella funzione di estensione, controllare che @code{num_actual_args} non
+ecceda @code{f->max_expected_args}. Se il massimo @`e superato, stampare
+un messaggio di errore fatale.
+@end table
+
+@node Funzioni di exit callback
+@subsubsection Registrare una funzione @dfn{exit callback}
+
+Una funzione @dfn{exit callback} @`e una funzione che @command{gawk} invoca
+prima di completare l'esecuzione del programma.
+Siffatte funzioni sono utili se ci sono dei compiti generali di ``pulizia''
+che dovrebbero essere effettuati nell'estensione (come chiudere connessioni a
+un @dfn{database} o rilasciare altre risorse).
+Si pu@`o registrare una tale
+funzione con @command{gawk} per mezzo della seguente funzione:
+
+@table @code
+@item void awk_atexit(void (*funcp)(void *data, int exit_status),
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ void *arg0);
+I parametri sono:
+
+@c nested table
+@table @code
+@item funcp
+Un puntatore alla funzione da chiamare prima che @command{gawk} completi
+l'esecuzione. Il parametro @code{data}
+sar@`a il valore originale di @code{arg0}.
+Il parametro @code{exit_status} @`e il valore del codice di ritorno che
+@command{gawk} intende passare alla chiamata di sistema @code{exit()}
+(che termina l'esecuzione del programma).
+
+@item arg0
+Un puntatore a un'area dati privata che @command{gawk} mantiene perch@'e
+sia poi passata alla funzione puntata da @code{funcp}.
+@end table
+@end table
+
+Le funzioni @dfn{exit callback} sono chiamate in ordine inverso rispetto
+a quello con cui @`e stata fatta la registrazione con @command{gawk}
+(LIFO: Last In, First Out).
+
+@node Stringa di versione Estensioni
+@subsubsection Registrare una stringa di versione per un'estensione
+
+Si pu@`o registrare una stringa di versione che indica il nome e la versione
+di una data estensione a @command{gawk}, come segue:
+
+@table @code
+@item void register_ext_version(const char *version);
+Registra la stringa puntata da @code{version} con @command{gawk}.
+Si noti che @command{gawk} @emph{non} copia la stringa @code{version}, e
+quindi questa stringa non dovrebbe essere modificata.
+@end table
+
+@command{gawk} stampa tutte le stringhe con le versioni di estensione
+registrate, quando viene invocato specificando l'opzione @option{--version}.
+
+@node Analizzatori di input
+@subsubsection Analizzatori di input personalizzati
+@cindex personalizzato, analizzatore di input
+@cindex analizzatore di input personalizzato
+@cindex input, analizzatore di, personalizzato
+
+Per default, @command{gawk} legge file di testo come input. Il valore della
+variabile @code{RS} @`e usato per determinare la fine di un record, e subito
+dopo la variabile @code{FS} (o @code{FIELDWIDTHS} o @code{FPAT}) viene usata
+per suddividerlo in campi
+@iftex
+(@pxrefil{Leggere file}).
+@end iftex
+@ifnottex
+(@pxref{Leggere file}).
+@end ifnottex
+Viene inoltre impostato il valore di @code{RT}
+(@pxref{Variabili predefinite}).
+
+Se lo si desidera, @`e possibile fornire un analizzatore di input
+personalizzato. Il compito di un analizzatore di input @`e di restituire un
+record al codice di @command{gawk}, che poi lo elaborer@`a, accompagnato,
+se necessario, da indicatori del valore e della lunghezza dei dati da usare
+per @code{RT}.
+
+Per fornire un analizzatore personalizzato di input, occorre innanzitutto
+rendere disponibili due funzioni (dove @var{XXX} @`e un nome che fa da prefisso
+all'estensione intera):
+
+@table @code
+@item awk_bool_t @var{XXX}_can_take_file(const awk_input_buf_t *iobuf);
+Questa funzione esamina l'informazione disponibile in @code{iobuf}
+(che vedremo tra poco). Basandosi su tale informazione,
+decide se l'analizzatore di input personalizzato andr@`a usato per questo file.
+Se questo @`e il caso, dovrebbe restituire @dfn{true}. Altrimenti, restituir@`a
+@dfn{false}. Nessuno stato (valori di variabili, etc.) dovrebbe venire
+modificato all'interno di @command{gawk}.
+
+@item awk_bool_t @var{XXX}_take_control_of(awk_input_buf_t *iobuf);
+Quando @command{gawk} decide di passare il controllo del file a questo
+analizzatore di input, richiamer@`a questa funzione.
+Questa funzione a sua volta deve assegnare un valore ad alcuni campi
+nella struttura @code{awk_input_buf_t} e assicurarsi che
+alcune condizioni siano verificate. Dovrebbe poi restituire @dfn{true}.
+Se si verifica un errore di qualche tipo, i campi in questione non dovrebbero
+venire riempiti, e la funzione dovrebbe restituire @dfn{false}; in questo caso
+@command{gawk} non utilizzer@`a pi@`u l'analizzatore personalizzato di input.
+I dettagli sono descritti pi@`u avanti.
+@end table
+
+L'estensione dovrebbe raccogliere queste funzioni all'interno di una
+struttura @code{awk_input_parser_t}, simile a questa:
+
+@example
+typedef struct awk_input_parser @{
+ const char *name; /* nome dell'analizzatore */
+ awk_bool_t (*can_take_file)(const awk_input_buf_t *iobuf);
+ awk_bool_t (*take_control_of)(awk_input_buf_t *iobuf);
+ awk_const struct awk_input_parser *awk_const next; /* per uso
+ di gawk */
+@} awk_input_parser_t;
+@end example
+
+I campi sono:
+
+@table @code
+@item const char *name;
+Il nome dell'analizzatore di input. Questa @`e una normale stringa di caratteri
+del linguaggio C.
+
+@item awk_bool_t (*can_take_file)(const awk_input_buf_t *iobuf);
+Un puntatore alla funzione @code{@var{XXX}_can_take_file()}.
+
+@item awk_bool_t (*take_control_of)(awk_input_buf_t *iobuf);
+Un puntatore alla funzione @code{@var{XXX}_take_control_of()}.
+
+@item awk_const struct input_parser *awk_const next;
+Questa struttura @`e per uso di @command{gawk};
+per questo motivo @`e marcata @code{awk_const} in modo che l'estensione non
+possa modificarla.
+@end table
+
+I passi da seguire sono i seguenti:
+
+@enumerate
+@item
+Creare una variabile @code{static awk_input_parser_t} e inizializzarla
+adeguatamente.
+
+@item
+Quando l'estensione @`e caricata, registrare l'analizzatore personalizzato di
+input con @command{gawk} usando la funzione API @code{register_input_parser()}
+(descritta pi@`u sotto).
+@end enumerate
+
+La definizione di una struttura @code{awk_input_buf_t} @`e simile a questa:
+
+@example
+typedef struct awk_input @{
+ const char *name; /* nome file */
+ int fd; /* descrittore di file */
+#define INVALID_HANDLE (-1)
+ void *opaque; /* area dati privata
+ per l'analizzatore di input */
+ int (*get_record)(char **out, struct awk_input *iobuf,
+ int *errcode, char **rt_start, size_t *rt_len);
+ ssize_t (*read_func)();
+ void (*close_func)(struct awk_input *iobuf);
+ struct stat sbuf; /* buffer per stat */
+@} awk_input_buf_t;
+@end example
+
+I campi si possono dividere in due categorie: quelli che sono usati (almeno
+inizialmente) da @code{@var{XXX}_can_take_file()}, e quelli che sono usati da
+@code{@var{XXX}_take_control_of()}. Il primo gruppo di campi, e il loro uso,
+@`e cos@`{@dotless{i}} definito:
+
+@table @code
+@item const char *name;
+Il nome del file.
+
+@item int fd;
+Un descrittore di file per il file. Se @command{gawk} riesce ad aprire
+il file, il valore di @code{fd} @emph{non} sar@`a uguale a
+@code{INVALID_HANDLE} [descrittore non valido]. In caso contrario,
+quello sar@`a il valore.
+
+@item struct stat sbuf;
+Se il descrittore di file @`e valido, @command{gawk} avr@`a riempito i campi di
+questa struttura invocando la chiamata di sistema @code{fstat()}.
+@end table
+
+La funzione @code{@var{XXX}_can_take_file()} dovrebbe esaminare i campi di
+cui sopra e decidere se l'analizzatore di input vada usato per il file.
+La decisione pu@`o dipendere da uno stato di @command{gawk} (il valore
+di una variabile definita in precedenza dall'estensione e impostata dal
+codice @command{awk}), dal nome del
+file, dal fatto che il descrittore di file sia valido o no,
+dalle informazioni contenute in @code{struct stat} o da una qualsiasi
+combinazione di questi fattori.
+
+Una volta che @code{@var{XXX}_can_take_file()} restituisce @dfn{true}, e
+@command{gawk} ha deciso di usare l'analizzatore personalizzato, viene
+chiamata la funzione @code{@var{XXX}_take_control_of()}. Tale funzione
+si occupa di riempire il campo @code{get_record} oppure il campo
+@code{read_func} nella struttura @code{awk_input_buf_t}. La funzione si
+assicura inoltre che @code{fd} @emph{not} sia impostato al valore
+@code{INVALID_HANDLE}. L'elenco seguente descrive i campi che
+possono essere riempiti da @code{@var{XXX}_take_control_of()}:
+
+@table @code
+@item void *opaque;
+Questo campo @`e usato per contenere qualiasi informazione di stato sia
+necessaria per l'analizzatore di input
+riguardo a questo file. Il campo @`e ``opaco'' per @command{gawk}.
+L'analizzatore di input non @`e obbligato a usare questo puntatore.
+
+@item int@ (*get_record)(char@ **out,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ struct@ awk_input *iobuf,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int *errcode,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ char **rt_start,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t *rt_len);
+Questo puntatore a funzione dovrebbe puntare a una funzione che crea i record
+in input. Tale funzione @`e il nucleo centrale dell'analizzatore di input.
+Il suo modo di operare @`e descritto nel testo che segue questo elenco.
+
+@item ssize_t (*read_func)();
+Questo puntatore a funzione dovrebbe puntare a una funzione che ha lo
+stesso comportamento della chiamata di sistema standard POSIX @code{read()}.
+@`E in alternativa al puntatore a @code{get_record}. Il relativo comportamento
+@`e pure descritto nel testo che segue quest'elenco.
+
+@item void (*close_func)(struct awk_input *iobuf);
+Questo puntatore a funzione dovrebbe puntare a una funzione che fa
+la ``pulizia finale''. Dovrebbe liberare ogni risorsa allocata da
+@code{@var{XXX}_take_control_of()}. Pu@`o anche chiudere il file. Se lo fa,
+dovrebbe impostare il campo @code{fd} a @code{INVALID_HANDLE}.
+
+Se @code{fd} @`e ancora diverso da @code{INVALID_HANDLE} dopo la chiamata a
+questa funzione, @command{gawk} invoca la normale chiamata di sistema
+@code{close()}.
+
+Avere una funzione di ``pulizia'' @`e facoltativo. Se l'analizzatore di input
+non ne ha bisogno, basta non impostare questo campo. In questo caso,
+@command{gawk} invoca la normale chiamata di sistema @code{close()} per il
+descrittore di file, che, quindi, dovrebbe essere valido.
+@end table
+
+La funzione @code{@var{XXX}_get_record()} svolge il lavoro di creazione dei
+record in input. I parametri sono i seguenti:
+
+@table @code
+@item char **out
+Questo @`e un puntatore a una variabile @code{char *} che @`e impostatata in modo
+da puntare al record. @command{gawk} usa una sua copia locale dei dati,
+quindi l'estensione deve gestire la relativa area di memoria.
+
+@item struct awk_input *iobuf
+Questa @`e la struttura @code{awk_input_buf_t} per il file. I campi dovrebbero
+essere usati per leggere i dati (@code{fd}) e per gestire lo stato privato
+(@code{opaque}), se necessario.
+
+@item int *errcode
+Se si verifica un errore, @code{*errcode} dovrebbe essere impostato a un
+valore appropriato tra quelli contenuti in @code{<errno.h>}.
+
+@item char **rt_start
+@itemx size_t *rt_len
+Se il concetto ``fine record'' @`e applicabile,
+@code{*rt_start} dovrebbe essere impostato per puntare ai dati da usare come
+@code{RT}, e @code{*rt_len} dovrebbe essere impostata alla lunghezza di quel
+campo. In caso contrario, @code{*rt_len} dovrebbe essere impostata a zero.
+@command{gawk} usa una sua copia di questi dati, quindi l'estensione deve
+gestire tale memoria.
+@end table
+
+Il codice di ritorno @`e la lunghezza del buffer puntato da
+@code{*out} oppure @code{EOF}, se @`e stata raggiunta la fine del file o se
+si @`e verificato un errore.
+
+Poich@'e @code{errcode} @`e sicuramente un puntatore valido, non c'@`e
+bisogno di controllare che il valore sia @code{NULL}. @command{gawk}
+imposta @code{*errcode} a zero, quindi non c'@`e bisogno di impostarlo, a meno
+che non si verifichi un errore.
+
+In presenza di un errore, la funzione dovrebbe restituire @code{EOF} e
+impostare @code{*errcode} a un valore maggiore di zero. In questo caso, se
+@code{*errcode} non @`e uguale a zero, @command{gawk} automaticamente aggiorna
+la variabile @code{ERRNO} usando il valore contenuto in @code{*errcode}.
+(In generale, impostare @samp{*errcode = errno} dovrebbe essere la
+cosa giusta da fare.)
+
+Invece di fornire una funzione che restituisce un record in input,
+@`e possibile fornirne una che semplicemente legge dei byte, e lascia
+che sia @command{gawk} ad analizzare i dati per farne dei record. In questo
+caso, i dati dovrebbero essere restituiti nella codifica multibyte propria
+della localizzazione corrente.
+Una siffatta funzione dovrebbe imitare il comportamento della chiamata di
+sistema @code{read()}, e riempire il puntatore @code{read_func} con
+il proprio indirizzo nella struttura @code{awk_input_buf_t}.
+
+Per default, @command{gawk} imposta il puntatore @code{read_func} in modo che
+punti alla chiamata di sistema @code{read()}. In questo modo l'estensione
+non deve preoccuparsi di impostare esplicitamente questo campo.
+
+@quotation NOTA
+Occorre decidere per l'uno o per l'altro metodo: o una funzione che
+restituisce un record o una che restituisce dei dati grezzi. Nel dettaglio,
+se si fornisce una funzione che prepara un record, @command{gawk} la
+invocher@`a, e non chiamer@`a mai la funzione che fa una lettura grezza.
+@end quotation
+
+@command{gawk} viene distribuito con un'estensione di esempio che legge
+delle directory, restituendo un record per ogni elemento contenuto nella
+directory (@pxref{Esempio di estensione Readdir}. Questo codice sorgente pu@`o
+essere usato come modello per scrivere un analizzatore di input
+personalizzato.
+
+Quando si scrive un analizzatore di input, si dovrebbe progettare (e
+documentare) il modo con cui si suppone che interagisca con il codice
+@command{awk}. Si pu@`o scegliere di utilizzarlo per tutte le letture, e
+intervenire solo quando @`e necessario, (come fa l'estensione di
+esempio @code{readdir}). Oppure lo si pu@`o utilizzare a seconda del
+valore preso da una variabile @command{awk}, come fa l'estensione XML
+inclusa nel progetto @code{gawkextlib} (@pxref{gawkextlib}).
+In quest'ultimo caso, il codice in una regola @code{BEGINFILE}
+pu@`o controllare @code{FILENAME} ed @code{ERRNO} per decidere se
+attivare un analizzatore di input (@pxref{BEGINFILE/ENDFILE}) oppure no.
+
+Un analizzatore di input va registrato usando la seguente funzione:
+
+@table @code
+@item void register_input_parser(awk_input_parser_t *input_parser);
+Registra l'analizzatore di input puntato da @code{input_parser} con
+@command{gawk}.
+@end table
+
+@node Processori di output
+@subsubsection Registrare un processore di output
+@cindex personalizzato, processore di output
+@cindex processore di output personalizzato
+@cindex output, processore di, personalizzato
+
+@cindex processore di output
+@cindex output, processore di
+Un @dfn{processore di output} @`e l'immagine riflessa di un
+analizzatore di input.
+Consente a un'estensione di prendere il controllo dell'output
+indirizzato verso un file
+che sia stato aperto con gli operatori di ridirezione di I/O
+@samp{>} o @samp{>>} (@pxref{Ridirezione}).
+
+Il processore di output @`e molto simile, come struttura,
+all'analizzatore di input:
+
+@example
+typedef struct awk_output_wrapper @{
+ const char *name; /* nome del processore */
+ awk_bool_t (*can_take_file)(const awk_output_buf_t *outbuf);
+ awk_bool_t (*take_control_of)(awk_output_buf_t *outbuf);
+ awk_const struct awk_output_wrapper *awk_const next; /* per gawk */
+@} awk_output_wrapper_t;
+@end example
+
+I campi sono i seguenti:
+
+@table @code
+@item const char *name;
+Questo @`e il nome del processore di output.
+
+@item awk_bool_t (*can_take_file)(const awk_output_buf_t *outbuf);
+Questo @`e il puntatore a una funzione che esamina l'informazione contenuta
+nella struttura @code{awk_output_buf_t} puntata da @code{outbuf}.
+Dovrebbe restituire @dfn{true} se il processore di output vuole elaborare
+il file, e @dfn{false} in caso contrario.
+Nessuno stato (valori di variabili, etc.) dovrebbe essere modificato
+all'interno di @command{gawk}.
+
+@item awk_bool_t (*take_control_of)(awk_output_buf_t *outbuf);
+La funzione puntata da questo campo viene chiamata quando @command{gawk}
+decide di consentire al processore di output di prendere il controllo del file.
+Dovrebbe riempire in maniera appropriata dei campi nella struttura
+@code{awk_output_buf_t}, come descritto sotto, e restituire @dfn{true} se
+ha successo, @dfn{false} in caso contrario.
+
+@item awk_const struct output_wrapper *awk_const next;
+Questa struttura @`e per uso di @command{gawk};
+per questo motivo @`e marcata @code{awk_const} in modo che l'estensione non
+possa modificarlo.
+@end table
+
+La struttura @code{awk_output_buf_t} @`e simile a questa:
+
+@example
+typedef struct awk_output_buf @{
+ const char *name; /* nome del file in output */
+ const char *mode; /* argomento @dfn{mode} per fopen */
+ FILE *fp; /* puntatore stdio file */
+ awk_bool_t redirected; /* @dfn{true} se un processore @`e attivo */
+ void *opaque; /* per uso del processore di output */
+ size_t (*gawk_fwrite)(const void *buf, size_t size, size_t count,
+ FILE *fp, void *opaque);
+ int (*gawk_fflush)(FILE *fp, void *opaque);
+ int (*gawk_ferror)(FILE *fp, void *opaque);
+ int (*gawk_fclose)(FILE *fp, void *opaque);
+@} awk_output_buf_t;
+@end example
+
+Anche qui, l'estensione definir@`a le funzioni @code{@var{XXX}_can_take_file()}
+e @code{@var{XXX}_take_control_of()} che esaminano e aggiornano
+campi dati in @code{awk_output_buf_t}.
+I campi dati sono i seguenti:
+
+@table @code
+@item const char *name;
+Il nome del file in output.
+
+@item const char *mode;
+La stringa @dfn{mode} (come sarebbe usata nel secondo argomento della
+chiamata di sistema @code{fopen()})
+con cui il file era stato aperto.
+
+@item FILE *fp;
+Il puntatore @code{FILE} da @code{<stdio.h>}. @command{gawk} apre il file
+prima di controllare se esiste un processore di output.
+
+@item awk_bool_t redirected;
+Questo campo dev'essere impostato a @dfn{true} dalla funzione
+@code{@var{XXX}_take_control_of()}.
+
+@item void *opaque;
+Questo puntatore @`e opaco per @command{gawk}. L'estensione dovrebbe usarlo
+per contenere un puntatore a qualsiasi dato privato associato al file.
+
+@item size_t (*gawk_fwrite)(const void *buf, size_t size, size_t count,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ FILE *fp, void *opaque);
+@itemx int (*gawk_fflush)(FILE *fp, void *opaque);
+@itemx int (*gawk_ferror)(FILE *fp, void *opaque);
+@itemx int (*gawk_fclose)(FILE *fp, void *opaque);
+Questi puntatori dovrebbero essere impostati per puntare a funzioni
+la cui azione sia equivalente a quella delle funzioni di @code{<stdio.h>},
+se questo @`e cio che si desidera.
+@command{gawk} usa questi puntatori a funzione per @emph{tutti} gli output.
+@command{gawk} inizializza i puntatori per puntare a funzioni interne
+``di passaggio'' che si limitano a chiamare le funzioni normali di
+@code{<stdio.h>}, e quindi un'estensione deve ridefinire solo le funzioni
+appropriate per fare il lavoro richiesto.
+@end table
+
+La funzione @code{@var{XXX}_can_take_file()} dovrebbe decidere in base ai
+campi @code{name} e @code{mode}, e a ogni altro ulteriore indicatore di stato
+(p.es., valori di variabili @command{awk}) adatto allo scopo.
+
+Quando @command{gawk} chiama @code{@var{XXX}_take_control_of()}, la funzione
+dovrebbe riempire i rimanenti campi
+in modo opportuno, tranne che per @code{fp}, che dovrebbe essere usato
+normalmente.
+
+Il processore di output va registrato usando la seguente funzione:
+
+@table @code
+@item void register_output_wrapper(awk_output_wrapper_t *output_wrapper);
+Registra il processore di output puntato da @code{output_wrapper} con
+@command{gawk}.
+@end table
+
+@node Processori bidirezionali
+@subsubsection Registrare un processore bidirezionale
+@cindex personalizzato, processore bidirezionale
+@cindex processore bidirezionale personalizzato
+@cindex bidirezionale, processore personalizzato
+
+Un @dfn{processore bidirezionale} combina un analizzatore di input e
+un processore di output per un I/O
+bidirezionale usando l'operatore @samp{|&} (@pxref{Ridirezione}).
+Le strutture @code{awk_input_parser_t} e @code{awk_output_buf_t}
+sono usate nella maniera gi@`a descritta precedentemente.
+
+Un processore bidirezionale @`e rappresentato dalla struttura seguente:
+
+@example
+typedef struct awk_two_way_processor @{
+ const char *name; /* nome del processore bidirezionale */
+ awk_bool_t (*can_take_two_way)(const char *name);
+ awk_bool_t (*take_control_of)(const char *name,
+ awk_input_buf_t *inbuf,
+ awk_output_buf_t *outbuf);
+ awk_const struct awk_two_way_processor *awk_const next; /* per gawk */
+@} awk_two_way_processor_t;
+@end example
+
+I campi sono i seguenti:
+
+@table @code
+@item const char *name;
+Il nome del processore bidirezionale.
+
+@item awk_bool_t (*can_take_two_way)(const char *name);
+La funzione puntata da questo campo dovrebbe restituire @dfn{true} se
+vuole gestire l'I/O bidirezionale per questo @value{FN}.
+La funzione non dovrebbe modificare alcuno stato (valori di variabili, etc.)
+all'interno di @command{gawk}.
+
+@item awk_bool_t (*take_control_of)(const char *name,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_input_buf_t *inbuf,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_output_buf_t *outbuf);
+La funzione puntata da questo campo dovrebbe riempire le strutture
+@code{awk_input_buf_t} e @code{awk_output_buf_t} puntate da @code{inbuf} e
+@code{outbuf}, rispettivamente. Queste strutture sono gi@`a state descritte
+in precedenza.
+
+@item awk_const struct two_way_processor *awk_const next;
+Questa struttura @`e per uso di @command{gawk};
+per questo motivo @`e marcata @code{awk_const} in modo che l'estensione non
+possa modificarla.
+@end table
+
+Come per l'analizzatore di input e il processore di output, vanno fornite le
+funzione ``s@`{@dotless{i}}, ci penso io'' e ``per questo, fai tu'',
+@code{@var{XXX}_can_take_two_way()} e @code{@var{XXX}_take_control_of()}.
+
+Il processore bidirezionale va registrato usando la seguente funzione:
+
+@table @code
+@item void register_two_way_processor(awk_two_way_processor_t *two_way_processor);
+Registra il processore bidirezionale puntato da @code{two_way_processor} con
+@command{gawk}.
+@end table
+
+@node Stampare messaggi
+@subsection Stampare messaggi dalle estensioni
+@cindex stampare messaggi dalle estensioni
+@cindex messaggi, stampare dalle estensioni
+@cindex estensioni, stampare messaggi dalle
+
+@`E possibile stampare diversi tipi di messaggi di avvertimento da
+un'estensione, come qui spiegato. Si noti che, per queste funzioni,
+si deve fornire l'ID di estensione ricevuto da @command{gawk}
+al momento in cui l'estensione @`e stata caricata:@footnote{Poich@'e l'API usa solo
+funzionalit@`a previste dal
+compilatore ISO C 90, non @`e possibile usare le macro di tipo variadico
+(che accettano un numero variabile di argomenti) disponibili nel compilatore
+ISO C 99, che nasconderebbero quel parametro. Un vero peccato!}
+
+@table @code
+@item void fatal(awk_ext_id_t id, const char *format, ...);
+Stampa un messaggio e poi @command{gawk} termina immediatamente l'esecuzione.
+
+@item void nonfatal(awk_ext_id_t id, const char *format, ...);
+Stampa un messaggio di errore non-fatale.
+
+@item void warning(awk_ext_id_t id, const char *format, ...);
+Stampa un messaggio di avvertimento.
+
+@item void lintwarn(awk_ext_id_t id, const char *format, ...);
+Stampa un messaggio di avvertimento ``lint''. Normalmente questo equivale a
+stampare un messaggio di avvertimento, ma se @command{gawk} era stato
+invocato specificando l'opzione @samp{--lint=fatal},
+gli avvertimenti di @dfn{lint} diventano messaggi di errore fatali.
+@end table
+
+Tutte queste funzioni sono per il resto simili alla famiglia di funzioni
+@code{printf()} del linguaggio C, dove il parametro @code{format} @`e una
+stringa contenente dei caratteri normali e delle istruzioni di formattazione,
+mischiati tra loro.
+
+@node Aggiornare @code{ERRNO}
+@subsection Funzioni per aggiornare @code{ERRNO}
+
+Le seguenti funzioni consentono l'aggiornamento della variabile
+@code{ERRNO}:
+
+@table @code
+@item void update_ERRNO_int(int errno_val);
+Imposta @code{ERRNO} alla stringa equivalente del codice di errore
+in @code{errno_val}. Il valore dovrebbe essere uno dei codici di errore
+definiti in @code{<errno.h>}, e @command{gawk} lo trasforma in una stringa
+(qualora possibile, tradotta) usando la funzione C @code{strerror()}.
+
+@item void update_ERRNO_string(const char *string);
+Imposta @code{ERRNO} direttamente usando il valore della stringa specificata.
+@command{gawk} fa una copia del valore di @code{stringa}.
+
+@item void unset_ERRNO(void);
+Annulla il valore di @code{ERRNO}.
+@end table
+
+@node Richiedere valori
+@subsection Richiedere valori
+
+Tutte le funzioni che restituiscono valori da @command{gawk}
+funzionano allo stesso modo. Si fornisce un campo @code{awk_valtype_t}
+per indicare il tipo di valore che ci si aspetta. Se il valore disponibile
+corrisponde a quello richiesto, la funzione restituisce @dfn{true} e riempie
+il campo del risultato @code{awk_value_t}.
+Altrimenti, la funzione restituisce @dfn{false}, e il campo @code{val_type}
+indica il tipo di valore disponibile.
+A quel punto si pu@`o, a seconda di quel che richiede la situazione,
+stampare un messaggio di errore oppure ripetere la
+richiesta specificando il tipo di valore che risulta disponibile. Questo
+comportamento @`e riassunto nella
+@ref{table-value-types-returned}.
+
+@float Tabella,table-value-types-returned
+@caption{Tipi di valori restituiti dall'API}
+@docbook
+<informaltable>
+<tgroup cols="8">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <colspec colname="c3"/>
+ <colspec colname="c4"/>
+ <colspec colname="c5"/>
+ <colspec colname="c6"/>
+ <colspec colname="c7"/>
+ <colspec colname="c8"/>
+ <spanspec spanname="hspan" namest="c3" nameend="c8" align="center"/>
+ <thead>
+ <row><entry></entry><entry spanname="hspan"><para>Tipo di valore reale</para></entry></row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry><para>Stringa</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>Numero</para></entry>
+ <entry><para>Regexp</para></entry>
+ <entry><para>Vettore</para></entry>
+ <entry><para>Indefinito</para></entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Stringa</emphasis></para></entry>
+ <entry><para>Stringa</para></entry>
+ <entry><para>Stringa</para></entry>
+ <entry><para>Stringa</para></entry>
+ <entry><para>Stringa</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Strnum</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Numero</emphasis></para></entry>
+ <entry><para>Numero</para></entry>
+ <entry><para>Numero</para></entry>
+ <entry><para>Numero</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry><para><emphasis role="bold">Tipo</emphasis></para></entry>
+ <entry><para><emphasis role="bold">Regexp</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Regexp</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry><para><emphasis role="bold">Richiesto</emphasis></para></entry>
+ <entry><para><emphasis role="bold">Vettore</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>Vettore</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Scalare</emphasis></para></entry>
+ <entry><para>Scalare</para></entry>
+ <entry><para>Scalare</para></entry>
+ <entry><para>Scalare</para></entry>
+ <entry><para>Scalare</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">Indefinito</emphasis></para></entry>
+ <entry><para>Stringa</para></entry>
+ <entry><para>Strnum</para></entry>
+ <entry><para>Numero</para></entry>
+ <entry><para>Regexp</para></entry>
+ <entry><para>Vettore</para></entry>
+ <entry><para>Indefinito</para></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry><para><emphasis role="bold">@dfn{Value cookie}</emphasis></para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ <entry><para>false</para></entry>
+ </row>
+ </tbody>
+</tgroup>
+</informaltable>
+@end docbook
+
+@ifnotplaintext
+@ifnotdocbook
+@multitable @columnfractions .50 .50
+@headitem @tab Tipo di valore reale
+@end multitable
+@c 10/2014: Thanks to Karl Berry for this bit to reduce the space:
+@tex
+\vglue-1.1\baselineskip
+@end tex
+@c @multitable @columnfractions .166 .166 .198 .15 .15 .166
+@ifclear SMALLPRINT
+@multitable {Richiesto} {Indefinito} {Numero} {Numero} {Scalar} {Regexp} {Vettore} {Indefinito}
+@headitem @tab @tab Stringa @tab Strnum @tab Numero @tab Regexp @tab Vettore @tab Indefinito
+@item @tab @b{Stringa} @tab Stringa @tab Stringa @tab Stringa @tab Stringa @tab false @tab false
+@item @tab @b{Strnum} @tab false @tab Strnum @tab Strnum @tab false @tab false @tab false
+@item @tab @b{Numero} @tab Numero @tab Numero @tab Numero @tab false @tab false @tab false
+@item @b{Tipo} @tab @b{Regexp} @tab false @tab false @tab false @tab Regexp @tab false @tab false
+@item @b{Richiesto} @tab @b{Vettore} @tab false @tab false @tab false @tab false @tab Vettore @tab false
+@item @tab @b{Scalar} @tab Scalar @tab Scalar @tab Scalar @tab Scalar @tab false @tab false
+@item @tab @b{Indefinito} @tab Stringa @tab Strnum @tab Numero @tab Regexp @tab Vettore @tab Indefinito
+@item @tab @b{Value cookie} @tab false @tab false @tab false @tab false @tab false @tab false
+@end multitable
+@end ifclear
+
+@ifset SMALLPRINT
+@smallformat
+@multitable {Richiesto} {Value cookie} {Num.} {Num.} {Scal.} {Regexp} {Vett.} {Indef.}
+@headitem @tab @tab String @tab Strn. @tab Num. @tab Regexp @tab Vett. @tab Indef.
+@item @tab @b{Stringa} @tab String @tab String @tab String @tab String @tab false @tab false
+@item @tab @b{Strnum} @tab false @tab Strn. @tab Strn. @tab false @tab false @tab false
+@item @tab @b{Numero} @tab Num. @tab Num. @tab Num. @tab false @tab false @tab false
+@item @b{Tipo} @tab @b{Regexp} @tab false @tab false @tab false @tab Regexp @tab false @tab false
+@item @b{Richiesto} @tab @b{Vettore} @tab false @tab false @tab false @tab false @tab Vett. @tab false
+@item @tab @b{Scalar} @tab Scal. @tab Scal. @tab Scal. @tab Scal. @tab false @tab false
+@item @tab @b{Indefinito} @tab String @tab Strn. @tab Num. @tab Regexp @tab Vett. @tab Indef.
+@item @tab @b{Value cookie} @tab false @tab false @tab false @tab false @tab false @tab false
+@end multitable
+@end smallformat
+@end ifset
+@end ifnotdocbook
+@end ifnotplaintext
+@ifplaintext
+@verbatim
+ +-------------------------------------------------------+
+ | Tipo di valore reale: |
+ +--------+--------+--------+--------+-------+-----------+
+ | Stringa| Strnum | Numero | Regexp |Vettore| Indefinito|
++-----------+-----------+--------+--------+--------+--------+-------+-----------+
+| | Stringa | Stringa| Stringa| Stringa| Stringa| false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Strnum | false | Strnum | Strnum | false | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Numero | Numero | Numero | Numero | false | false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Regexp | false | false | false | Regexp | false | false |
+| Tipo +-----------+--------+--------+--------+--------+-------+-----------+
+|Richiesto: | Vettore | false | false | false | false |Vettore| false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Scalare | Scalare| Scalare| Scalare| Scalare| false | false |
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Indefinito| Stringa| Strnum | Numero | Regexp |Vettore| Indefinito|
+| +-----------+--------+--------+--------+--------+-------+-----------+
+| | Value- | false | false | false | false | false | false |
+| | Cookie | | | | | | |
++-----------+-----------+--------+--------+--------+--------+-------+-----------+
+@end verbatim
+@end ifplaintext
+@end float
+
+@node Accedere ai parametri
+@subsection Accedere ai parametri e aggiornarli
+
+Due funzioni consentono di accedere agli argomenti (parametri)
+passati all'estensione. Esse sono:
+
+@table @code
+@item awk_bool_t get_argument(size_t count,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *risultato);
+Riempie la struttura @code{awk_value_t} puntata da @code{risultato}
+con l'argomento numero @code{count}. Restituisce @dfn{true} se il tipo
+dell'argomento corrisponde
+a quello specificato in @code{wanted}, e @dfn{false} in caso contrario.
+In quest'ultimo caso,
+@code{risultato@w{->}val_type} indica il tipo effettivo dell'argomento
+(@pxref{table-value-types-returned}). La numerazione degli argomenti parte
+da zero: il primo
+argomento @`e il numero zero, il secondo @`e il numero uno, e cos@`{@dotless{i}} via.
+@code{wanted} indica il tipo di valore atteso.
+
+@item awk_bool_t set_argument(size_t count, awk_array_t array);
+Converte un parametro di tipo indefinito in un vettore; ci@`o permette la
+chiamata per riferimento per i vettori. Restituisce @dfn{false} se @code{count} @`e troppo elevato,
+o se il tipo di argomento @`e diverso da @dfn{undefined}.
+@xref{Manipolazione di vettori}
+per ulteriori informazioni riguardo alla creazione di vettori.
+@end table
+
+@node Accedere alla tabella simboli
+@subsection Accedere alla Tabella dei simboli
+@cindex accedere alle variabili globali dalle estensioni
+@cindex variabili globali, accesso dalle estensioni
+@cindex estensioni, accesso alle variabili globali
+
+Due insiemi di routine permettono di accedere alle variabili globali,
+e un insieme consente di creare e rilasciare dei valori nascosti.
+
+@menu
+* Tabella simboli per nome:: Accedere alle variabili per nome.
+* Tabella simboli tramite cookie:: Accedere alle variabili per ``cookie''.
+* Valori nascosti:: Creare e usare valori nascosti.
+@end menu
+
+@node Tabella simboli per nome
+@subsubsection Accedere alle variabili per nome e aggiornarle
+
+Le routine che seguono permettono di raggiungere e aggiornare
+le variabili globali a livello di @command{awk} per nome. Nel gergo dei
+compilatori, gli identificativi di vario tipo sono noti come @dfn{simboli},
+da cui il prefisso ``sym'' nei nomi delle routine. La struttura di dati che
+contiene informazioni sui simboli @`e chiamata @dfn{Tabella dei simboli}
+(@dfn{Symbol table}).
+Le funzioni sono le seguenti:
+
+@table @code
+@item awk_bool_t sym_lookup(const char *name,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *risultato);
+Riempie la struttura @code{awk_value_t} puntata da @code{risultato}
+con il valore della variabile il cui nome @`e nella stringa @code{name},
+che @`e una normale stringa di caratteri C.
+@code{wanted} indica il tipo di valore atteso.
+La funzione restituisce @dfn{true} se il tipo effettivo della variabile @`e quello
+specificato in @code{wanted}, e @dfn{false} in caso contrario.
+In quest'ultimo caso, @code{risultato>val_type} indica il tipo effettivo
+della variabile
+(@pxref{table-value-types-returned}).
+
+@item awk_bool_t sym_update(const char *name, awk_value_t *valore);
+Aggiorna la variabile il cui nome @`e contenuto nella stringa @code{name},
+che @`e una normale stringa di caratteri C.
+La variabile @`e aggiunta alla Tabella dei simboli di @command{gawk},
+se non @`e gi@`a presente. Restituisce @dfn{true} se tutto @`e andato bene, e
+@dfn{false} in caso contrario.
+
+La modifica del tipo (da scalare a vettoriale o viceversa) di una variabile
+gi@`a esistente @emph{non} @`e consentito, e questa routine non pu@`o neppure
+essere usata per aggiornare un vettore.
+Questa routine non pu@`o essere usata per modificare nessuna delle variabili
+predefinite (come @code{ARGC} o @code{NF}).
+@end table
+
+Un'estensione pu@`o andare a cercare il valore delle variabili speciali di
+@command{gawk}.
+Tuttavia, con l'eccezione del vettore @code{PROCINFO}, un'estensione
+non pu@`o cambiare alcuna di queste variabili.
+
+@node Tabella simboli tramite cookie
+@subsubsection Accedere alle variabili per ``cookie'' e aggiornarle
+
+Uno @dfn{scalar cookie} @`e un puntatore nascosto (@dfn{opaque handle}) che
+fornisce accesso a una
+variabile globale o a un vettore. Si tratta di un'ottimizzazione, per evitare
+di ricercare variabili nella Tabella dei simboli di @command{gawk} ogni volta
+che un accesso @`e necessario. Questo
+argomento @`e gi@`a stato trattato in precedenza, nella
+@ref{Tipi di dati generali}.
+
+Le funzioni seguenti servono per gestire gli @dfn{scalar cookie}:
+
+@table @code
+@item awk_bool_t sym_lookup_scalar(awk_scalar_t cookie,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *risultato);
+Ottiene il valore corrente di uno @dfn{scalar cookie}.
+Una volta ottenuto lo @dfn{scalar cookie} usando @code{sym_lookup()}, si
+pu@`o usare questa funzione per accedere al valore della variabile in modo
+pi@`u efficiente.
+Restituisce @dfn{false} se il valore non @`e disponibile.
+
+@item awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *valore);
+Aggiorna il valore associato con uno @dfn{scalar cookie}.
+Restituisce @dfn{false} se il nuovo valore non @`e del tipo
+@code{AWK_STRING}, @code{AWK_STRNUM}, @code{AWK_REGEX} o @code{AWK_NUMBER}.
+Anche in questo caso, le variabili predefinite non possono essere aggiornate.
+@end table
+
+Non @`e immediatamente evidente come si lavora con gli @dfn{scalar cookie} o
+quale sia la loro vera @i{ragion d'essere}. In teoria, le routine
+@code{sym_lookup()} e @code{sym_update()} sono tutto ci@`o che occorre per
+lavorare con le variabili. Per esempio, ci potrebbe essere un codice che
+ricerca il valore di una variabile, valuta una condizione, e potrebbe
+poi cambiare il valore della variabile a seconda dei risultati della
+valutazione in modo simile a questo:
+
+@example
+/* do_magic --- fai qualcosa di veramente grande */
+
+static awk_value_t *
+do_magic(int nargs, awk_value_t *risultato)
+@{
+ awk_value_t valore;
+
+ if ( sym_lookup("MAGIC_VAR", AWK_NUMBER, & valore)
+ && qualche_condizione(valore.num_valore)) @{
+ valore.num_valore += 42;
+ sym_update("MAGIC_VAR", & valore);
+ @}
+
+ return make_number(0.0, risultato);
+@}
+@end example
+
+@noindent
+Questo codice sembra (ed @`e) semplice e immediato. Qual @`e il problema?
+
+Beh, si consideri cosa succede se un qualche codice a livello di @command{awk}
+associato con l'estensione richiama la funzione @code{magic()}
+(implementata in linguaggio C da @code{do_magic()}), una volta per ogni
+record, mentre si stanno elaborando
+file contenenti migliaia o milioni di record.
+La variabile @code{MAGIC_VAR} viene ricercata nella Tabella dei simboli una o due
+volte per ogni richiamo della funzione!
+
+La ricerca all'interno della Tabella dei simboli @`e in realt@`a una pura perdita
+di tempo; @`e molto pi@`u efficiente
+ottenere un @dfn{value cookie} che rappresenta la variabile, e usarlo per
+ottenere il valore della variabile e aggiornarlo a seconda della
+necessit@`a.@footnote{La differenza @`e misurabile e indubbiamente reale.
+Fidatevi.}
+
+Quindi, la maniera per usare i valori-cookie @`e la seguente. Per prima
+cosa, la variabile di estensione va messa nella Tabella dei simboli di
+@command{gawk} usando @code{sym_update()}, come al solito. Poi si deve ottenere
+uno @dfn{scalar cookie} per la
+variabile usando @code{sym_lookup()}:
+
+@example
+static awk_scalar_t magic_var_cookie; /* cookie per MAGIC_VAR */
+
+static void
+inizializza_estensione()
+@{
+ awk_value_t valore;
+
+ /* immettere il valore iniziale */
+ sym_update("MAGIC_VAR", make_number(42.0, & valore));
+
+ /* ottenere il @dfn{value cookie} */
+ sym_lookup("MAGIC_VAR", AWK_SCALAR, & valore);
+
+ /* salvarlo per dopo */
+ magic_var_cookie = valore.scalar_cookie;
+ @dots{}
+@}
+@end example
+
+Dopo aver fatto questo, si usino le routine descritte in questa @value{SECTION}
+per ottenere e modificare
+il valore usando il @dfn{value cookie}. Quindi, @code{do_magic()} diviene ora
+qualcosa del tipo:
+
+@example
+/* do_magic --- fai qualcosa di veramente grande */
+
+static awk_value_t *
+do_magic(int nargs, awk_value_t *risultato)
+@{
+ awk_value_t valore;
+
+ if ( sym_lookup_scalar(magic_var_cookie, AWK_NUMBER, & valore)
+ && qualche_condizione(valore.num_valore)) @{
+ valore.num_valore += 42;
+ sym_update_scalar(magic_var_cookie, & valore);
+ @}
+ @dots{}
+
+ return make_number(0.0, risultato);
+@}
+@end example
+
+@quotation NOTA
+Il codice appena visto omette il controllo di eventuali errori, per
+amor di semplicit@`a. Il codice dell'estensione dovrebbe essere pi@`u complesso
+e controllare attentamente i valori
+restituiti dalle funzioni dell'API.
+@end quotation
+
+@node Valori nascosti
+@subsubsection Creare e usare valori nascosti
+
+Le routine in questa @value{SECTION} permettono di creare e rilasciare
+valori nascosti. Come gli @dfn{scalar cookie}, in teoria i valori nascosti
+non sono necessari. Si possono creare numeri e stringhe usando
+le funzioni descritte
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzioni di costruzione}. Si possono poi assegnare
+quei valori a delle variabili usando @code{sym_update()}
+o @code{sym_update_scalar()}, come si preferisce.
+
+Tuttavia, si pu@`o comprendere l'utilit@`a di avere dei valori nascosti
+se si pone mente al fatto che la memoria di @emph{ogni} valore di stringa
+@emph{deve} essere ottenuta tramite @code{gawk_malloc()},
+@code{gawk_calloc()} o @code{gawk_realloc()}.
+Se ci sono 20 variabili, e tutte hanno per valore la stessa stringa,
+si devono creare 20 copie identiche della stringa.@footnote{I valori
+numerici creano molti meno problemi, in quanto richiedono solo una variabile
+C @code{double} (8 byte) per contenerli.}
+
+Chiaramente @`e pi@`u efficiente, se possibile, creare il valore una sola volta,
+e fare in modo che @command{gawk} utilizzi quell'unico valore per molte
+variabili. Questo @`e ci@`o che la routine in
+@ifnotinfo
+questa
+@end ifnotinfo
+@ifinfo
+questo
+@end ifinfo
+@value{SECTION} permette
+di fare. Le funzioni sono le seguenti:
+
+@table @code
+@item awk_bool_t create_value(awk_value_t *valore, awk_value_cookie_t *risultato);
+Crea una stringa o un valore numerico nascosti, da @code{valore}, in
+vista di un successivo assegnamento di valore. Sono consentiti solo valori di
+tipo @code{AWK_NUMBER}, @code{AWK_REGEX} ed @code{AWK_STRING}.
+Ogni altro tipo @`e rifiutato.
+Il tipo @code{AWK_UNDEFINED} potrebbe essere consentito, ma in questo caso
+l'efficienza del programma ne soffrirebbe.
+
+@item awk_bool_t release_value(awk_value_cookie_t vc);
+Libera la memoria associata con un @dfn{value cookie} ottenuto mediante
+@code{create_value()}.
+@end table
+
+Si usano i @dfn{value cookie} in modo dimile a quello con cui si usano gli
+@dfn{scalar cookie}.
+Nella routine di inizializzazione dell'estensione, si crea il
+@dfn{value cookie}:
+
+@example
+static awk_value_cookie_t answer_cookie; /* static @dfn{value cookie} */
+
+static void
+inizializza_estensione()
+@{
+ awk_value_t value;
+ char *long_string;
+ size_t long_string_len;
+
+ /* codice precedente */
+ @dots{}
+ /* @dots{} riempire long_string e long_string_len @dots{} */
+ make_malloced_string(long_string, long_string_len, & value);
+ create_value(& value, & answer_cookie); /* creare cookie */
+ @dots{}
+@}
+@end example
+
+Una volta che il valore @`e creato, si pu@`o usare come valore per un numero
+qualsiasi di variabili:
+
+@example
+static awk_value_t *
+do_magic(int nargs, awk_value_t *risultato)
+@{
+ awk_value_t new_value;
+
+ @dots{} /* come in precedenza */
+
+ value.val_type = AWK_VALUE_COOKIE;
+ value.value_cookie = answer_cookie;
+ sym_update("VAR1", & value);
+ sym_update("VAR2", & value);
+ @dots{}
+ sym_update("VAR100", & value);
+ @dots{}
+@}
+@end example
+
+@noindent
+Usare @dfn{value cookie} in questo modo permette di risparmiare parecchia
+memoria, poich@'e tutte le variabili da @code{VAR1} a @code{VAR100} condividono
+lo stesso valore.
+
+Ci si potrebbe chiedere, ``Questa condivisione crea problemi?
+Cosa succede se il codice @command{awk} assegna un nuovo valore a @code{VAR1};
+sono modificate anche tutte le altre variabili?''
+
+Buona domanda! La risposta @`e che no, non @`e un problema.
+Internamente, @command{gawk} usa
+@dfn{un contatore dei riferimenti alle stringhe}. Questo significa
+che molte variabili possono condividere lo stesso valore di tipo stringa,
+e @command{gawk} mantiene traccia del loro uso. Quando il valore di
+una variabile viene modificato, @command{gawk} semplicemente diminuisce di
+uno il contatore dei riferimenti del vecchio valore, e aggiorna la variabile
+perch@'e usi il nuovo valore.
+
+Infine, come parte della pulizia al termine del programma
+(@pxref{Funzioni di exit callback})
+si deve liberare ogni valore nascosto che era stato creato, usando
+la funzione @code{release_value()}.
+
+@node Manipolazione di vettori
+@subsection Manipolazione di vettori
+@cindex vettori, manipolazione nelle estensioni
+@cindex estensioni, manipolazione di vettori
+
+La struttura di dati primaria@footnote{D'accordo, l'unica struttura di dati.}
+in @command{awk} @`e il vettore associativo
+@iftex
+(@pxrefil{Vettori}).
+@end iftex
+@ifnottex
+(@pxref{Vettori}).
+@end ifnottex
+Le estensioni devono essere in grado di manipolare vettori @command{awk}.
+L'API fornisce varie strutture di dati per lavorare con vettori,
+funzioni per lavorare con singoli elementi di un vettore, e funzioni per
+lavorare con interi vettori. @`E prevista anche la possibilit@`a di
+``appiattire'' un vettore in modo da rendere facile a un programma scritto in
+C la ``visita'' di tutti gli elementi del vettore.
+Le strutture dati per i vettori sono facilmente integrabili con le
+strutture dati per variabili scalari, per facilitare sia l'elaborazione, sia
+la creazione di @dfn{veri} vettori di vettori (@pxref{Tipi di dati generali}).
+
+@menu
+* Tipi di dati per i vettori:: Tipi dati per lavorare coi vettori.
+* Funzioni per i vettori:: Funzioni per lavorare coi vettori.
+* Appiattimento di vettori:: Come appiattire i vettori.
+* Creazione di vettori:: Come creare e popolare vettori.
+@end menu
+
+@node Tipi di dati per i vettori
+@subsubsection Tipi di dati per i vettori
+
+I tipi di dato associati con i vettori sono i seguenti:
+
+@table @code
+@item typedef void *awk_array_t;
+Se si richiede il valore di una variabile contenuta in un vettore, si ottiene
+un valore del tipo @code{awk_array_t}. Questo valore @`e
+@dfn{opaco}@footnote{@`E anche un
+``cookie,'' ma gli sviluppatori di @command{gawk} hanno preferito non abusare
+di questo termine.} per l'estensione; identifica in maniera univoca il
+vettore ma pu@`o solo essere usato come parametro di una funzione dell'API,
+o essere ricevuto da una funzione dell'API. Questo @`e molto simile al modo
+in cui i valori @samp{FILE *} sono usati con le routine di libreria di
+@code{<stdio.h>}.
+
+@item typedef struct awk_element @{
+@itemx @ @ @ @ /* puntatore di servizio
+@itemx @ @ @ @ a lista collegata, non usato da gawk */
+@itemx @ @ @ @ struct awk_element *next;
+@itemx @ @ @ @ enum @{
+@itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DEFAULT = 0,@ @ /* impostato da gawk */
+@itemx @ @ @ @ @ @ @ @ AWK_ELEMENT_DELETE = 1@ @ @ @ /* impostato dall'estensione */
+@itemx @ @ @ @ @} flags;
+@itemx @ @ @ @ awk_value_t index;
+@itemx @ @ @ @ awk_value_t value;
+@itemx @} awk_element_t;
+@code{awk_element_t} @`e un elemento di vettore ``appiattito''.
+@command{awk} produce un vettore di questo tipo all'interno della struttura
+@code{awk_flat_array_t} (si veda poco pi@`u avanti).
+Singoli elementi di vettore possono essere marcati per essere cancellati.
+Nuovi elementi del vettore devono essere aggiunti individualmente, uno per
+volta, usando una funzione API apposita. I campi sono i seguenti:
+
+@c nested table
+@table @code
+@item struct awk_element *next;
+Questo puntatore @`e presente come ausilio a chi scrive un'estensione.
+Permette a un'estensione di creare una lista collegata (@dfn{linked list}) di
+nuovi elementi che possono essere aggiunti a un vettore con un
+singolo ciclo che percorre tutta la lista.
+
+@item enum @{ @dots{} @} flags;
+Un insieme di valori di flag che passano informazione tra l'estensione
+e @command{gawk}. Per ora c'@`e solo un flag disponibile:
+@code{AWK_ELEMENT_DELETE}.
+Se lo si imposta, @command{gawk} elimina l'elemento in questione dal vettore
+originale, dopo che il vettore ``appiattito'' @`e stato rilasciato.
+
+@item index
+@itemx value
+L'indice e il valore di un elemento, rispettivamente.
+@emph{Tutta} la memoria puntata da @code{index} e @code{valore} appartiene
+a @command{gawk}.
+@end table
+
+@item typedef struct awk_flat_array @{
+@itemx @ @ @ @ awk_const void *awk_const opaque1;@ @ @ @ /* per uso di gawk */
+@itemx @ @ @ @ awk_const void *awk_const opaque2;@ @ @ @ /* per uso di gawk */
+@itemx @ @ @ @ awk_const size_t count;@ @ @ @ @ /* quanti elementi nel vettore */
+@itemx @ @ @ @ awk_element_t elements[1];@ @ /* saranno ``appiattiti'' */
+@itemx @} awk_flat_array_t;
+Questo @`e un vettore appiattito. Quando un'estensione ottiene da
+@command{gawk} questa struttura, il vettore @code{elements} ha una dimensione
+reale di @code{count} elementi.
+I puntatori @code{opaque1} e @code{opaque2} sono per uso di @command{gawk};
+come tali, sono marcati come @code{awk_const} in modo che l'estensione non
+possa modificarli.
+@end table
+
+@node Funzioni per i vettori
+@subsubsection Funzioni per lavorare coi vettori
+
+Le funzioni seguenti permettono di gestire singoli elementi di un vettore:
+
+@table @code
+@item awk_bool_t get_element_count(awk_array_t a_cookie, size_t *count);
+Per il vettore rappresentato da @code{a_cookie}, restituisce in @code{*count}
+il numero di elementi in esso contenuti. Ogni sottovettore @`e conteggiato come
+se fosse un solo elemento.
+Restituisce @dfn{false} se si verifica un errore.
+
+@item awk_bool_t get_array_element(awk_array_t a_cookie,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_value_t *const index,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_valtype_t wanted,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_value_t *risultato);
+Per il vettore rappresentato da @code{a_cookie}, restituisce in @code{*risultato}
+il valore dell'elemento il cui indice @`e @code{index}.
+@code{wanted} specifica il tipo di valore che si vuole ritrovare.
+Restituisce @dfn{false} se @code{wanted} non coincide con il tipo di dato o
+se @code{index} non @`e nel vettore (@pxref{table-value-types-returned}).
+
+Il valore per @code{index} pu@`o essere numerico, nel qual caso @command{gawk}
+lo converte in una stringa. Usare valori non interi @`e possibile, ma
+richiede di comprendere il modo con cui tali valori sono convertiti in stringhe
+(@pxref{Conversione}); per questo motivo, @`e meglio usare numeri interi.
+
+Come per @emph{tutte} le stringhe passate a @command{gawk} da
+un'estensione, la memoria che contiene il valore della stringa con chiave
+@code{index} deve essere stata acquisita utilizzando le funzioni
+@code{gawk_malloc()}, @code{gawk_calloc()} o @code{gawk_realloc()}, e
+@command{gawk} rilascer@`a (al momento opportuno) la relativa memoria.
+
+@item awk_bool_t set_array_element(awk_array_t a_cookie,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const@ awk_value_t *const index,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const@ awk_value_t *const value);
+Nel vettore rappresentato da @code{a_cookie}, crea o modifica
+l'elemento il cui indice @`e contenuto in @code{index}.
+I vettori @code{ARGV} ed @code{ENVIRON} non possono essere modificati,
+mentre il vettore @code{PROCINFO} @`e modificabile.
+
+@item awk_bool_t set_array_element_by_elem(awk_array_t a_cookie,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_element_t element);
+Come @code{set_array_element()}, ma prende l'indice @code{index} e
+il valore @code{value} da @code{element}. Questa @`e una macro di utilit@`a.
+
+@item awk_bool_t del_array_element(awk_array_t a_cookie,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_value_t* const index);
+Elimina dal vettore, rappresentato da @code{a_cookie}, l'elemento con
+l'indice specificato.
+Restituisce @dfn{true} se l'elemento @`e stato rimosso o @dfn{false} se
+l'elemento non era presente nel vettore.
+@end table
+
+Le seguenti funzioni operano sull'intero vettore:
+
+@table @code
+@item awk_array_t create_array(void);
+Crea un nuovo vettore a cui si possono aggiungere elementi.
+@xref{Creazione di vettori} per una trattazione su come
+creare un nuovo vettore e aggiungervi elementi.
+
+@item awk_bool_t clear_array(awk_array_t a_cookie);
+Svuota il vettore rappresentato da @code{a_cookie}.
+Restituisce @dfn{false} in presenza di qualche tipo di problema, @dfn{true}
+in caso contrario. Il vettore non viene eliminato ma, dopo aver chiamato
+questa funzione, resta privo di elementi. Questo @`e equivalente a usare
+l'istruzione @code{delete} (@pxref{Cancellazione}).
+
+@item awk_bool_t flatten_array_typed(awk_array_t a_cookie, awk_flat_array_t **data, awk_valtype_t index_type, awk_valtype_t value_type);
+Per il vettore rappresentato da @code{a_cookie}, crea una struttura
+@code{awk_flat_array_t} e la riempie con indici e valori del tipo richiesto.
+Imposta il puntatore il cui indirizzo @`e passato in @code{data} per puntare a
+questa struttura.
+Restituisce @dfn{true} se tutto va bene o @dfn{false} in caso contrario.
+@ifset FOR_PRINT
+Si veda la prossima @value{SECTION}
+@end ifset
+@ifclear FOR_PRINT
+@xref{Appiattimento di vettori},
+@end ifclear
+per una trattazione su come appiattire un vettore per poterci lavorare.
+
+@item awk_bool_t flatten_array(awk_array_t a_cookie, awk_flat_array_t **data);
+Per il vettore rappresentato da @code{a_cookie}, crea una struttura
+@code{awk_flat_array_t} e la riempie con indici di tipo @code{AWK_STRING} e
+valori @code{AWK_UNDEFINED}.
+Questa funzione @`e resa obsoleta da @code{flatten_array_typed()}.
+@`E fornita come macro, e mantenuta per convenienza e per compatibilit@`a a
+livello di codice sorgente con la precedente versione dell'API.
+
+@item awk_bool_t release_flattened_array(awk_array_t a_cookie,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ awk_flat_array_t *data);
+Quando si @`e finito di lavorare con un vettore appiattito, si liberi la
+memoria usando questa funzione. Occorre fornire sia il cookie del vettore
+originale, sia l'indirizzo della struttura da liberare,
+@code{awk_flat_array_t}.
+La funzione restituisce @dfn{true} se tutto va bene, @dfn{false} in caso contrario.
+@end table
+
+@node Appiattimento di vettori
+@subsubsection Lavorare con tutti gli elementi di un vettore
+
+@dfn{Appiattire} un vettore vuol dire creare una struttura che
+rappresenta l'intero vettore in modo da facilitare la visita
+dell'intero vettore da parte del codice in C . Parte del codice in
+@file{extension/testext.c} fa questo, ed @`e anche un bell'esempio
+di come utilizzare l'API.
+
+Questa parte del codice sorgente sar@`a descritta un po' per volta.
+Ecco, per iniziare, lo script @command{gawk} che richiama l'estensione di test:
+
+@example
+@@load "testext"
+BEGIN @{
+ n = split("blacky rusty sophie raincloud lucky", pets)
+ printf("pets ha %d elementi\n", length(pets))
+ ret = dump_array_and_delete("pets", "3")
+ printf("dump_array_and_delete(pets) ha restituito %d\n", ret)
+ if ("3" in pets)
+ printf("dump_array_and_delete() NON ha rimosso l'indice \"3\"!\n")
+ else
+ printf("dump_array_and_delete() ha rimosso l'indice \"3\"!\n")
+ print ""
+@}
+@end example
+
+@noindent
+Questo codice crea un vettore usando la funzione @code{split()}
+(@pxref{Funzioni per stringhe})
+e poi chiama @code{dump_array_and_delete()}. Questa funzione ricerca
+il vettore il cui nome @`e passato come primo argomento, ed
+elimina l'elemento il cui indice @`e passato come secondo argomento.
+Il codice @command{awk} stampa poi il valore restituito e controlla che
+l'elemento sia stato effettivamente cancellato. Ecco il codice C che
+costituisce la funzione
+@code{dump_array_and_delete()}. @`E stato leggermente modificato per facilitare
+l'esposizione.
+
+La prima parte dichiara variabili, imposta il valore di ritorno di default
+in @code{risultato}, e controlla che la funzione
+sia stata chiamata con il numero corretto di argomenti:
+
+@example
+static awk_value_t *
+dump_array_and_delete(int nargs, awk_value_t *risultato)
+@{
+ awk_value_t valore, valore2, valore3;
+ awk_flat_array_t *flat_array;
+ size_t count;
+ char *name;
+ int i;
+
+ assert(risultato != NULL);
+ make_number(0.0, risultato);
+
+ if (nargs != 2) @{
+ printf("dump_array_and_delete: nargs errato "
+ "(%d dovrebbe essere 2)\n", nargs);
+ goto out;
+ @}
+@end example
+
+La funzione poi prosegue un passo per volta, come segue. Il primo passo @`e
+ricuperare il nome del vettore, passato come primo argomento, seguito dal
+vettore stesso. Se una di queste operazioni non riesce, viene stampato un
+messaggio di errore e si ritorna al chiamante:
+
+@example
+ /* trasforma in un vettore piatto il vettore
+ passato come argomento e lo stampa */
+ if (get_argument(0, AWK_STRING, & value)) @{
+ name = valore.str_value.str;
+ if (sym_lookup(name, AWK_array, & value2))
+ printf("dump_array_and_delete: sym_lookup di %s effettuato\n",
+ name);
+ else @{
+ printf("dump_array_and_delete: sym_lookup di %s non riuscito\n",
+ name);
+ goto out;
+ @}
+ @} else @{
+ printf("dump_array_and_delete: get_argument(0) non riuscito\n");
+ goto out;
+ @}
+@end example
+
+Per controllo, e per assicurarsi che il codice C veda
+lo stesso numero di elementi del codice @command{awk},
+il secondo passo @`e quello di ottenere il numero di elementi nel vettore
+e stamparlo:
+
+@example
+ if (! get_element_count(valore2.array_cookie, & count)) @{
+ printf("dump_array_and_delete: get_element_count non riuscito\n");
+ goto out;
+ @}
+
+ printf("dump_array_and_delete: il vettore in input ha %lu elementi\n",
+ (unsigned long) count);
+@end example
+
+Il terzo passo @`e quello di appiattire il vettore, e quindi
+controllare che il numero di elementi nella struttura @code{awk_flat_array_t}
+sia uguale a quello appena trovato:
+
+@example
+ if (! flatten_array_typed(valore2.array_cookie, & flat_array,
+ AWK_STRING, AWK_UNDEFINED)) @{
+ printf("dump_array_and_delete: non sono riuscito ad appiattire \
+il vettore\n");
+ goto out;
+ @}
+
+ if (flat_array->count != count) @{
+ printf("dump_array_and_delete: flat_array->count (%lu)"
+ " != count (%lu)\n",
+ (unsigned long) flat_array->count,
+ (unsigned long) count);
+ goto out;
+ @}
+@end example
+
+Il quarto passo @`e ritrovare l'indice dell'elemento
+da eliminare, che era stato passato come secondo argomento.
+Va tenuto presente che i contatori di argomenti passati a @code{get_argument()}
+partono da zero, e che quindi il secondo argomento @`e quello numero uno:
+
+@example
+ if (! get_argument(1, AWK_STRING, & value3)) @{
+ printf("dump_array_and_delete: get_argument(1) non riuscito\n");
+ goto out;
+ @}
+@end example
+
+Il quinto passo @`e quello in cui si fa il ``vero lavoro''. La funzione esegue
+un ciclo su ogni elemento nel vettore, stampando i valori degli indici e
+degli elementi. Inoltre, dopo aver trovato, tramite l'indice, l'elemento
+che si vorrebbe eliminare, la funzione imposta il @dfn{bit}
+@code{AWK_ELEMENT_DELETE} nel campo @code{flags}
+dell'elemento. Quando il vettore @`e stato interamente percorso, @command{gawk}
+visita il vettore appiattito, ed elimina ogni elemento in cui il relativo
+@dfn{bit} della flag sia impostato:
+
+@example
+ for (i = 0; i < flat_array->count; i++) @{
+ printf("\t%s[\"%.*s\"] = %s\n",
+ name,
+ (int) flat_array->elements[i].index.str_value.len,
+ flat_array->elements[i].index.str_value.str,
+ valrep2str(& flat_array->elements[i].valore));
+
+ if (strcmp(valore3.str_value.str,
+ flat_array->elements[i].index.str_value.str) == 0) @{
+ flat_array->elements[i].flags |= AWK_ELEMENT_DELETE;
+ printf("dump_array_and_delete: ho marcato l'elemento \"%s\" "
+ "per eliminazione\n",
+ flat_array->elements[i].index.str_value.str);
+ @}
+ @}
+@end example
+
+Il sesto passo @`e liberare il vettore appiattito. Questo segnala a
+@command{gawk} che l'estensione non sta pi@`u usando il vettore,
+e che dovrebbe eliminare gli elementi marcati per l'eliminazione.
+@command{gawk} libera anche ogni area di memoria che era stata allocata,
+e quindi non si dovrebbe pi@`u usare il puntatore (@code{flat_array} in
+questo codice) dopo aver chiamato @code{release_flattened_array()}:
+
+@example
+ if (! release_flattened_array(valore2.array_cookie, flat_array)) @{
+ printf("dump_array_and_delete: non riesco a liberare \
+il vettore appiattito\n");
+ goto out;
+ @}
+@end example
+
+Infine, poich@'e tutto @`e andato bene, la funzione imposta il codice di ritorno
+a "successo", e lo restituisce quando esce:
+
+@example
+ make_number(1.0, risultato);
+out:
+ return risultato;
+@}
+@end example
+
+Ecco l'output ottenuto eseguendo questa parte del test:
+
+@example
+pets ha 5 elementi
+dump_array_and_delete: sym_lookup di pets effettuato
+dump_array_and_delete: il vettore in input ha 5 elementi
+ pets["1"] = "blacky"
+ pets["2"] = "rusty"
+ pets["3"] = "sophie"
+dump_array_and_delete: ho marcato l'elemento "3" per eliminazione
+ pets["4"] = "raincloud"
+ pets["5"] = "lucky"
+dump_array_and_delete(pets) ha restituito 1
+dump_array_and_delete() ha rimosso l'indice "3"!
+@end example
+
+@node Creazione di vettori
+@subsubsection Come creare e popolare vettori
+
+Oltre a lavorare con vettori creati da codice @command{awk}, si possono
+creare vettori a cui aggiungere elementi secondo le esigenze, che poi
+il codice @command{awk} pu@`o utilizzare e manipolare.
+
+Ci sono due punti importanti da tener presente quando di creano vettori dal
+codice di un'estensione:
+
+@itemize @value{BULLET}
+@item
+Il vettore appena creato deve essere subito messo nella Tabella dei simboli di
+@command{gawk}. Solo dopo aver fatto questo @`e possibile aggiungere elementi
+al vettore.
+
+@ignore
+Strictly speaking, this is required only
+for arrays that will have subarrays as elements; however it is
+a good idea to always do this. This restriction may be relaxed
+in a subsequent revision of the API.
+@end ignore
+
+Analogamente, se si installa un nuovo vettore come sottovettore di
+un vettore gi@`a esistente,
+occorre prima aggiungere il nuovo vettore al suo "genitore" per poter poi
+aggiungere degli elementi allo stesso.
+
+Quindi, il modo giusto per costruire un vettore @`e di lavorare ``dall'alto
+verso il basso''. Creare il vettore, e subito aggiungerlo alla Tabella dei
+simboli di @command{gawk} usando @code{sym_update()}, o installarlo come
+elemento in un vettore gi@`a esistente usando @code{set_array_element()}.
+Un esempio di codice @`e fornito pi@`u sotto.
+
+@item
+Per come funziona internamente @command{gawk}, dopo aver usato
+@code{sym_update()} per definire un vettore
+in @command{gawk}, si deve innanzitutto ricuperare il @dfn{cookie}
+del vettore dal valore passato a @command{sym_update()}, in questo modo:
+
+@example
+awk_value_t val;
+awk_array_t new_array;
+
+new_array = create_array();
+val.val_type = AWK_ARRAY;
+val.array_cookie = new_array;
+
+/* aggiunge il vettore alla Tabella dei simboli */
+sym_update("array", & val);
+
+new_array = val.array_cookie; /* QUESTO @`E OBBLIGATORIO */
+@end example
+
+Se si sta installando un vettore come sottovettore, occorre anche
+ricuperare il @dfn{cookie} del vettore dopo aver chiamato @code{set_element()}.
+@end itemize
+
+Il seguente codice C @`e una semplice estensione di test per creare un vettore
+con due elementi normali e con un sottovettore. Le direttive iniziali
+@code{#include} e le solite dichiarazione di variabili sono state omesse per
+amor di brevit@`a
+(@pxref{Codice predefinito di un'estensione API}).
+Il primo passo @`e creare un nuovo vettore e poi aggiungerlo alla
+Tabella dei simboli:
+
+@example
+@ignore
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "gawkapi.h"
+
+static const gawk_api_t *api; /* per far funzionare le macro di utilit@`a */
+static awk_ext_id_t *ext_id;
+static const char *ext_version = "testarray extension: version 1.0";
+
+int plugin_is_GPL_compatible;
+
+@end ignore
+/* create_new_array --- creare un vettore denominato */
+
+static void
+create_new_array()
+@{
+ awk_array_t a_cookie;
+ awk_array_t sottovettore;
+ awk_value_t index, valore;
+
+ a_cookie = create_array();
+ valore.val_type = AWK_array;
+ valore.array_cookie = a_cookie;
+
+ if (! sym_update("new_array", & value))
+ printf("create_new_array: sym_update(\"nuovo_vettore\") \
+non riuscito!\n");
+ a_cookie = valore.array_cookie;
+@end example
+
+@noindent
+Si noti come @code{a_cookie} @`e reimpostato dal campo @code{array_cookie}
+nella struttura @code{valore}.
+
+Il secondo passo aggiunge due elementi normali a @code{nuovo_vettore}:
+
+@example
+ (void) make_const_string("salve", 5, & index);
+ (void) make_const_string("mondo", 5, & value);
+ if (! set_array_element(a_cookie, & index, & value)) @{
+ printf("fill_in_array: set_array_element non riuscito\n");
+ return;
+ @}
+
+ (void) make_const_string("risposta", 8, & index);
+ (void) make_number(42.0, & value);
+ if (! set_array_element(a_cookie, & index, & value)) @{
+ printf("fill_in_array: set_array_element non riuscito\n");
+ return;
+ @}
+@end example
+
+Il terzo passo @`e creare il sottovettore e aggiungerlo al vettore:
+
+@example
+ (void) make_const_string("sottovettore", 12, & index);
+ sottovettore = create_array();
+ valore.val_type = AWK_array;
+ valore.array_cookie = subarray;
+ if (! set_array_element(a_cookie, & index, & value)) @{
+ printf("fill_in_array: set_array_element non riuscito\n");
+ return;
+ @}
+ sottovettore = valore.array_cookie;
+@end example
+
+Il passo finale @`e di aggiungere al sottovettore un suo proprio elemento:
+
+@example
+ (void) make_const_string("pippo", 5, & index);
+ (void) make_const_string("pluto", 5, & value);
+ if (! set_array_element(sottovettore, & index, & value)) @{
+ printf("fill_in_array: set_array_element non riuscito\n");
+ return;
+ @}
+@}
+@ignore
+static awk_ext_func_t func_table[] = @{
+ @{ NULL, NULL, 0 @}
+@};
+
+/* init_testarray --- funzione ulteriore di inizializzazione */
+
+static awk_bool_t init_testarray(void)
+@{
+ create_new_array();
+
+ return awk_true;
+@}
+
+static awk_bool_t (*init_func)(void) = init_testarray;
+
+dl_load_func(func_table, testarray, "")
+@end ignore
+@end example
+
+Ecco uno script di esempio che carica l'estensione
+e quindi stampa il valore di tutti gli elementi del vettore,
+invocando nuovamente se stessa nel caso che un particolare
+elemento sia a sua volta un vettore:
+
+@example
+@@load "subarray"
+
+function dumparray(name, vettore, i)
+@{
+ for (i in vettore)
+ if (isarray(vettore[i]))
+ dumparray(name "[\"" i "\"]", vettore[i])
+ else
+ printf("%s[\"%s\"] = %s\n", name, i, vettore[i])
+@}
+
+BEGIN @{
+ dumparray("new_array", new_array);
+@}
+@end example
+
+Ecco il risultato dell'esecuzione dello script:
+
+@example
+$ @kbd{AWKLIBPATH=$PWD ./gawk -f subarray.awk}
+@print{} new_array["sottovettore"]["pippo"] = pluto
+@print{} new_array["salve"] = mondo
+@print{} new_array["risposta"] = 42
+@end example
+
+@noindent
+(@xref{Trovare le estensioni} per ulteriori dettagli sulla
+variabile d'ambiente @env{AWKLIBPATH}.)
+
+@node Ridirezione API
+@subsection Accedere alle ridirezioni e modificarle
+
+La seguente funzione consente alle estensioni di accedere e di manipolare
+delle ridirezioni.
+
+@table @code
+@item awk_bool_t get_file(const char *name,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ size_t name_len,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const char *tipofile,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ int fd,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_input_buf_t **ibufp,
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ const awk_output_buf_t **obufp);
+Ricerca il file @code{name} nella tabella interna di ridirezione di
+@command{gawk}.
+Se @code{name} @`e @code{NULL} o @code{name_len} @`e zero, restituisce
+i dati del file in input correntemente aperto il cui nome @`e memorizzato in
+@code{FILENAME}.
+(Questa chiamata non usa l'argomento @code{filetype}, che, quindi, pu@`o essere
+lasciato indefinito).
+Se il file non @`e gi@`a aperto, tenta di aprirlo.
+L'argomento @code{filetype} deve terminare con uno zero binario, e dovrebbe
+dovrebbe avere uno di questi valori:
+
+@table @code
+@item ">"
+Un file aperto in output.
+
+@item ">>"
+Un file aperto in output, record aggiunti a fine file,
+dopo quelli gi@`a esistenti [@dfn{append}].
+
+@item "<"
+Un file aperto in input.
+
+@item "|>"
+Una @dfn{pipe} aperta in output.
+
+@item "|<"
+Una @dfn{pipe} aperta in input.
+
+@item "|&"
+Un coprocesso bidirezionale.
+@end table
+
+In caso di errore, restituisce il valore @code{@dfn{awk_false}}.
+Altrimenti, restituisce
+@code{@dfn{awk_true}}, insieme a ulteriori informazioni sulla ridirezione
+nei puntatori @code{ibufp} e @code{obufp}.
+Per ridirezioni di input il valore @code{*ibufp} non dovrebbe essere
+@code{NULL}, mentre @code{*obufp} dovrebbe essere @code{NULL}.
+Per ridirezioni di output,
+il valore di @code{*obufp} non dovrebbe essere @code{NULL}, e @code{*ibufp}
+dovrebbe essere @code{NULL}. Per coprocessi bidirezionali, nessuno dei due
+valori dovrebbe essere @code{NULL}.
+
+Normalmente, l'estensione @`e interessata a @code{(*ibufp)->fd}
+e/o @code{fileno((*obufp)->fp)}. Se il file non @`e gi@`a
+aperto, e l'argomento @code{fd} non @`e negativo, @command{gawk}
+user@`a quel descrittore di file invece di aprire il file nella
+maniera solita. Se l'@code{fd} non @`e negativo, ma il file esiste gi@`a,
+@command{gawk} ignora l'@code{fd} e restituisce il file esistente. @`E
+responsabilit@`a del chiamante notare che n@'e l'@code{fd} nella struttura
+restituita @code{awk_input_buf_t}, n@'e l'@code{fd} nella struttura restituita
+@code{awk_output_buf_t} contiene il valore richiesto.
+
+Si noti che fornire un descrittore di file @emph{non} @`e al momento supportato
+per le @dfn{pipe}. Tuttavia, l'utilizzo di un descrittore di file
+dovrebbe essere possibile per @dfn{socket} in input, output,
+aggiunta-a-fine-file (append), e bidirezionale (coprocessi).
+Se @code{filetype} @`e bidirezionale, @command{gawk} presuppone che sia un
+@dfn{socket}! Si noti che nel caso
+bidirezionale i descrittori di file in input e output possono essere
+differenti.
+Per essere sicuri che tutto sia andato bene, si deve controllare che uno dei due
+corrisponda alla richiesta.
+@end table
+
+Si prevede che questa funzione API verr@`a usata per parallelizzare l'I/O
+e rendere disponibile una libreria per i @dfn{socket}.
+
+@node Variabili dell'estensione API
+@subsection Variabili fornite dall'API
+
+L'API fornisce due insiemi di variabili. Il primo insieme contiene
+informazioni sulla versione dell'API (sia la versione dell'estensione
+compilata, che quella di @command{gawk}). Il secondo
+insieme contiene informazioni su come @command{gawk} @`e stato invocato.
+
+@menu
+* Versione dell'estensione:: Informazioni sulla versione API.
+* Variabili informative di estens. API:: Variabili che forniscono informationi
+ sull'invocazione di @command{gawk}.
+@end menu
+
+@node Versione dell'estensione
+@subsubsection Costanti e variabili della versione dell'API
+@cindex API, versione
+@cindex versione dell'estensione API @command{gawk}
+@cindex estensione @command{gawk}, versione API
+
+L'API fornisce sia un numero di versione ``principale'' che uno ``secondario''.
+Le versioni dell'API sono disponibili al momento della compilazione, come
+definizioni per il preprocessore C, a supporto della compilazione
+condizionale, e come elencazione di costanti per facilitare il debug:
+
+@float Tabella,gawk-api-version
+@caption{Costanti delle versioni API gawk}
+@multitable {@b{API Version}} {@code{gawk_api_major_version}} {@code{GAWK_API_MAJOR_VERSION}}
+@headitem versione API @tab Definiz. Preprocessore C @tab Costante di elenco
+@item Major @tab @code{gawk_api_major_version} @tab @code{GAWK_API_MAJOR_VERSION}
+@item Minor @tab @code{gawk_api_minor_version} @tab @code{GAWK_API_MINOR_VERSION}
+@end multitable
+@end float
+
+La versione secondaria aumenta quando nuove funzioni sono aggiunte all'API.
+Tali nuove funzioni sono sempre aggiunte alla fine della @code{struct} dell'API.
+
+La versione principale aumenta (e la versione secondaria torna a zero) se
+qualche tipo di dati cambia dimensione o si modifica l'ordine dei campi, o se
+qualcuna delle funzioni esistenti cambia il livello di versione.
+
+Pu@`o capitare che un'estensione sia stata compilata con una versione
+dell'API ma caricata da una versione di @command{gawk} che ne usa una
+differente. Per questo motivo, la versione principale e quella secondaria
+dell'API della versione in uso di @command{gawk} sono incluse nella
+@code{struct} dell'API come costanti intere in sola lettura:
+
+@table @code
+@item api->major_version
+La versione principale di @command{gawk} in esecuzione.
+
+@item api->minor_version
+La versione secondaria di @command{gawk} in esecuzione.
+@end table
+
+Dipende dall'estensione decidere se ci sono incompatibilit@`a con l'API.
+Tipicamente, basta un controllo di questo tipo:
+
+@example
+if (api->major_version != GAWK_API_MAJOR_VERSION
+ || api->minor_version < GAWK_API_MINOR_VERSION) @{
+ fprintf(stderr, "estensione_pippo: discordanza di versione \
+con gawk!\n");
+ fprintf(stderr, "\tLa mia versione (%d, %d), versione gawk \
+(%d, %d)\n",
+ GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION,
+ api->major_version, api->minor_version);
+ exit(1);
+@}
+@end example
+
+Questo codice @`e incluso nella macro generica @code{dl_load_func()}
+presente in @file{gawkapi.h} (trattata
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Codice predefinito di un'estensione API}).
+
+@node Variabili informative di estens. API
+@subsubsection Variabili informative
+@cindex API, variabili informative dell'estensione
+@cindex variabili informative dell'API
+@cindex estensione API, variabili informative
+
+L'API fornisce accesso a parecchie variabili che descrivono
+se le opzioni della riga di comando corrispondenti sono state specificate
+quando @command{gawk} @`e stato chiamato. Le variabili sono:
+
+@table @code
+@item do_debug
+Questa variabile @`e @dfn{true} se @command{gawk} @`e stato invocato con l'opzione @option{--debug}.
+
+@item do_lint
+Questa variabile @`e @dfn{true} se @command{gawk} @`e stato invocato con l'opzione @option{--lint}.
+
+@item do_mpfr
+Questa variabile @`e @dfn{true} se @command{gawk} @`e stato invocato con l'opzione @option{--bignum}.
+
+@item do_profile
+Questa variabile @`e @dfn{true} se @command{gawk} @`e stato invocato con l'opzione @option{--profile}.
+
+@item do_sandbox
+Questa variabile @`e @dfn{true} se @command{gawk} @`e stato invocato con l'opzione @option{--sandbox}.
+
+@item do_traditional
+Questa variabile @`e @dfn{true} se @command{gawk} @`e stato invocato con l'opzione @option{--traditional}.
+@end table
+
+Il valore di @code{do_lint} pu@`o cambiare se il codice @command{awk}
+modifica la variabile predefinita @code{LINT} (@pxref{Variabili predefinite}).
+Gli altri valori non dovrebbero cambiare durante l'esecuzione.
+
+@node Codice predefinito di un'estensione API
+@subsection Codice predefinito di interfaccia API
+
+Come gi@`a detto (@pxref{Panoramica sul meccanismo delle estensioni}),
+le definizioni di funzioni qui presentate sono in realt@`a delle macro.
+Per usare queste macro, l'estensione deve fornire una piccola quantit@`a di
+codice predefinito (variabili e
+funzioni) nella parte iniziale del file sorgente, usando dei nomi
+standard, come descritto qui sotto. Il codice predefinito in questione @`e
+anche descritto nel file di intestazione @file{gawkapi.h}:
+
+@example
+/* Codice predefinito: */
+int plugin_is_GPL_compatible;
+
+static gawk_api_t *const api;
+static awk_ext_id_t ext_id;
+static const char *ext_version = NULL; /* o @dots{} = "qualche stringa" */
+
+static awk_ext_func_t func_table[] = @{
+ @{ "name", do_name, 1, 0, awk_false, NULL @},
+ /* @dots{} */
+@};
+
+/* O: */
+
+static awk_bool_t (*init_func)(void) = NULL;
+
+/* OPPURE: */
+
+static awk_bool_t
+init_mia_estensione(void)
+@{
+ @dots{}
+@}
+
+static awk_bool_t (*init_func)(void) = init_mia_estensione;
+
+dl_load_func(func_table, qualche_nome, "name_space_in_quotes")
+@end example
+
+Queste variabili e funzioni sono:
+
+@table @code
+@item int plugin_is_GPL_compatible;
+Qui si dichiara che l'estensione @`e compatibile con
+@ifclear FOR_PRINT
+la licenza GNU GPL (@pxref{Copia}).
+
+@end ifclear
+@ifset FOR_PRINT
+la licenza GNU GPL.
+@end ifset
+Se l'estensione non ha questa variabile, non verr@`a caricata da @command{gawk}
+(@pxref{Licenza delle estensioni}).
+
+@item static gawk_api_t *const api;
+Questa variabile globale @code{static} dovrebbe essere impostata per
+puntare al puntatore
+@code{gawk_api_t} che @command{gawk} passa alla funzione (dell'estensione)
+@code{dl_load()}. Questa variabile @`e usata da tutte le macro.
+
+@item static awk_ext_id_t ext_id;
+Questa variabile globale @code{static} dovrebbe essere impostata al valore
+@code{awk_ext_id_t} che @command{gawk} passa alla funzione @code{dl_load()}.
+Questa variabile @`e usata da tutte le macro.
+
+@item static const char *ext_version = NULL; /* o @dots{} = "qualche stringa" */
+Questa variabile globale @code{static} dovrebbe essere impostata
+a @code{NULL} oppure puntare a una stringa che contiene il nome e la
+versione dell'estensione.
+
+@item static awk_ext_func_t func_table[] = @{ @dots{} @};
+Questo @`e un vettore di una o pi@`u strutture @code{awk_ext_func_t},
+come descritto in precedenza (@pxref{Funzioni di estensione}).
+Pu@`o essere usato in seguito per pi@`u chiamate a
+@code{add_ext_func()}.
+
+@c Use @var{OR} for docbook
+@item static awk_bool_t (*init_func)(void) = NULL;
+@itemx @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @var{OR}
+@itemx static awk_bool_t init_mia_estensione(void) @{ @dots{} @}
+@itemx static awk_bool_t (*init_func)(void) = init_mia_estensione;
+Se qualche lavoro di inizializzazione @`e necessario, si dovrebbe definire una
+funzione all'uopo (crea variabili, apre file, etc.)
+e poi definire il puntatore @code{init_func} che punti alla funzione
+stessa.
+La funzione dovrebbe restituire @code{awk_@dfn{false}} se non va a buon fine
+o @code{awktrue} se tutto va bene.
+
+Se un'inizializzazione non @`e necessaria, si definisca il puntatore e
+lo si inizializzi a @code{NULL}.
+
+@item dl_load_func(func_table, qualche_nome, "nome_spazio_tra_doppi_apici")
+Questa macro genera una funzione @code{dl_load()} che far@`a
+tutte le inizializzazioni necessarie.
+@end table
+
+Lo scopo di tutte le variabili e dei vettori @`e di far s@`{@dotless{i}} che la
+funzione @code{dl_load()} (richiamata dalla macro @code{dl_load_func()})
+faccia tutto il lavoro standard necessario, qui descritto:
+
+@enumerate 1
+@item
+Controlla le versioni dell'API. Se la versione principale dell'estensione
+non corrisponde a quella di @command{gawk} o se la versione secondaria
+dell'estensione @`e maggiore di quella di @command{gawk}, stampa un messaggio
+di errore fatale ed esce.
+
+@item
+Carica le funzioni definite in @code{func_table}.
+Se qualche caricamento non riesce, stampa un messaggio di
+avvertimento ma continua l'esecuzione.
+
+@item
+Se il puntatore @code{init_func} non @`e @code{NULL}, chiama la
+funzione da esso puntata. Se questa restituisce @code{awk_false}, stampa un
+messaggio di avvertimento.
+
+@item
+Se @code{ext_version} non @`e @code{NULL}, registra la
+stringa di versione con @command{gawk}.
+@end enumerate
+
+@node Modifiche dalla versione API 1
+@subsection Modifiche dalla versione 1 dell'API
+
+La versione API corrente @emph{non} @`e compatibile a livello binario con la
+versione 1 dell'API.
+Le funzioni di estensione vanno ricompilate per poterle usare con la versione
+corrente di @command{gawk}.
+
+Fortunatamente, fatti salvi alcuni possibili avvertimenti a livello di
+compilazione, l'API rimane compatibile a livello di codice sorgente con la
+precedente versione API. Le differenze pi@`u rilevanti sono gli ulteriori
+campi nella struttura @code{awk_ext_func_t}, e l'aggiunta del terzo argomento
+nella funzione di implementazione in linguaggio C.
+
+@node Trovare le estensioni
+@section Come @command{gawk} trova le estensioni compilate
+@cindex estensioni, percorso di ricerca per
+@cindex estensioni, come trovarle
+@cindex trovare le estensioni
+@cindex percorso di ricerca per estensioni
+
+Le estensioni compilate vanno installate in una directory dove
+@command{gawk} possa trovarle. Se @command{gawk} @`e configurato e
+installato nella maniera di default, la directory dove trovare le
+estensioni @`e @file{/usr/local/lib/gawk}. Si pu@`o anche specificare un
+percorso di ricerca contenente una lista di directory da esaminare per la
+ricerca di estensioni compilate.
+@xref{AWKLIBPATH (Variabile)} per ulteriori dettagli.
+
+@node Esempio di estensione
+@section Esempio: alcune funzioni per i file
+@cindex estensione, esempio
+@cindex esempio di estensione
+
+@quotation
+@i{In qualunque posto vai, l@`a tu sei.}
+@author Buckaroo Banzai
+@end quotation
+
+@c It's enough to show chdir and stat, no need for fts
+
+Due utili funzioni che non sono in @command{awk} sono @code{chdir()} (per
+permettere a un programma @command{awk} di cambiare directory di lavoro) e
+@code{stat()}
+(per far s@`{@dotless{i}} che un programma @command{awk} possa raccogliere informazioni
+su un dato file).
+Per illustrare l'azione dell'API, questa @value{SECTION} fornisce
+queste funzioni a @command{gawk} in un'estensione.
+
+@menu
+* Descrizione interna file:: Quello che le nuove funzioni faranno
+* Operazioni interne file:: Codice per gestire file all'interno
+* Usare operazioni interne file:: Come usare un'estensione esterna
+@end menu
+
+@node Descrizione interna file
+@subsection Usare @code{chdir()} e @code{stat()}
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} mostra come usare le nuove funzioni a
+livello di @command{awk} una volta che siano state integrate nell'interprete
+del programma @command{gawk} in esecuzione. Usare @code{chdir()} @`e molto
+semplice. Richiede un solo argomento, la nuova directory su cui
+posizionarsi:
+
+@example
+@@load "filefuncs"
+@dots{}
+newdir = "/home/arnold/funstuff"
+ret = chdir(newdir)
+if (ret < 0) @{
+ printf("non riesco a passare a %s: %s\n", newdir, ERRNO) > "/dev/stderr"
+ exit 1
+@}
+@dots{}
+@end example
+
+Il valore restituito @`e negativo se la chiamata a @code{chdir()} non @`e riuscita,
+ed @code{ERRNO} (@pxref{Variabili predefinite}) @`e impostato a una stringa
+che descrive l'errore.
+
+Usare @code{stat()} @`e un po' pi@`u complicato. La funzione scritta in C
+@code{stat()} riempie una struttura che ha una certa quantit@`a di informazioni.
+La maniera corretta per immagazzinarle in @command{awk} @`e quella di riempire
+un vettore associativo con le informazioni appropriate:
+
+@c broke printf for page breaking
+@example
+file = "/home/arnold/.profile"
+ret = stat(file, fdata)
+if (ret < 0) @{
+ printf("non @`e stato possibile eseguire @command{stat} per %s: %s\n",
+ file, ERRNO) > "/dev/stderr"
+ exit 1
+@}
+printf("dimensione di %s @`e %d byte\n", file, fdata["size"])
+@end example
+
+La funzione @code{stat()} svuota sempre il vettore che contiene i dati,
+anche nel caso che la chiamata a @code{stat()} non riesca. I seguenti
+elementi vengono restituiti dalla funzione:
+
+@table @code
+@item "name"
+Il nome del file oggetto della chiamata a @code{stat()}.
+
+@item "dev"
+@itemx "ino"
+I numeri di @dfn{device} e di @dfn{inode}, rispettivamente.
+
+@item "mode"
+Il modo del file, in formato numerico. Questo include sia il tipo di file che
+i suoi permessi di accesso.
+
+@item "nlink"
+Il numero di collegamenti fisici del file (stesso file con diversi nomi).
+
+@item "uid"
+@itemx "gid"
+Gli identificativi di utente e di gruppo del possessore del file.
+
+@item "size"
+La dimensione in byte del file.
+
+@item "blocks"
+Il numero di blocchi su disco realmente occupati dal file. Questo pu@`o non
+essere
+proporzionale alla dimensione del file se il file ha delle lacune
+[ossia se solo alcune parti del file esistono veramente, il resto
+non @`e ancora stato riempito].
+
+@item "atime"
+@itemx "mtime"
+@itemx "ctime"
+La data e ora dell'ultimo accesso, modifica, e aggiornamento dell'@dfn{inode},
+rispettivamente. Questi sono delle marcature temporali numeriche
+(misurate in secondi dal
+01 gennaio 1970), che possono essere formattate dalla funzione
+@code{strftime()}
+(@pxref{Funzioni di tempo}).
+
+@item "pmode"
+La modalit@`a stampabile (``printable mode'') del file.
+Questo @`e una stringa che rappresenta
+il tipo del file e i permessi di accesso, come sono visualizzati da
+@samp{ls -l}---per esempio, @code{"drwxr-xr-x"}.
+
+@item "type"
+Una stringa stampabile che descrive il tipo di file. Il valore @`e uno dei
+seguenti:
+
+@table @code
+@item "blockdev"
+@itemx "chardev"
+Il file @`e un dispositico a blocchi o a caratteri (``file speciale'').
+
+@ignore
+@item "door"
+The file is a Solaris ``door'' (special file used for
+interprocess communications).
+@end ignore
+
+@item "directory"
+Il file @`e una directory.
+
+@item "fifo"
+Il file @`e una @dfn{pipe} denominata (nota anche come FIFO [First In First
+Out]).
+
+@item "file"
+Il file @`e un file normale.
+
+@item "@dfn{socket}"
+Il file @`e un @dfn{socket} @code{AF_UNIX} (``Unix domain'') nel
+filesystem.
+
+@item "symlink"
+Il file @`e un collegamento simbolico.
+@end table
+
+@c 5/2013: Thanks to Corinna Vinschen for this information.
+@item "devbsize"
+La dimensione di un blocco per l'elemento indicizzato da @code{"blocks"}.
+Questa informazione @`e derivata dalla costante @code{DEV_BSIZE}
+definita in @code{<sys/param.h>} nella maggior parte dei sistemi,
+o dalla costante @code{S_BLKSIZE} in @code{<sys/stat.h>} nei sistemi BSD.
+Per alcuni altri sistemi il valore si basa su una conoscenza @dfn{a priori}
+delle caratteristiche di un particolare sistema.
+Se non si riesce a determinare il valore, viene
+restituito quello di default, che @`e 512.
+@end table
+
+Possono essere presenti diversi altri elementi, a seconda del
+sistema operativo e del tipo di file.
+Si pu@`o controllarne la presenza dal programma @command{awk} per mezzo
+dell'operatore @code{in}
+(@pxref{Visitare elementi}):
+
+@table @code
+@item "blksize"
+La dimensione preferita di un blocco per effettuare operazioni di I/O sul file.
+Questo campo non @`e presente nella struttura C @code{stat} di tutti i sistemi
+che rispettano lo standard POSIX.
+
+@item "linkval"
+Se il file @`e un collegamento simbolico, questo elemento @`e il nome del
+file puntato dal collegamento simbolico (cio@`e, il valore del collegamento).
+
+@item "rdev"
+@itemx "major"
+@itemx "minor"
+Se il file @`e un dispositivo a blocchi o a caratteri, questi valori
+rappresentano il numero del dispositivo e, rispettivamente, le componenti
+principale e secondaria di quel numero.
+@end table
+
+@node Operazioni interne file
+@subsection Codice C per eseguire @code{chdir()} e @code{stat()}
+
+Questo @`e il codice C per queste estensioni.@footnote{La versione qui
+presentata @`e
+lievemente modificata per amor di semplicit@`a. Si veda @file{extension/filefuncs.c}
+nella distribuzione @command{gawk} per la versione completa.}
+
+Il file include alcuni file di intestazione standard, e poi il file di
+intestazione @file{gawkapi.h}, che fornisce le definizioni dell'API.
+A queste seguono le dichiarazioni di variabili, necessarie
+per usare le macro dell'API e il codice predefinito
+(@pxref{Codice predefinito di un'estensione API}):
+
+@example
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "gawkapi.h"
+
+#include "gettext.h"
+#define _(msgid) gettext(msgid)
+#define N_(msgid) msgid
+
+#include "gawkfts.h"
+#include "stack.h"
+
+static const gawk_api_t *api; /* per consentire il funzionamento
+ delle macro di utilit@`a */
+static awk_ext_id_t *ext_id;
+static awk_bool_t init_filefuncs(void);
+static awk_bool_t (*init_func)(void) = init_filefuncs;
+static const char *ext_version = "filefuncs extension: version 1.0";
+
+int plugin_is_GPL_compatible;
+@end example
+
+@cindex programmazione, convenzioni di, estensioni @command{gawk}
+@cindex estensioni @command{gawk}, convenzioni di programmazione
+Per convenzione, per una funzione @command{awk} di nome @code{pippo()},
+la funzione C che la implementa @`e chiamata @code{do_pippo()}. La funzione
+dovrebbe avere due argomenti. Il primo @`e un numero @code{int}, chiamato
+@code{nargs}, che rappresenta il numero di argomenti passato alla funzione.
+Il secondo @`e un puntatore a una struttura @code{awk_value_t}, normalmente
+chiamata @code{risultato}:
+
+@example
+/* do_chdir --- fornisce funzione chdir()
+ caricata dinamicamente per gawk */
+
+static awk_value_t *
+do_chdir(int nargs, awk_value_t *risultato, struct awk_ext_func *non_usata)
+@{
+ awk_value_t newdir;
+ int ret = -1;
+
+ assert(risultato != NULL);
+@end example
+
+La variabile @code{newdir}
+rappresenta la nuova directory nella quale cambiare, che @`e ottenuta
+tramite la funzione @code{get_argument()}. Si noti che il primo argomento @`e
+quello numero zero.
+
+Se l'argomento @`e stato trovato con successo, la funzione invoca la chiamata di
+sistema @code{chdir()}. In caso contrario, se la @code{chdir()} non riesce,
+viene aggiornata la variabile @code{ERRNO}:
+
+@example
+ if (get_argument(0, AWK_STRING, & newdir)) @{
+ ret = chdir(newdir.str_value.str);
+ if (ret < 0)
+ update_ERRNO_int(errno);
+ @}
+@end example
+
+Infine, la funzione restituisce il codice di ritorno da @code{chdir} a
+livello di @command{awk}:
+
+@example
+ return make_number(ret, risultato);
+@}
+@end example
+
+L'estensione @code{stat()} @`e pi@`u impegnativa. Dapprima abbiamo
+una funzione che trasforma la stringa di autorizzazione numerica
+(@dfn{mode}) in una rappresentazione stampabile
+(p.es., il codice ottale @code{0644} diviene @samp{-rw-r--r--}). Questa
+parte @`e qui omessa per brevit@`a.
+
+@example
+/* format_mode --- trasforma il campo @dfn{mode} di @dfn{stat}
+ in qualcosa di leggibile */
+
+static char *
+format_mode(unsigned long fmode)
+@{
+ @dots{}
+@}
+@end example
+
+Viene poi una funzione per leggere dei collegamenti simbolici, anche questa
+omessa per brevit@`a:
+
+@example
+/* read_symlink --- legge un collegamento simbolico in un buffer
+ allocato.
+ @dots{} */
+
+static char *
+read_symlink(const char *fname, size_t bufsize, ssize_t *linksize)
+@{
+ @dots{}
+@}
+@end example
+
+Due funzioni ausiliarie semplificano l'immissione di valori nel
+vettore che conterr@`a il risultato della chiamata a @code{stat()}:
+
+@example
+/* array_set --- imposta un elemento di un vettore */
+
+static void
+array_set(awk_array_t vettore, const char *sub, awk_value_t *valore)
+@{
+ awk_value_t index;
+
+ set_array_element(vettore,
+ make_const_string(sub, strlen(sub), & index),
+ valore);
+
+@}
+
+/* array_set_numeric --- imposta un elemento di un vettore con un
+ numero */
+
+static void
+array_set_numeric(awk_array_t vettore, const char *sub, double num)
+@{
+ awk_value_t tmp;
+
+ array_set(vettore, sub, make_number(num, & tmp));
+@}
+@end example
+
+La seguente funzione fa il grosso del lavoro per riempire il vettore dei
+risultati @code{awk_array_t} con valori ottenuti
+da una @code{struct stat} valida. Questo lavoro @`e fatto in una funzione
+separata per supportare sia la funzione
+@code{stat()} per @command{gawk}, che l'estensione @code{fts()},
+che @`e inclusa nello stesso file, ma non
+ @`e mostrata qui
+(@pxref{Esempio di estensione funzioni file}).
+
+La prima parte della funzione @`e la dichiarazione delle variabili,
+compresa una tabella per tradurre i tipi di file in stringhe:
+
+@example
+/* fill_stat_array --- fa il lavoro di riempire un
+ vettore con informazioni da stat */
+
+static int
+fill_stat_array(const char *name, awk_array_t vettore, struct stat *sbuf)
+@{
+ char *pmode; /* @dfn{mode} stampabile */
+ const char *type = "unknown";
+ awk_value_t tmp;
+ static struct ftype_map @{
+ unsigned int mask;
+ const char *type;
+ @} ftype_map[] = @{
+ @{ S_IFREG, "file" @},
+ @{ S_IFBLK, "blockdev" @},
+ @{ S_IFCHR, "chardev" @},
+ @{ S_IFDIR, "directory" @},
+#ifdef S_IFSOCK
+ @{ S_IFSOCK, "socket" @},
+#endif
+#ifdef S_IFIFO
+ @{ S_IFIFO, "fifo" @},
+#endif
+#ifdef S_IFLNK
+ @{ S_IFLNK, "symlink" @},
+#endif
+#ifdef S_IFDOOR /* Stranezza Solaris */
+ @{ S_IFDOOR, "door" @},
+#endif /* S_IFDOOR */
+ @};
+ int j, k;
+@end example
+
+Il vettore di destinazione @`e svuotato di elementi, e poi il codice riempie
+i vari elementi prendendoli dai valori presenti in @code{struct stat}:
+@example
+ /* svuota il vettore */
+ clear_array(vettore);
+
+ /* riempie il vettore */
+ array_set(vettore, "name", make_const_string(name, strlen(name),
+ & tmp));
+ array_set_numeric(vettore, "dev", sbuf->st_dev);
+ array_set_numeric(vettore, "ino", sbuf->st_ino);
+ array_set_numeric(vettore, "mode", sbuf->st_mode);
+ array_set_numeric(vettore, "nlink", sbuf->st_nlink);
+ array_set_numeric(vettore, "uid", sbuf->st_uid);
+ array_set_numeric(vettore, "gid", sbuf->st_gid);
+ array_set_numeric(vettore, "size", sbuf->st_size);
+ array_set_numeric(vettore, "blocks", sbuf->st_blocks);
+ array_set_numeric(vettore, "atime", sbuf->st_atime);
+ array_set_numeric(vettore, "mtime", sbuf->st_mtime);
+ array_set_numeric(vettore, "ctime", sbuf->st_ctime);
+
+ /* per dispositivi a blocchi o carattere, aggiunge rdev,
+ e il numero principale e secondario */
+ if (S_ISBLK(sbuf->st_mode) || S_ISCHR(sbuf->st_mode)) @{
+ array_set_numeric(vettore, "rdev", sbuf->st_rdev);
+ array_set_numeric(vettore, "major", major(sbuf->st_rdev));
+ array_set_numeric(vettore, "minor", minor(sbuf->st_rdev));
+ @}
+@end example
+
+@noindent
+L'ultima parte della funzione fa alcune aggiunte selettive
+al vettore di destinazione, a seconda che siano disponibili o no
+certi campi e/o il tipo del file. Viene poi restituito zero, per indicare che
+tutto @`e andato bene:
+
+@example
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ array_set_numeric(vettore, "blksize", sbuf->st_blksize);
+#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
+
+ pmode = format_mode(sbuf->st_mode);
+ array_set(vettore, "pmode", make_const_string(pmode, strlen(pmode),
+ & tmp));
+
+ /* per collegamenti simbolici, si aggiunge un campo linkval */
+ if (S_ISLNK(sbuf->st_mode)) @{
+ char *buf;
+ ssize_t linksize;
+
+ if ((buf = read_symlink(name, sbuf->st_size,
+ & linksize)) != NULL)
+ array_set(vettore, "linkval",
+ make_malloced_string(buf, linksize, & tmp));
+ else
+ warning(ext_id, _("stat: non riesco a leggere il \
+collegamento simbolico `%s'"),
+ name);
+ @}
+
+ /* aggiunge il tipo di campo */
+ type = "unknown"; /* non dovrebbe succedere */
+ for (j = 0, k = sizeof(ftype_map)/sizeof(ftype_map[0]); j < k; j++) @{
+ if ((sbuf->st_mode & S_IFMT) == ftype_map[j].mask) @{
+ type = ftype_map[j].type;
+ break;
+ @}
+ @}
+
+ array_set(vettore, "type", make_const_string(type, strlen(type), & tmp));
+
+ return 0;
+@}
+@end example
+
+Del terzo argomento passato a @code{stat()} non si era ancora parlato.
+Questo argomento @`e facoltativo. Se presente, dice a @code{do_stat()} di
+usare la chiamata di sistema @code{stat()} invece della chiamata di sistema
+@code{lstat()}. Questo avviene attraverso un puntatore a funzione:
+@code{statfunc}.
+@code{statfunc} @`e inizializzato per puntare a @code{lstat()} (invece che a
+@code{stat()}) per ottenere le informazioni relative al file, nel caso che
+il file in questione sia un
+collegamento simbolico. Tuttavia, se il terzo argomento @`e specificato,
+@code{statfunc} viene modificato in modo da puntare a @code{stat()}.
+
+Ecco la funzione @code{do_stat()}, che inizia con la dichiarazione delle
+variabili e un controllo degli argomenti passati dal chiamante:
+
+@example
+/* do_stat --- fornisce una funzione stat() per gawk */
+
+static awk_value_t *
+do_stat(int nargs, awk_value_t *risultato, struct awk_ext_func *non_usata)
+@{
+ awk_value_t file_param, array_param;
+ char *name;
+ awk_array_t vettore;
+ int ret;
+ struct stat sbuf;
+ /* per default si usa lstat() */
+ int (*statfunc)(const char *path, struct stat *sbuf) = lstat;
+
+ assert(risultato != NULL);
+@end example
+
+A questo punto inizia l'elaborazione vera e propria. Per prima cosa, la
+funzione esamina gli argomenti.
+Poi, ottiene le informazioni relative al file. Se la funzione chiamata
+(@code{lstat()} o @code{stat()}) restituisce un errore, il codice imposta
+@code{ERRNO} e torna al chiamante:
+
+@example
+ /* file @`e il primo argomento,
+ il vettore per contenere i risultati @`e il secondo */
+ if ( ! get_argument(0, AWK_STRING, & file_param)
+ || ! get_argument(1, AWK_ARRAY, & array_param)) @{
+ warning(ext_id, _("stat: parametri errati"));
+ return make_number(-1, risultato);
+ @}
+
+ if (nargs == 3) @{
+ statfunc = stat;
+ @}
+
+ name = file_param.str_value.str;
+ vettore = array_param.array_cookie;
+
+ /* svuota sempre il vettore all'inizio */
+ clear_array(vettore);
+
+ /* chiama stat per il file;
+ in caso di errore,
+ imposta ERRNO e ritorna */
+ ret = statfunc(name, & sbuf);
+ if (ret < 0) @{
+ update_ERRNO_int(errno);
+ return make_number(ret, risultato);
+ @}
+@end example
+
+Il lavoro noioso @`e svolto da @code{fill_stat_array()}, visto in
+precedenza. Alla fine, la funzione restituisce il codice di ritorno
+impostato da @code{fill_stat_array()}:
+
+@example
+ ret = fill_stat_array(name, vettore, & sbuf);
+
+ return make_number(ret, risultato);
+@}
+@end example
+
+Infine, @`e necessario fornire la ``colla'' che aggrega
+le nuove funzioni a @command{gawk}.
+
+L'estensione @code{filefuncs} comprende anche una funzione
+@code{fts()}, qui omessa
+(@pxref{Esempio di estensione funzioni file}).
+@`E anche prevista una funzione di
+inizializzazione:
+
+@example
+/* init_filefuncs --- routine di initializazione */
+
+static awk_bool_t
+init_filefuncs(void)
+@{
+ @dots{}
+@}
+@end example
+
+Siamo quasi alla fine. Serve un vettore di strutture @code{awk_ext_func_t}
+per caricare ogni funzione in @command{gawk}:
+
+@example
+static awk_ext_func_t func_table[] = @{
+ @{ "chdir", do_chdir, 1, 1, awk_false, NULL @},
+ @{ "stat", do_stat, 3, 2, awk_false, NULL @},
+ @dots{}
+@};
+@end example
+
+Ogni estensione deve avere una routine di nome @code{dl_load()} per caricare
+tutto ci@`o che occorre caricare. La cosa pi@`u semplice @`e di usare la macro
+@code{dl_load_func()} in @code{gawkapi.h}:
+
+@example
+/* definizione della funzione dl_load()
+ usando la macro standard */
+
+dl_load_func(func_table, filefuncs, "")
+@end example
+
+Abbiamo finito!
+
+@node Usare operazioni interne file
+@subsection Integrare le estensioni
+
+@cindex @command{gawk}, aggiungere funzionalit@`a a
+@cindex funzionalit@`a, aggiungere a @command{gawk}
+@cindex aggiungere funzionalit@`a a @command{gawk}
+Dopo aver scritto il codice, dev'essere possibile aggiungerlo in fase
+di esecuzione all'interprete @command{gawk}. Per prima cosa, il codice
+va compilato. Supponendo che le funzioni siano in
+un file di nome @file{filefuncs.c}, e che @var{idir} sia la posizione
+del file di intestazione @file{gawkapi.h},
+i seguenti passi@footnote{In pratica, si potrebbe decidere di usare
+i comandi GNU Autotools (Automake, Autoconf, Libtool, e @command{gettext})
+per configurare e costruire le librerie necessarie. L'esposizione di come
+ci@`o pu@`o essere fatto esula dal tema di questo @value{DOCUMENT}.
+@xref{gawkextlib} per i puntatori a siti Internet che permettono di accedere
+a questi strumenti.} creano una libreria condivisa GNU/Linux:
+
+@example
+$ @kbd{gcc -fPIC -shared -DHAVE_CONFIG_H -c -O -g -I@var{idir} filefuncs.c}
+$ @kbd{gcc -o filefuncs.so -shared filefuncs.o}
+@end example
+
+Una volta creata la libreria, questa viene caricata usando la parola
+chiave @code{@@load}:
+
+@example
+# file testff.awk
+@@load "filefuncs"
+
+BEGIN @{
+ "pwd" | getline curdir # salva la directory corrente
+ close("pwd")
+
+ chdir("/tmp")
+ system("pwd") # verifica l'avvenuto cambio di directory
+ chdir(curdir) # torna indietro
+
+ print "Info per testff.awk"
+ ret = stat("testff.awk", data)
+ print "ret =", ret
+ for (i in data)
+ printf "data[\"%s\"] = %s\n", i, data[i]
+ print "testff.awk modified:",
+ strftime("%m %d %Y %H:%M:%S", data["mtime"])
+
+ print "\nInfo per JUNK"
+ ret = stat("JUNK", data)
+ print "ret =", ret
+ for (i in data)
+ printf "data[\"%s\"] = %s\n", i, data[i]
+ print "JUNK modified:", strftime("%m %d %Y %H:%M:%S", data["mtime"])
+@}
+@end example
+
+La variabile d'ambiente @env{AWKLIBPATH} dice a
+@command{gawk} dove @`e possibile trovare le estensioni (@pxref{Trovare le estensioni}).
+La variabile viene impostata alla directory corrente, e quindi viene eseguito
+il programma:
+
+@example
+$ @kbd{AWKLIBPATH=$PWD gawk -f testff.awk}
+@print{} /tmp
+@print{} Info per testff.awk
+@print{} ret = 0
+@print{} data["blksize"] = 4096
+@print{} data["devbsize"] = 512
+@print{} data["mtime"] = 1412004710
+@print{} data["mode"] = 33204
+@print{} data["type"] = file
+@print{} data["dev"] = 2053
+@print{} data["gid"] = 1000
+@print{} data["ino"] = 10358899
+@print{} data["ctime"] = 1412004710
+@print{} data["blocks"] = 8
+@print{} data["nlink"] = 1
+@print{} data["name"] = testff.awk
+@print{} data["atime"] = 1412004716
+@print{} data["pmode"] = -rw-rw-r--
+@print{} data["size"] = 666
+@print{} data["uid"] = 1000
+@print{} testff.awk modified: 09 29 2014 18:31:50
+@print{}
+@print{} Info per JUNK
+@print{} ret = -1
+@print{} JUNK modified: 01 01 1970 02:00:00
+@end example
+
+@node Esempi di estensione
+@section Le estensioni di esempio incluse nella distribuzione @command{gawk}
+@cindex estensioni distribuite con @command{gawk}
+
+Questa @value{SECTION} fornisce una breve panoramica degli esempi di
+estensione inclusi nella distribuzione di @command{gawk}. Alcune di esse
+sono destinate per l'uso in produzione (p.es., le estensioni
+@code{filefuncs}, @code{readdir}, e
+@code{inplace}). Altre sono state scritte principalmente per mostrare come
+si usa l'estensione API.
+
+@menu
+* Esempio di estensione funzioni file:: L'esempio che usa funzioni file.
+* Esempio di estensione Fnmatch:: Un'interfaccia a @code{fnmatch()}.
+* Esempio di estensione Fork:: Un'interfaccia a @code{fork()} e
+ altre funzioni di processo.
+* Esempio di estensione Inplace:: Consentire modifica diretta dei file.
+* Esempio di estensione Ord:: Conversioni a valore e a stringa di
+ caratteri.
+* Esempio di estensione Readdir:: Un'interfaccia a @code{readdir()}.
+* Esempio di estensione Revout:: Semplice post-processore per
+ invertire la stringa in output.
+* Esempio di estensione Rev2way:: Processore bidirezionale per
+ invertire la stringa in output.
+* Esempio di estensione Rwarray:: Serializzare il vettore in un
+ file.
+* Esempio di estensione Readfile:: Leggere un intero file in una stringa.
+* Esempio di estensione Time:: Un'interfaccia a @code{gettimeofday()}
+ e @code{sleep()}.
+* Esempio di estensione API Test:: Test per la API.
+@end menu
+
+@node Esempio di estensione funzioni file
+@subsection Funzioni relative ai file
+
+L'estensione @code{filefuncs} include tre funzioni diverse, come descritto sotto.
+L'uso @`e il seguente:
+
+@table @asis
+@item @code{@@load "filefuncs"}
+Questo @`e il modo per caricare l'estensione.
+
+@cindex @code{chdir()}, estensione
+@cindex estensione @code{chdir()}
+@item @code{risultato = chdir("/qualche/directory")}
+La funzione @code{chdir()} invoca a sua volta la chiamata di sistema
+@code{chdir()} per cambiare la directory corrente. Restituisce zero
+se tutto va bene o un valore minore di zero in caso di errore.
+In quest'ultimo caso, viene aggiornata la variabile @code{ERRNO}.
+
+@cindex @code{stat()}, estensione
+@cindex estensione @code{stat()}
+@item @code{risultato = stat("/qualche/percorso", statdata} [@code{, follow}]@code{)}
+La funzione @code{stat()} invoca a sua volta la chiamata di sistema
+@code{stat()}.
+Restituisce zero se tutto va bene o un valore minore di zero in caso di
+errore.
+In quest'ultimo caso, viene aggiornata la variabile @code{ERRNO}.
+
+Per default, viene usata la chiamata di sistema @code{lstat()}.
+Tuttavia, se alla funzione viene passato un terzo argomento, questa invoca
+invece @code{stat()}.
+
+In tutti i casi, il vettore @code{statdata} viene preventivamente svuotato.
+Quando la chiamata a @code{stat()} riesce, viene riempito il vettore
+@code{statdata} con le informazioni ottenute dal fileystem, come segue:
+
+@multitable @columnfractions .15 .50 .20
+@headitem Indice @tab Campo in @code{struct stat} @tab Tipo file
+@item @code{"name"} @tab Il @value{FN} @tab Tutti
+@item @code{"dev"} @tab @code{st_dev} @tab Tutti
+@item @code{"ino"} @tab @code{st_ino} @tab Tutti
+@item @code{"mode"} @tab @code{st_mode} @tab Tutti
+@item @code{"nlink"} @tab @code{st_nlink} @tab Tutti
+@item @code{"uid"} @tab @code{st_uid} @tab Tutti
+@item @code{"gid"} @tab @code{st_gid} @tab Tutti
+@item @code{"size"} @tab @code{st_size} @tab Tutti
+@item @code{"atime"} @tab @code{st_atime} @tab Tutti
+@item @code{"mtime"} @tab @code{st_mtime} @tab Tutti
+@item @code{"ctime"} @tab @code{st_ctime} @tab Tutti
+@item @code{"rdev"} @tab @code{st_rdev} @tab Dispositivi
+@item @code{"major"} @tab @code{st_major} @tab Dispositivi
+@item @code{"minor"} @tab @code{st_minor} @tab Dispositivi
+@item @code{"blksize"} @tab @code{st_blksize} @tab Tutti
+@item @code{"pmode"} @tab Una versione leggibile del valore dell'autorizzazione,
+come quello stampato dal comando
+@command{ls} (per esempio, @code{"-rwxr-xr-x"}) @tab Tutti
+@item @code{"linkval"} @tab Il valore del collegamento simbolico @tab
+Collegamenti simbolici
+@item @code{"type"} @tab Il tipo del file in formato stringa---pu@`o essere
+@code{"file"},
+@code{"blockdev"},
+@code{"chardev"},
+@code{"directory"},
+@code{"socket"},
+@code{"fifo"},
+@code{"symlink"},
+@code{"door"}
+o
+@code{"unknown"}
+(non tutti i sistemi supportano tutti i tipi file) @tab Tutti
+@end multitable
+
+@cindex @code{fts()}, estensione
+@cindex estensione @code{fts()}
+@item @code{flags = or(FTS_PHYSICAL, ...)}
+@itemx @code{risultato = fts(pathlist, flags, filedata)}
+Percorre gli alberi di file elencati in @code{pathlist} e riempie il vettore
+@code{filedata}, come descritto qui di seguito. @code{flags} @`e l'operazione
+@dfn{OR} @dfn{bit} a @dfn{bit} di parecchi valori predefiniti, pure descritti
+pi@`u sotto.
+Restituisce zero in assenza di errori, in caso contrario restituisce @minus{}1.
+@end table
+
+La funzione @code{fts()} invoca a sua volta la routine di libreria C
+@code{fts()} per percorrere gerarchie di file. Invece di restituire i dati
+relativi ai file uno per volta in sequenza,
+riempie un vettore multidimensionale con i dati di ogni file e directory
+che risiedono nelle gerarchie richieste.
+
+Gli argomenti sono i seguenti:
+
+@table @code
+@item pathlist
+Un vettore di @value{FNS}. Sono usati i valori dei singoli elementi;
+gli indici che puntano a tali valori vengono ignorati.
+
+@item flags
+Questo dovrebbe essere l'@dfn{OR} @dfn{bit} a @dfn{bit} di uno o pi@`u dei
+seguenti valori dei flag costanti predefiniti.
+Almeno uno dei due flag @code{FTS_LOGICAL}
+o @code{FTS_PHYSICAL} dev'essere impostato; in caso contrario
+@code{fts()} restituisce una segnalazione di errore e imposta @code{ERRNO}.
+I flag sono:
+
+@c nested table
+@table @code
+@item FTS_LOGICAL
+Passa in rassegna i file in modo ``logico'', e quindi l'informazione restituita
+per un collegamento simbolico @`e quella relativa al file puntato, e non al
+collegamento simbolico stesso. Questo flag @`e mutuamente esclusivo con
+@code{FTS_PHYSICAL}.
+
+@item FTS_PHYSICAL
+Passa in rassegna i file in modo ``fisico'', e quindi l'informazione restituita
+per un collegamento simbolico @`e quella relativa al collegamento simbolico
+stesso. Questo flag @`e mutuamente esclusivo con @code{FTS_LOGICAL}.
+
+@item FTS_NOCHDIR
+Per migliorare le prestazioni, la routine di libreria C @code{fts()}
+cambia directory mentre percorre una gerarchia di file. Questo flag
+disabilita quell'ottimizzazione.
+
+@item FTS_COMFOLLOW
+Si accede al file puntato da un collegamento simbolico esistente in @code{pathlist},
+anche se @code{FTS_LOGICAL} non @`e stato impostato.
+
+@item FTS_SEEDOT
+Per default, la routine di libreria C @code{fts()} non restituisce
+informazioni per i file
+@file{"."} (punto) e @file{".."} (punto-punto). Quest'opzione richiede
+l'informazione anche per @file{".."}. (L'estensione ritorna sempre
+l'informazione per @file{"."}; maggiori dettagli pi@`u sotto.)
+
+@item FTS_XDEV
+Mentre si percorre un filesystem, non passare mai a un filesystem montato
+diverso da quello in cui si opera.
+@c Pu@`o succedere nel caso di collegamenti simbolici, che contengono un nome di file
+@c che si trova da tutt'altra parte
+@c lrwxrwxrwx 1 root root 6 ago 6 2015 /aca -> /d/aca
+@c /d/aca:
+@c /dev/sda6 115234344 15648380 93709280 15% /d
+@c / (e il collegamento simbolico /aca)
+@c /dev/sda1 37308224 13573368 21816644 39% /
+@end table
+
+@item filedata
+Il vettore @code{filedata} contiene i risultati.
+La funzione @code{fts()} lo svuota all'inizio. In seguito viene creato
+un elemento in @code{filedata} per ogni elemento in @code{pathlist}.
+L'indice @`e il nome della directory o del file specificato in @code{pathlist}.
+L'elemento puntato da questo indice @`e a sua volta un vettore. Ci sono due
+casi:
+
+@c nested table
+@table @emph
+@item Il percorso @`e un file
+In questo caso, il vettore contiene due o tre elementi:
+
+@c doubly nested table
+@table @code
+@item "path"
+Il percorso completo di questo file, a partire dalla directory radice (``root'')
+indicata nel vettore @code{pathlist}.
+
+@item "stat"
+Questo elemento @`e esso stesso un vettore, contenente le stesse informazioni
+fornite dalla funzione @code{stat()} vista in precedenza a proposito del suo
+argomento
+@code{statdata}. L'elemento pu@`o non essere presente se la chiamata
+di sistema @code{stat()} per il file non @`e riuscita.
+
+@item "error"
+Se qualche tipo di errore si verifica durante l'elaborazione, il vettore
+conterr@`a anche un elemento con chiave @code{"error"}, che @`e una stringa
+che descrive l'errore.
+@end table
+
+@item Il percorso @`e una directory
+In questo caso, nel vettore viene creato un elemento per ogni elemento
+contenuto nella directory. Se un elemento della directory @`e un
+file, l'azione del programma @`e la stessa descritta sopra per un file.
+Se invece la directory contiene delle sottodirectory, l'elemento creato
+nel vettore @`e (ricorsivamente) a sua volta un vettore che descrive la
+sottodirectory. Se fra i flag @`e stato
+specificato il flag @code{FTS_SEEDOT},
+ci sar@`a anche un elemento di nome
+@code{".."}. Questo elemento sar@`a un vettore contenente i dati restituiti
+da un'invocazione di @code{stat()}.
+
+Inoltre, ci sar@`a un elemento il cui indice @`e @code{"."}.
+Questo elemento @`e un vettore contenente gli stessi due o tre elementi che
+sono messi a disposizione per un file: @code{"path"}, @code{"stat"},
+ed @code{"error"}.
+@end table
+@end table
+
+La funzione @code{fts()} restituisce zero in assenza di errori.
+in caso contrario, restituisce @minus{}1.
+
+@quotation NOTA
+L'estensione @code{fts()} non imita esattamente l'interfaccia fornita dalla
+routine di libreria C @code{fts()}, ma sceglie di fornire un'interfaccia
+basata sui vettori associativi, che @`e pi@`u adeguata per l'uso da parte di un
+programma @command{awk}. Questo
+implica la mancanza di una funzione di
+confronto, poich@'e @command{gawk} gi@`a
+prevede la possibilit@`a di mettere facilmente nell'ordine desiderato gli
+elementi di un vettore.
+Anche se un'interfaccia modellata su @code{fts_read()} avrebbe potuto essere
+fornita, @`e sembrato pi@`u naturale mettere a disposizione un vettore
+multidimensionale, che rappresenta la gerarchia dei file e le informazioni
+relative a ognuno di essi.
+@end quotation
+
+Si veda il file @file{test/fts.awk} nella distribuzione di @command{gawk}
+per un esempio di uso dell'estensione @code{fts()}.
+
+@node Esempio di estensione Fnmatch
+@subsection Un'interfaccia a @code{fnmatch()}
+
+Quest'estensione fornisce un'interfaccia per utilizzare la funzione di
+libreria C @code{fnmatch()}. Si usa cos@`{@dotless{i}}:
+
+@table @code
+@item @@load "fnmatch"
+@`E questo il modo per caricare l'estensione.
+
+@cindex @code{fnmatch()}, estensione
+@cindex estensione @code{fnmatch()}
+@item risultato = fnmatch(pattern, stringa, flags)
+Il valore restituito @`e zero se tutto va bene, oppure @code{FNM_NOMATCH}
+se la funzione non ha trovato alcuna corrispondenza, o
+un valore differente, diverso da zero, se si @`e verificato un errore.
+@end table
+
+Oltre a rendere disponibile la funzione @code{fnmatch()}, l'estensione
+di @code{fnmatch} definisce una costante (@code{FNM_NOMATCH}), e un vettore
+con dei valori di flag, di nome @code{FNM}.
+
+Gli argomenti per @code{fnmatch()} sono:
+
+@table @code
+@item pattern
+L'espressione regolare con cui confrontare @value{FN}
+
+@item stringa
+La stringa @value{FN}
+
+@item flags
+Pu@`o valere zero o essere l'@dfn{OR} @dfn{bit} a @dfn{bit} di uno o pi@`u flag
+nel vettore @code{FNM}
+@end table
+
+I flag sono i seguenti:
+
+@multitable @columnfractions .40 .60
+@headitem Elemento del vettore @tab Flag corrispondente definito da @code{fnmatch()}
+@item @code{FNM["CASEFOLD"]} @tab @code{FNM_CASEFOLD}
+@item @code{FNM["FILE_NAME"]} @tab @code{FNM_FILE_NAME}
+@item @code{FNM["LEADING_DIR"]} @tab @code{FNM_LEADING_DIR}
+@item @code{FNM["NOESCAPE"]} @tab @code{FNM_NOESCAPE}
+@item @code{FNM["PATHNAME"]} @tab @code{FNM_PATHNAME}
+@item @code{FNM["PERIOD"]} @tab @code{FNM_PERIOD}
+@end multitable
+
+Ecco un esempio:
+
+@example
+@@load "fnmatch"
+@dots{}
+flags = or(FNM["PERIOD"], FNM["NOESCAPE"])
+if (fnmatch("*.a", "pippo.c", flags) == FNM_NOMATCH)
+ print "nessuna corrispondenza"
+@end example
+
+@node Esempio di estensione Fork
+@subsection Un'interfaccia a @code{fork()}, @code{wait()}, e @code{waitpid()}
+
+L'estensione @code{fork} mette a disposizione tre funzioni, come segue:
+
+@table @code
+@item @@load "fork"
+Questo @`e il modo per caricare l'estensione.
+
+@cindex @code{fork()}, estensione
+@cindex estensione @code{fork()}
+@item pid = fork()
+Questa funzione crea un nuovo processo. Il valore restituito @`e zero nel
+processo ``figlio'' e il numero che identifica il nuovo processo
+(@dfn{pid}) nel processo ``padre'', o @minus{}1
+in caso di errore. In quest'ultimo caso, @code{ERRNO} indica il problema.
+Nel processo figlio, gli elementi @code{PROCINFO["pid"]} e
+@code{PROCINFO["ppid"]} vengono aggiornati per riflettere i valori corretti.
+
+@cindex @code{waitpid()}, estensione
+@cindex estensione @code{waitpid()}
+@item ret = waitpid(pid)
+Questa funzione ha un unico argomento numerico, l'identificativo del processo
+di cui aspettare l'esito. Il valore di ritorno @`e quello restituito dalla
+chiamata di sistema @code{waitpid()}.
+
+@cindex @code{wait()}, estensione
+@cindex estensione @code{wait()}
+@item ret = wait()
+Questa funzione attende che il primo processo ``figlio'' termini.
+Il valore restituito @`e quello della chiamata di sistema @code{wait()}.
+@end table
+
+Non c'@`e una funzione corrispondente alla chiamata di sistema @code{exec()}.
+
+Ecco un esempio:
+
+@example
+@@load "fork"
+@dots{}
+if ((pid = fork()) == 0)
+ print "salve dal processo figlio"
+else
+ print "salve dal processo padre"
+@end example
+
+@node Esempio di estensione Inplace
+@subsection Consentire la modifica in loco dei file
+
+@cindex @code{inplace}, estensione
+@cindex estensione @code{inplace}
+L'estensione @code{inplace} svolge un lavoro simile a quello
+dell'opzione @option{-i} nel programma di utilit@`a GNU @command{sed},
+che svolge delle funzioni di modifica ``al volo'' su ogni file in input.
+Viene usato il file @file{inplace.awk}, caricato dinamicamente, per richiamare
+l'estensione in maniera corretta:
+
+@example
+@c file eg/lib/inplace.awk
+@group
+# inplace --- carica e richiama l'estensione inplace.
+
+@@load "inplace"
+
+# @`E buona cosa impostare INPLACE_SUFFIX in modo da fare
+# una copia di backup.
+# Per esempio, si potrebbe impostare INPLACE_SUFFIX a .bak
+# sulla riga di comando, o in una regola BEGIN.
+
+# Per default, ogni file specificato sulla riga di comando
+# verr@`a modificato sovrascrivendo il file originale.
+# Ma @`e possibile evitarlo specificando l'argomento inplace=0
+# davanti al nome del file che non si desidera elaborare in questo modo.
+# Si pu@`o poi abilitare di nuovo l'aggiornamento diretto del file
+# sulla riga di comando, specificando inplace=1 prima del file
+# che si vuole modificare direttamente.
+
+# N.B. La funzione inplace_end() @`e invocata nelle regole
+# BEGINFILE ed END, in modo che ogni eventuale azione
+# in una regola ENDFILE sar@`a ridiretta come previsto.
+
+BEGIN @{
+ inplace = 1 # abilitato per default
+@}
+
+BEGINFILE @{
+ if (_inplace_filename != "")
+ inplace_end(_inplace_filename, INPLACE_SUFFIX)
+ if (inplace)
+ inplace_begin(_inplace_filename = FILENAME, INPLACE_SUFFIX)
+ else
+ _inplace_filename = ""
+@}
+
+END @{
+ if (_inplace_filename != "")
+ inplace_end(_inplace_filename, INPLACE_SUFFIX)
+@}
+@end group
+@c endfile
+@end example
+
+Per ogni file elaborato, l'estensione ridirige lo
+standard output verso un file temporaneo definito in modo da avere lo stesso
+proprietario e le stesse autorizzazioni del file originale. Dopo che il file
+@`e stato elaborato, l'estensione riporta lo standard output alla sua
+destinazione originale.
+Se @code{INPLACE_SUFFIX} non @`e una stringa vuota, il file originale @`e
+collegato a un @value{FN} di backup, creato aggiungendo il
+suffisso al nome originale.
+Infine, il file temporaneo @`e rinominato in modo da essere lo stesso del
+@value{FN} originario.
+
+Si noti che l'uso di questa funzionalit@`a pu@`o essere controllato
+specificando @samp{inplace=0} sulla riga di comando, prima del nome del file
+che non dovrebbe essere elaborato come appena descritto. Si pu@`o richiedere
+ancora l'aggiornamento diretto di un file, specificando l'argomento
+@samp{inplace=1} davanti al nome del file da elaborare in maniera diretta.
+
+La variabile @code{_inplace_filename} serve per tener traccia del nome del
+file corrente, in modo da non eseguire la funzione @code{inplace_end()} prima
+di aver elaborato il primo file.
+
+Se si verifica un errore, l'estensione emette un messaggio di errore fatale
+per terminare l'elaborazione immediatamente, senza danneggiare il
+file originale.
+
+Ecco alcuni semplici esempi:
+
+@example
+$ @kbd{gawk -i inplace '@{ gsub(/pippo/, "pluto") @}; @{ print @}' file1 file2 file3}
+@end example
+
+Per mantenere una copia di backup del file originale, si provi a fare cos@`{@dotless{i}}:
+
+@example
+$ @kbd{gawk -i inplace -v INPLACE_SUFFIX=.bak '@{ gsub(/pippo/, "pluto") @}}
+> @kbd{@{ print @}' file1 file2 file3}
+@end example
+
+Si noti che, anche se l'estensione tenta di mantenere il proprietario e i
+permessi di accesso del file originario, non viene tentata la copia degli
+ulteriori permessi di accesso
+(@dfn{ACL - Access Control Lists}) del file originale.
+
+Se il programma termina prima del previsto, come potrebbe succedere se riceve
+dal sistema un segnale non gestito, pu@`o lasciare come residuo un file
+temporaneo.
+
+@node Esempio di estensione Ord
+@subsection Caratteri e valori numerici: @code{ord()} e @code{chr()}
+
+L'estensione @code{ordchr} aggiunge due funzioni, di nome
+@code{ord()} e @code{chr()}, come segue:
+
+@table @code
+@item @@load "ordchr"
+Questo @`e il modo per caricare l'estensione.
+
+@cindex @code{ord()}, estensione
+@cindex estensione @code{Ord}
+@item numero = ord(stringa)
+Restituisce il valore numerico del primo carattere in @code{stringa}.
+
+@cindex @code{Chr}, estensione
+@cindex estensione @code{Chr}
+@item char = chr(number)
+Restituisce una stringa il cui primo carattere @`e quello rappresentato
+da @code{number}.
+@end table
+
+Queste funzioni sono ispirate alle funzioni del linguaggio Pascal
+dallo stesso nome. Ecco un esempio:
+
+@example
+@@load "ordchr"
+@dots{}
+printf("Il valore numerico di 'A' @`e %d\n", ord("A"))
+printf("Il valore come stringa di 65 @`e %s\n", chr(65))
+@end example
+
+@node Esempio di estensione Readdir
+@subsection Leggere directory
+
+L'estensione @code{readdir} aggiunge un analizzatore di input
+per esaminare directory.
+L'uso @`e il seguente:
+
+@cindex @code{readdir}, estensione
+@cindex estensione @code{readdir}
+@example
+@@load "readdir"
+@end example
+
+Quando quest'estensione @`e in uso, invece che saltare le
+directory presenti sulla riga di comando, (o accedute tramite @code{getline}),
+queste sono lette, e ogni elemento della directory @`e restituito come
+un record.
+
+Il record consiste di tre campi. I primi due sono il numero di @dfn{inode} e
+il @value{FN}, separati fra loro da una barra.
+Nei sistemi in cui l'elemento di directory contiene il tipo del file,
+il record ha un terzo campo (pure separato da una barra), composto da una
+sola lettera, che indica il tipo del file. Le lettere e i tipi di file a cui
+corrispondono sono mostrate in @ref{table-readdir-file-types}.
+
+@float Tabella,table-readdir-file-types
+@caption{Tipi file restituiti dall'estensione @code{readdir}}
+@multitable @columnfractions .1 .9
+@headitem Lettera @tab Tipo di file
+@item @code{b} @tab Dispositivo a blocchi
+@item @code{c} @tab Dispositivo a caratteri
+@item @code{d} @tab Directory
+@item @code{f} @tab File normale
+@item @code{l} @tab Collegamento simbolico
+@item @code{p} @tab @dfn{pipe} con nome (FIFO)
+@item @code{s} @tab @dfn{socket}
+@item @code{u} @tab Tutto il resto (sconosciuto)
+@end multitable
+@end float
+
+Nei sistemi che non contengono l'informazione sul tipo del file, il terzo
+campo @`e sempre @samp{u}.
+
+@quotation NOTA
+Nei sistemi GNU/Linux, ci sono fileystem che non supportano il campo
+@code{d_type} (si veda la pagina di manuale @i{readdir}(3)), e in questo caso
+il tipo di file @`e sempre @samp{u}. Si pu@`o usare l'estensione
+@code{filefuncs} per chiamare @code{stat()} e ottenere l'informazione
+corretta sul tipo di file.
+@end quotation
+
+Ecco un esempio:
+
+@example
+@@load "readdir"
+@dots{}
+BEGIN @{ FS = "/" @}
+@{ print "@value{FN} @`e", $2 @}
+@end example
+
+@node Esempio di estensione Revout
+@subsection Invertire la stringa in output
+
+L'estensione @code{revoutput} aggiunge un semplice processore
+di output che inverte i caratteri di ogni riga in output. Serve a dimostrare
+come @`e possibile scrivere un processore di output, anche se pu@`o essere
+a prima vista vagamente divertente.
+Ecco un esempio:
+
+@cindex @code{revoutput}, estensione
+@cindex estensione @code{revoutput}
+@example
+@@load "revoutput"
+
+BEGIN @{
+ REVOUT = 1
+ print "non v'allarmate" > "/dev/stdout"
+@}
+@end example
+
+L'output di questo programma @`e @samp{etamralla'v non}.
+
+@node Esempio di estensione Rev2way
+@subsection Esempio di I/O bidirezionale
+
+L'estensione @code{revtwoway} aggiunge un semplice processore
+bidirezionale che inverte i caratteri di ogni riga che riceve, per farla
+poi rileggere dal programma @command{awk}. Il motivo per cui @`e stata scritta
+@`e quello di mostrare come si scrive un processore bidirezionale, anche se pu@`o
+sembrare un programma vagamente divertente.
+Il seguente esempio mostra come usarlo:
+
+@cindex @code{revtwoway}, estensione
+@cindex estensione @code{revtwoway}
+@example
+@@load "revtwoway"
+
+BEGIN @{
+ cmd = "/specchio/magico"
+ print "non v'allarmate" |& cmd
+ cmd |& getline risultato
+ print risultato
+ close(cmd)
+@}
+@end example
+
+L'output di questo programma
+@ifnotinfo
+anche in questo caso @`e:
+@end ifnotinfo
+@ifinfo
+@`e:
+@end ifinfo
+@samp{etamralla'v non}.
+
+@node Esempio di estensione Rwarray
+@subsection Scaricare e ricaricare un vettore
+
+L'estensione @code{rwarray} aggiunge due funzioni,
+di nome @code{writea()} e @code{reada()}, come segue:
+
+@table @code
+@item @@load "rwarray"
+Questo @`e il modo per caricare l'estensione.
+
+@cindex @code{writea()}, estensione
+@cindex estensione @code{writea()}
+@item ret = writea(file, vettore)
+Questa funzione ha come argomento una stringa, che @`e il nome del file
+sul quale scaricare il vettore, e il vettore stesso @`e il secondo argomento.
+@code{writea()} @`e in grado di gestire vettori di vettori. Restituisce il
+valore uno se completa il lavoro o zero se non va a buon fine.
+
+@cindex @code{reada()}, estensione
+@cindex estensione @code{reada()}
+@item ret = reada(file, vettore)
+@code{reada()} @`e la funzione inversa di @code{writea()};
+legge il file il cui nome @`e fornito come primo argomento, riempiendo il
+vettore il cui nome @`e il secondo argomento. Il vettore viene preventivamente
+svuotato.
+Anche in questo caso, il valore restituito @`e uno se tutto va bene o zero se
+la funzione non va a buon fine.
+@end table
+
+Il vettore creato da @code{reada()} @`e identico a quello scritto da
+@code{writea()} nel senso che i contenuti sono gli stessi. Tuttavia,
+per come @`e strutturata la funzione, l'ordine di attraversamento del vettore
+ricreato @`e quasi certamente differente da quello del vettore originale.
+Poich@'e l'ordine di attraversamento di un vettore @`e, per default, indefinito
+in @command{awk}, questo non @`e (tecnicamente) un problema. Se serve che
+l'attraversamento del vettore avvenga in un ordine preciso, si possono usare
+le funzionalit@`a di ordinamento di un vettore disponibili in @command{gawk}
+(@pxref{Ordinamento di vettori}).
+
+Il file contiene dati in formato binario. Tutti i valori interi sono scritti
+in @dfn{network byte order}@footnote{Cio@`e, nella maniera con cui sarebbero
+normalmente scritti in un testo, con le cifre pi@`u significative del
+numero contenute nella parte sinistra, e quelle meno significative
+nella parte destra della rappresentazione binaria del numero.}.
+Tuttavia, i valori in virgola mobile a doppia precisione sono scritti come
+dati binari nativi. Quindi, vettori che contengono solo dati in formato
+stringa possono essere scaricati da un sistema con un certo ordine di byte
+e ripristinati su un sistema con un ordine di byte differente, anche se
+un test al riguardo non @`e mai stato fatto.
+
+Ecco un esempio:
+
+@example
+@@load "rwarray"
+@dots{}
+ret = writea("scaricato.bin", vettore)
+@dots{}
+ret = reada("scaricato.bin", vettore)
+@end example
+
+@node Esempio di estensione Readfile
+@subsection Leggere un intero file in una stringa
+
+L'estensione @code{readfile} aggiunge una sola funzione
+di nome @code{readfile()}, e un analizzatore di input:
+
+@table @code
+@item @@load "readfile"
+Questo @`e il modo per caricare l'estensione.
+
+@cindex @code{readfile()}, estensione
+@cindex estensione @code{readfile()}
+@item risultato = readfile("/qualche/persorso")
+L'argomento @`e il nome del file da leggere. Il valore restituito @`e una
+stringa contenente l'intero contenuto del file richiesto. In caso di errore,
+la funzione restituisce la stringa vuota e imposta @code{ERRNO}.
+
+@item BEGIN @{ PROCINFO["readfile"] = 1 @}
+Inoltre, l'estensione aggiunge un analizzatore di input che @`e attivato se
+l'elemento @code{PROCINFO["readfile"]} esiste.
+Quando l'analizzatore @`e attivato, ogni file in input @`e restituito interamente
+come @code{$0}.
+La variabile @code{RT} @`e impostata alla stringa nulla.
+@end table
+
+Ecco un esempio:
+
+@example
+@@load "readfile"
+@dots{}
+contents = readfile("/percorso/del/file");
+if (contents == "" && ERRNO != "") @{
+ print("problema in lettura file", ERRNO) > "/dev/stderr"
+ ...
+@}
+@end example
+
+@node Esempio di estensione Time
+@subsection Funzioni dell'estensione time
+
+L'estensione @code{time} aggiunge due funzioni, di nome
+@code{gettimeofday()} e @code{sleep()}, come segue:
+
+@table @code
+@item @@load "time"
+Questo @`e il modo per caricare l'estensione.
+
+@cindex @code{gettimeofday()}, estensione
+@cindex estensione @code{gettimeofday()}
+@item ora_corrente = gettimeofday()
+Restituisce il numero di secondi trascorsi dalle ore 00:00 del giorno
+01/01/1970 UTC come valore a virgola mobile.
+Se questa informazione non @`e disponibile nella piattaforma in uso,
+restituisce @minus{}1 e imposta @code{ERRNO}. Il valore fornito dovrebbe
+avere la precisione di una frazione di
+secondo, ma la precisione effettiva pu@`o variare a seconda della
+piattaforma.
+Se la chiamata di sistema standard C @code{gettimeofday()} @`e disponibile
+nella piattaforma in uso, questo @`e il valore restituito. In caso contrario,
+se si sta lavorando con MS-Windows, la chiamata di sistema @`e fatta a
+@code{GetSystemTimeAsFileTime()}.
+
+@cindex @code{sleep()}, estensione
+@cindex estensione @code{sleep()}
+@item risultato = sleep(@var{secondi})
+Il programma @command{gawk} resta inattivo (dorme) per i @var{secondi}
+specificati. Se @var{secondi} ha un valore negativo,
+o la chiamata di sistema non riesce, restituisce @minus{}1 e imposta @code{ERRNO}.
+In caso contrario, restituisce zero dopo aver lasciato trascorrere
+la quantit@`a di tempo indicata.
+Si noti che @var{secondi} pu@`o essere un numero a virgola mobile (non solo un
+numero intero).
+Dettagli di implementazione: a seconda della disponibilit@`a nel sistema in uso,
+questa funzione tenta di usare @code{nanosleep()} o @code{select()} per
+ottenere il tempo di attesa richiesto.
+@end table
+
+@node Esempio di estensione API Test
+@subsection Test per la API
+@cindex @code{testext}, estensione
+@cindex estensione @code{testext}
+
+L'estensione @code{testext} controlla la funzionalit@`a di
+parti dell'API delle estensioni che non sono utilizzate negli altri esempi.
+Il file @file{extension/testext.c}
+contiene sia il codice C per l'estensione che il codice @command{awk}
+(tra i commenti del codice C) per eseguire i test. L'ambiente di test
+estrae il codice sorgente @command{awk} ed esegue i test. Si veda il file
+sorgente per maggiori informazioni.
+
+@node gawkextlib
+@section Il progetto @code{gawkextlib}
+@cindex @code{gawkextlib}, estensioni
+@cindex estensioni, @code{gawkextlib}
+@cindex estensioni, dove trovarle
+
+@cindex @code{gawkextlib}, progetto
+@cindex progetto @code{gawkextlib}
+Il progetto @uref{http://sourceforge.net/projects/gawkextlib/, @code{gawkextlib}}
+fornisce varie estensioni per @command{gawk}, compresa una per
+l'elaborazione dei file XML. Questa @`e un'evoluzione del progetto noto come
+@command{xgawk} (XML @command{gawk}).
+
+Al momento della stesura di questo testo, ci sono otto estensioni:
+
+@itemize @value{BULLET}
+@item
+Estensione @code{errno}
+
+@item
+Estensione GD graphics library
+
+@item
+Estensione libreria MPFR
+(fornisce l'accesso a varie funzioni MPFR non previste dal supporto nativo
+di MPFR disponibile in @command{gawk})
+
+@item
+Estensione PDF
+
+@item
+Estensione PostgreSQL
+
+@item
+Estensione Redis
+
+@item
+Estensione Select
+
+@item
+Estensione analizzatore XML, usando la libreria di analisi XML
+@uref{http://expat.sourceforge.net, Expat}
+@end itemize
+
+@cindex @command{git}, programma di utilit@`a
+@cindex programma di utilit@`a @command{git}
+Si pu@`o scaricare il codice del progetto @code{gawkextlib}
+usando il codice sorgente mantenuto tramite
+@uref{http://git-scm.com, Git}.
+Il comando per farlo @`e il seguente:
+
+@example
+git clone git://git.code.sf.net/p/gawkextlib/code gawkextlib-code
+@end example
+
+@cindex Expat, libreria per analizzare XML
+@cindex XML, Expat, libreria per analizzare
+Per poter compilare e usare l'estensione XML, @`e necessario installare
+la libreria di analisi XML @uref{http://expat.sourceforge.net, Expat}.
+
+Inoltre, @`e necessario installare gli strumenti GNU Autotools
+(@uref{http://www.gnu.org/software/autoconf, Autoconf},
+@uref{http://www.gnu.org/software/automake, Automake},
+@uref{http://www.gnu.org/software/libtool, Libtool}
+e
+@uref{http://www.gnu.org/software/gettext, GNU @command{gettext}}).
+
+La semplice procedura per compilare e testare @code{gawkextlib} @`e la seguente.
+Dapprima, occorre compilare e installare @command{gawk}:
+
+@example
+cd .../percorso/del/sorgente/gawk
+./configure --prefix=/tmp/newgawk @ii{Installa in /tmp/newgawk per ora}
+make && make check @ii{Compila e controlla che tutto sia a posto}
+make install @ii{Installa gawk}
+@end example
+
+Poi, dal sito @url{http://sourceforge.net/projects/gawkextlib/files} si deve
+scaricare @code{gawkextlib} e le estensioni che si vogliono installare.
+Il file @file{README} del sito spiega come compilare il codice. Se si @`e
+installato @command{gawk} in una posizione non-standard, occorre
+specificare @code{./configure --with-gawk=@var{/percorso/del/programma/gawk}}
+per far s@`{@dotless{i}} che venga trovato.
+Pu@`o essere necessario usare il programma di utilit@`a @command{sudo}
+per installare sia @command{gawk} che @code{gawkextlib}, a seconda di come
+funziona il sistema su cui si lavora.
+
+Chi scrive un'estensione e desidera condividerla con altri utenti
+@command{gawk}, pu@`o prendere in considerazione l'idea di farlo attraverso
+il progetto @code{gawkextlib}.
+Si veda il sito web del progetto per maggiori informazioni.
+
+@node Sommario delle estensioni
+@section Sommario
+
+@itemize @value{BULLET}
+@item
+Si possono scrivere estensioni (dette anche @dfn{plug-in})
+per @command{gawk}
+nel linguaggio C o C++ usando l'interfaccia di programmazione applicativa
+(API) definita dagli sviluppatori di
+@command{gawk}.
+
+@item
+Le estensioni devono avere una licenza compatibile con la
+GNU General Public License (GPL), e devono dichiararlo definendo un'apposita
+variabile di nome
+@code{plugin_is_GPL_compatibile}.
+
+@item
+La comunicazione tra @command{gawk} e un'estensione @`e bidirezionale.
+@command{gawk} passa all'estensione una struttura (@code{struct}) che contiene
+vari campi di dati e puntatori a funzione. L'estensione pu@`o poi chiamare
+funzioni all'interno di @command{gawk} tramite dei puntatori a funzioni
+per svolgere alcuni compiti.
+
+@item
+Uno di questi compiti @`e di ``registrare'' il nome e l'implementazione di
+nuove funzioni a livello di @command{awk} con @command{gawk}.
+L'implementazione ha la forma di un puntatore del linguaggio C,
+cui @`e associato un dato livello di versione.
+Per convenzione, le funzioni di implementazione hanno nome
+@code{do_@var{XXXX}()} per una funzione a livello di @command{awk} di nome
+@code{@var{XXXX}()}.
+
+@item
+L'API @`e definita in un file di intestazione di nome @file{gawkapi.h}.
+Occorre includere alcuni file di intestazione standard @emph{prima} di
+includere tale intestazione nel codice sorgente.
+
+@item
+Vengono forniti dei puntatori a funzioni dell'API per i seguenti tipi di
+operazioni:
+
+@itemize @value{BULLET}
+@item
+Allocare, riallocare, e liberare memoria
+
+@item
+Registrare funzioni (si possono registrare
+funzioni di estensione,
+funzioni ausiliarie di pulizia (@dfn{callbacks}),
+una stringa di versione,
+degli analizzatori di input,
+dei processori di output,
+e dei processori bidirezionali)
+
+@item
+Stampare messaggi fatali, non fatali, di avvertimento, e avvertimenti ``lint''
+
+@item
+Aggiornare @code{ERRNO} o annullarlo
+
+@item
+Accedere a parametri, come pure convertire un parametro di tipo non definito
+in un vettore
+
+@item
+Accedere alla tabella dei simboli (ricuperare il valore di una
+variabile globale, crearne una nuova o modificarne una esistente)
+
+@item
+Creare e rilasciare valori nascosti; questo consente di usare in modo
+efficiente lo stesso valore per pi@`u variabili e pu@`o migliorare di molto le
+prestazioni del programma
+
+@item
+Manipolare vettori
+(ricuperare, aggiungere, cancellare e modificare elementi;
+ottenere il numero di elementi in un vettore;
+creare un nuovo vettore;
+svuotare un vettore;
+e
+appiattire un vettore per poterlo percorrere facilmente con un ciclo in
+stile C, visitando tutti i suoi indici ed elementi)
+@end itemize
+
+@item
+L'API definisce diversi tipi di dati standard per rappresentare
+valori di variabili, elementi di vettore e vettori presenti in @command{awk}.
+
+@item
+L'API fornisce funzioni di servizio per definire dei valori.
+Sono anche disponibili funzioni di gestione della memoria, per assicurare
+la compatibilit@`a fra memoria allocata da @command{gawk} e memoria allocata da
+un'estensione.
+
+@item
+@emph{Tutta} la memoria passata da @command{gawk} a un'estensione dev'essere
+considerata come in sola lettura dall'estensione.
+
+@item
+@emph{Tutta} la memoria passata da un'estensione a @command{gawk} deve
+essere ottenuta dalle funzioni di allocazione della memoria previste
+dall'API. @command{gawk} @`e responsabile per la gestione di quella memoria e
+la libera quando @`e il momento per farlo.
+
+@item
+L'API fornisce informazioni sulla versione di @command{gawk} in
+esecuzione, in modo che un'estensione possa verificare la propria compatibilit@`a
+con la versione di @command{gawk} da cui @`e stata caricata.
+
+@item
+@`E pi@`u facile iniziare a programmare una nuova estensione usando il
+codice predefinito descritto in questo @value{CHAPTER}. Alcune macro nel
+file di intestazione @file{gawkapi.h} rendono la cosa pi@`u agevole.
+
+@item
+La distribuzione di @command{gawk} comprende un numero di piccoli ma utili
+esempi di estensione. Il progetto @code{gawkextlib} include diverse altre
+estensioni, di maggiori dimensioni.
+Per chi desideri scrivere un'estensione e metterla a disposizione della
+comunit@`a degli utenti di @command{gawk}, il progetto @code{gawkextlib}
+@`e il posto adatto per farlo.
+
+@end itemize
+
+@c EXCLUDE START
+@node Esercizi sulle estensioni
+@section Esercizi
+
+@enumerate
+@item
+Aggiungere funzioni per rendere disponibili chiamate di sistema come
+@code{chown()}, @code{chmod()} e @code{umask()} nelle estensioni che
+operano con i file viste
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Operazioni interne file}.
+
+@c Idea from comp.lang.awk, February 2015
+@item
+Scrivere un analizzatore di input che stampi un prompt se l'input proviene
+da un dispositivo che sia un ``terminale''. Si pu@`o usare la funzione
+@code{isatty()} per sapere se il file in input @`e un terminale.
+(Suggerimento: questa funzione
+normalmente usa parecchie risorse quando @`e richiamata; si tenti di chiamarla
+una volta sola.)
+Il contenuto del prompt dovrebbe provenire da una variabile che sia possibile
+impostare a livello di codice @command{awk}.
+Si pu@`o inviare il prompt allo standard error. Tuttavia,
+per ottenere risultati migliori, @`e meglio aprire un nuovo descrittore di file
+(o puntatore a un file)
+sul file @file{/dev/tty} e stampare il prompt su quel file, nel caso
+in cui lo standard error sia stato ridiretto.
+
+Perch@'e lo standard error @`e una scelta migliore dello
+standard output per scrivere il prompt?
+Quale meccanismo di lettura andrebbe sostituito, quello che legge un record
+o quello che legge dei semplici byte?
+
+@item
+(Difficile.)
+Come si potrebbero gestire degli insiemi di nomi (@dfn{namespaces})
+in @command{gawk}, in modo
+che i nomi di funzione presenti in estensioni differenti non siano in conflitto
+tra loro?
+Chi riesce a trovare uno schema di buona qualit@`a @`e pregato di contattare il
+manutentore di @command{gawk}, per metterlo al corrente.
+
+@item
+Si scriva uno script di shell che funga da interfaccia per
+l'estensione ``inplace'', vista
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Esempio di estensione Inplace},
+in modo che il comportamento sia simile a quello del comando @samp{sed -i}.
+
+@end enumerate
+@c EXCLUDE END
+
+@ifnotinfo
+@part @value{PART4}Appendici
+@end ifnotinfo
+
+@ifdocbook
+
+@ifclear FOR_PRINT
+La Parte IV contiene le appendici (come pure le due licenze che proteggono
+il codice sorgente di @command{gawk} e questo @value{DOCUMENT},
+rispettivamente) e inoltre il Glossario:
+@end ifclear
+
+@ifset FOR_PRINT
+La Parte IV contiene tre appendici, l'ultima delle quali @`e la licenza
+che protegge il codice sorgente di @command{gawk}:
+@end ifset
+
+@itemize @value{BULLET}
+@item
+@ref{Storia del linguaggio}
+
+@item
+@ref{Installazione}
+
+@ifclear FOR_PRINT
+@item
+@ref{Note}
+
+@item
+@ref{Concetti fondamentali}
+
+@item
+@ref{Glossario}
+@end ifclear
+
+@item
+@ref{Copia}
+
+@ifclear FOR_PRINT
+@item
+@ref{Licenza per Documentazione Libera GNU (FDL)}
+@end ifclear
+@end itemize
+@end ifdocbook
+
+@node Storia del linguaggio
+@appendix L'evoluzione del linguaggio @command{awk}
+
+Questo @value{DOCUMENT} descrive l'implementazione GNU di @command{awk}
+conforme alle specifiche POSIX. Molti degli utenti di lunga data di
+@command{awk} hanno imparato a programmare in @command{awk} usando
+l'implementazione originale di @command{awk} presente nella versione 7 di
+Unix. (Questa versione @`e servita da base per la versione Berkeley Unix di
+@command{awk}, attraverso la versione 4.3BSD-Reno. Successive versioni di
+Berkeley Unix e, per un certo periodo, alcuni sistemi derivati da
+4.4BSD-Lite, hanno usato varie versioni di @command{gawk} come loro
+@command{awk}.) Questo @value{CHAPTER} descrive in breve l'evoluzione
+del linguaggio @command{awk}, facendo riferimento ad altre parti del
+@value{DOCUMENT} dove si possono trovare ulteriori informazioni.
+
+@ifset FOR_PRINT
+Per amor di brevit@`a, sono state omesse in questa edizione informazioni
+sulla storia delle funzionalit@`a di @command{gawk}. Si possono trovare nella
+@uref{http://www.gnu.org/software/gawk/manual/html_node/Feature-History.html,
+documentazione online}.
+@end ifset
+
+@menu
+* V7/SVR3.1:: Le principali differenze tra V7 e System V
+ Release 3.1.
+* SVR4:: Differenze minori tra System V
+ Release 3.1 e 4.
+* POSIX:: Nuove funzionalit@`a per lo standard POSIX.
+* BTL:: Nuove funzionalit@`a dalla versione
+ di @command{awk} di Brian Kernighan.
+* POSIX/GNU:: Le estensioni in @command{gawk} non
+ previste in @command{awk} POSIX.
+* Storia delle funzionalit@`a:: La storia delle funzionalit@`a di
+ @command{gawk}.
+* Estensioni comuni:: Sommario Estensioni comuni.
+* Intervalli e localizzazione:: Come le localizzazioni influiscono sugli
+ intervalli delle espressioni regolari.
+* Contributori:: I maggiori contributori a @command{gawk}.
+* Sommario della storia:: Sommario della storia.
+@end menu
+
+@node V7/SVR3.1
+@appendixsec Differenze importanti tra V7 e System V Release 3.1
+@cindex @command{awk}, versioni di
+@cindex @command{awk}, versioni di, differenze tra V7 e SVR3.1
+
+Il liguaggio @command{awk} si @`e evoluto considerevolmente tra Unix versione
+7 (1978) e la nuova implementazione disponibile a partire da Unix System V
+Release 3.1 (1987). Questa @value{SECTION} riassume le differenze e indica
+dove @`e possibile trovare ulteriori dettagli:
+
+@itemize @value{BULLET}
+@item
+La necessit@`a di inserire @samp{;} per separare pi@`u regole su una riga
+(@pxref{Istruzioni/Righe})
+
+@item
+Funzioni definite dall'utente e istruzione @code{return}
+(@pxref{Funzioni definite dall'utente})
+
+@item
+L'istruzione @code{delete} (@pxref{Cancellazione})
+
+@item
+L'istruzione @code{do}-@code{while}
+(@pxref{Istruzione do})
+
+@item
+Le funzioni predefinite @code{atan2()}, @code{cos()}, @code{sin()}, @code{rand()} e
+@code{srand()} (@pxref{Funzioni numeriche})
+
+@item
+Le funzioni predefinite @code{gsub()}, @code{sub()} e @code{match()}
+(@pxref{Funzioni per stringhe})
+
+@item
+Le funzioni predefinite @code{close()} e @code{system()}
+(@pxref{Funzioni di I/O})
+
+@item
+Le variabili predefinite @code{ARGC}, @code{ARGV}, @code{FNR}, @code{RLENGTH},
+@code{RSTART} e @code{SUBSEP} (@pxref{Variabili predefinite})
+
+@item
+Possibilit@`a di modificare @code{$0} (@pxref{Cambiare i campi})
+
+@item
+L'espressione condizionale che fa uso dell'operatore ternario @samp{?:}
+(@pxref{Espressioni condizionali})
+
+@item
+L'espressione @samp{@var{indice} in @var{vettore}} esterna alle istruzioni
+@code{for} (@pxref{Visitare elementi})
+
+@item
+L'operatore esponenziale @samp{^}
+(@pxref{Operatori aritmetici}) e il relativo operatore di assegnamento
+@samp{^=} (@pxref{Operatori di assegnamento})
+
+@item
+Precedenze tra operatori compatibili con quelle del linguaggio C, che
+rendono non funzionanti alcuni vecchi programmi @command{awk} (@pxref{Precedenza})
+
+@item
+La possibilit@`a di usare @dfn{regexp} come valori di @code{FS}
+(@pxref{Separatori di campo}) e come
+terzo argomento per la funzione @code{split()}
+(@pxref{Funzioni per stringhe}), invece di usare solo il primo carattere
+di @code{FS}
+
+@item
+@dfn{Regexp} dinamiche come operandi degli operatori @samp{~} e @samp{!~}
+(@pxref{Espressioni regolari calcolate})
+
+@item
+Le sequenze di protezione @samp{\b}, @samp{\f} e @samp{\r}
+(@pxref{Sequenze di protezione})
+
+@item
+La ridirezione dell'input per la funzione @code{getline}
+(@pxref{Getline})
+
+@item
+La possibilit@`a di avere pi@`u regole @code{BEGIN} ed @code{END}
+(@pxref{BEGIN/END})
+
+@item
+Vettori multidimensionali
+(@pxref{Vettori multidimensionali})
+@end itemize
+
+@node SVR4
+@appendixsec Differenze tra le versioni System V Release 3.1 e SVR4
+
+@cindex @command{awk}, versioni di, differenze tra SVR3.1 e SVR4
+La versione per Unix System V Release 4 (1989) di @command{awk} ha aggiunto
+queste funzionalit@`a (alcune delle quali introdotte da @command{gawk}):
+
+@itemize @value{BULLET}
+@item
+Il vettore @code{ENVIRON} (@pxref{Variabili predefinite})
+@c gawk and MKS awk
+
+@item
+La possibilit@`a di specificare pi@`u opzioni @option{-f} sulla riga di comando
+(@pxref{Opzioni})
+@c MKS awk
+@c Mortice Kern Systems, ditta produttrice di una versione commerciale di awk
+
+@item
+L'opzione @option{-v} per assegnare variabili prima di iniziare
+l'esecuzione del programma
+(@pxref{Opzioni})
+@c GNU, Bell Laboratories & MKS together
+
+@item
+La notazione @option{--} per indicare la fine delle opzioni sulla riga di
+comando
+
+@item
+Le sequenze di protezione @samp{\a}, @samp{\v} e @samp{\x}
+(@pxref{Sequenze di protezione})
+@c GNU, for ANSI C compat
+
+@item
+Un valore di ritorno definito per la funzione predefinita @code{srand()}
+(@pxref{Funzioni numeriche})
+
+@item
+Le funzioni predefinite per stringhe @code{toupper()} e @code{tolower()}
+per la conversione maiuscolo/minuscolo
+(@pxref{Funzioni per stringhe})
+
+@item
+Una specificazione pi@`u accurata per la lettera @samp{%c} di controllo del
+formato nella funzione @code{printf}
+(@pxref{Lettere di controllo})
+
+@item
+La capacit@`a di decidere dinamicamente la larghezza di un campo e la
+precisione da usare (@code{"%*.*d"}) nella lista degli argomenti passati a
+@code{printf} e @code{sprintf()}
+(@pxref{Lettere di controllo})
+
+@item
+L'uso di costanti @dfn{regexp}, p.es. @code{/pippo/}, come espressioni,
+che equivalgono a usare l'operatore di ricerca di una
+corrispondenza, p.es. @samp{$0 ~ /pippo/}
+(@pxref{Usare le costanti @dfn{regexp}})
+
+@item
+Gestione di sequenze di protezione nell'assegnamento di variabili
+effettuato tramite la riga di comando
+(@pxref{Opzioni di assegnamento})
+@end itemize
+
+@node POSIX
+@appendixsec Differenze tra versione SVR4 e POSIX di @command{awk}
+@cindex @command{awk}, versioni di, differenze tra SVR4 e POSIX @command{awk}
+@cindex POSIX @command{awk}, differenze tra versioni @command{awk}
+
+Lo standard POSIX Command Language and Utilities per @command{awk} (1992)
+ha introdotto le seguenti modifiche al linguaggio:
+
+@itemize @value{BULLET}
+@item
+L'uso dell'opzione @option{-W} per opzioni specifiche a una data
+implementazione
+(@pxref{Opzioni})
+
+@item
+L'uso di @code{CONVFMT} per controllare la conversione di numeri
+in stringhe (@pxref{Conversione})
+
+@item
+Il concetto di stringa numerica e regole di confronto pi@`u precise da seguire
+al riguardo (@pxref{Tipi di variabile e confronti})
+
+@item
+L'uso di variabili predefinite come nomi di parametri delle funzioni @`e vietato
+(@pxref{Sintassi delle definizioni})
+
+@item
+Una documentazione pi@`u completa di molte tra le funzionalit@`a del linguaggio
+precedentemente non documentate
+@end itemize
+
+Nel 2012, un certo numero di estensioni che erano gi@`a comunemente
+disponibili da parecchi anni sono state finalmente aggiunte allo standard
+POSIX. Ecco l'elenco:
+
+@itemize @value{BULLET}
+@item
+La funzione predefinita @code{fflush()} per forzare la scrittura dei buffer
+in output
+(@pxref{Funzioni di I/O})
+
+@item
+L'istruzione @code{nextfile}
+(@pxref{Istruzione nextfile})
+
+@item
+La possibilit@`a di eliminare completamente un vettore con l'istruzione
+@samp{delete @var{vettore}}
+(@pxref{Cancellazione})
+
+@end itemize
+
+@xref{Estensioni comuni} per una lista delle estensioni comuni
+non previste nello standard POSIX.
+
+Lo standard POSIX 2008 @`e reperibile online a:
+@url{http://www.opengroup.org/onlinepubs/9699919799/}.
+
+
+@node BTL
+@appendixsec Estensioni nell'@command{awk} di Brian Kernighan
+
+@cindex @command{awk}, versioni di, si veda anche Brian Kernighan, @command{awk} di
+@cindex estensioni, Brian Kernighan @command{awk}
+@cindex Brian Kernighan, @command{awk} di, estensioni
+@cindex Kernighan, Brian
+Brian Kernighan
+ha reso disponibile la sua versione nel suo sito.
+(@pxref{Altre versioni}).
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive estensioni comuni disponibili per la
+prima volta nella sua versione di @command{awk}:
+
+@itemize @value{BULLET}
+@item
+Gli operatori @samp{**} e @samp{**=}
+(@pxref{Operatori aritmetici}
+e
+@ref{Operatori di assegnamento})
+
+@item
+L'uso di @code{func} come abbreviazione di @code{function}
+(@pxref{Sintassi delle definizioni})
+
+@item
+La funzione predefinita @code{fflush()} per forzare la scrittura dei buffer
+in output
+(@pxref{Funzioni di I/O})
+
+@ignore
+@item
+The @code{SYMTAB} array, that allows access to @command{awk}'s internal symbol
+table. This feature was never documented for his @command{awk}, largely because
+it is somewhat shakily implemented. For instance, you cannot access arrays
+or array elements through it
+@end ignore
+@end itemize
+
+@xref{Estensioni comuni} per una lista completa delle estensioni
+disponibile nel suo @command{awk}.
+
+@node POSIX/GNU
+@appendixsec Estensioni di @command{gawk} non in POSIX @command{awk}
+
+@cindex modalit@`a compatibile di (@command{gawk}), estensioni nella
+@cindex estensioni nella modalit@`a compatibile di (@command{gawk})
+@cindex estensioni, in @command{gawk}, non in POSIX @command{awk}
+@cindex POSIX, estensioni @command{gawk} non incluse in
+L'implementazione GNU di @command{gawk} aggiunge molte funzionalit@`a.
+Queste possono essere disabilitate completamente sia con l'opzione
+@option{--traditional} che con l'opzione
+@option{--posix}
+(@pxref{Opzioni}).
+
+Alcune funzionalit@`a sono state introdotte e successivamente tolte
+con il passare del tempo.
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION}
+sintetizza le ulteriori funzionalit@`a rispetto a POSIX @command{awk} che sono
+presenti nella versione corrente di @command{gawk}.
+
+@itemize @value{BULLET}
+
+@item
+Ulteriori variabili predefinite:
+
+@itemize @value{MINUS}
+@item
+Le variabili
+@code{ARGIND},
+@code{BINMODE},
+@code{ERRNO},
+@code{FIELDWIDTHS},
+@code{FPAT},
+@code{IGNORECASE},
+@code{LINT},
+@code{PROCINFO},
+@code{RT}
+e
+@code{TEXTDOMAIN}
+(@pxref{Variabili predefinite})
+@end itemize
+
+@item
+File speciali verso cui ridirigere l'I/O:
+
+@itemize @value{MINUS}
+@item
+I file @file{/dev/stdin}, @file{/dev/stdout}, @file{/dev/stderr} e i
+@value{FNS} speciali @file{/dev/fd/@var{N}}
+(@pxref{File speciali})
+
+@item
+I file speciali @file{/inet}, @file{/inet4} e @file{/inet6} per
+interagire con la rete TCP/IP usando @samp{|&} per specificare quale
+versione usare del protocollo IP
+(@pxref{Reti TCP/IP})
+@end itemize
+
+@item
+Differenze e/o aggiunte al linguaggio:
+
+@itemize @value{MINUS}
+@item
+La sequenza di protezione @samp{\x}
+(@pxref{Sequenze di protezione})
+
+@item
+Supporto completo per @dfn{regexp} sia POSIX che GNU
+@iftex
+(@pxrefil{Espressioni regolari})
+@end iftex
+@ifnottex
+(@pxref{Espressioni regolari})
+@end ifnottex
+
+@item
+La possibilit@`a che @code{FS} e il terzo
+argomento di @code{split()} siano la stringa nulla
+(@pxref{Campi di un solo carattere})
+
+@item
+La possibilit@`a che @code{RS} sia una @dfn{regexp}
+(@pxref{Record})
+
+@item
+La possibilit@`a di usare costanti ottali ed esadecimali nei programmi
+scritti in @command{awk}
+(@pxref{Numeri non-decimali})
+
+@item
+L'operatore @samp{|&} per poter effettuare I/O bidirezionale verso un
+coprocesso
+(@pxref{I/O bidirezionale})
+
+@item
+Chiamate indirette di funzione
+(@pxref{Chiamate indirette})
+
+@item
+La possibilit@`a di ignorare directory specificate sulla riga di comando,
+emettendo un messaggio di avvertimento
+(@pxref{Directory su riga di comando})
+
+@item
+Errori in output usando @code{print} e @code{printf} non provocano
+necessariamente la fine del programma
+(@pxref{Continuazione dopo errori})
+@end itemize
+
+@item
+Nuove parole chiave:
+
+@itemize @value{MINUS}
+@item
+I criteri di ricerca speciali @code{BEGINFILE} ed @code{ENDFILE}
+(@pxref{BEGINFILE/ENDFILE})
+
+@item
+L'istruzione @code{switch}
+(@pxref{Istruzione switch})
+@end itemize
+
+@item
+Differenze in funzioni standard di @command{awk}:
+
+@itemize @value{MINUS}
+@item
+Il secondo argomento opzionale di @code{close()} che consente di chiudere
+un solo lato dell'I/O di una @dfn{pipe} bidirezionale aperta verso un
+coprocesso (@pxref{I/O bidirezionale})
+
+@item
+Aderenza allo standard POSIX per le funzioni @code{gsub()} e @code{sub()}
+se @`e stata specificata l'opzione @option{--posix}
+
+@item
+La funzione @code{length()} accetta come argomento il nome di un vettore
+e restituisce il numero di elementi nel vettore
+(@pxref{Funzioni per stringhe})
+
+@item
+Il terzo argomento opzionale della funzione @code{match()}
+per contenere eventuali sottoespressioni individuate all'interno di una
+@dfn{regexp}
+(@pxref{Funzioni per stringhe})
+
+@item
+Specificatori posizionali nei formati di @code{printf} per facilitare
+le traduzioni di messaggi
+(@pxref{Ordinamento di printf})
+
+@item
+L'aggiunta di un quarto argomento opzionale alla funzione @code{split()},
+per designare un vettore che contenga il testo dei separatori di campo
+(@pxref{Funzioni per stringhe})
+@end itemize
+
+@item
+Ulteriori funzioni presenti solo in @command{gawk}:
+
+@itemize @value{MINUS}
+@item
+Le funzioni @code{gensub()}, @code{patsplit()} e @code{strtonum()}
+per una gestione di testi pi@`u potente
+(@pxref{Funzioni per stringhe})
+
+@item
+Le funzioni @code{asort()} e @code{asorti()} per l'ordinamento di vettori
+(@pxref{Ordinamento di vettori})
+
+@item
+Le funzioni @code{mktime()}, @code{systime()} e @code{strftime()}
+per lavorare con date e ore
+(@pxref{Funzioni di tempo})
+
+@item
+Le funzioni
+@code{and()},
+@code{compl()},
+@code{lshift()},
+@code{or()},
+@code{rshift()}
+e
+@code{xor()}
+per la manipolazione a livello di bit
+(@pxref{Funzioni a livello di bit})
+@c In 4.1, and(), or() and xor() grew the ability to take > 2 arguments
+
+@item
+La funzione @code{isarray()} per controllare se una variabile @`e un vettore
+oppure no
+(@pxref{Funzioni per i tipi})
+
+@item
+Le funzioni @code{bindtextdomain()}, @code{dcgettext()}
+e @code{dcngettext()} per l'internazionalizzazione
+(@pxref{I18N per programmatore})
+
+@item
+La funzione @code{intdiv()} per effettuare divisioni a numeri interi e
+ottenere il resto della divisione
+(@pxref{Funzioni numeriche})
+@end itemize
+
+@item
+Modifiche e/o aggiunte alle opzioni della riga di comando:
+
+@itemize @value{MINUS}
+@item
+La variabile d'ambiente @env{AWKPATH} per specificare un percorso di ricerca
+per l'opzione @option{-f} della riga di comando
+(@pxref{Opzioni})
+
+@item
+La variabile d'ambiente @env{AWKLIBPATH} per specificare un percorso di ricerca
+per l'opzione @option{-l} della riga di comando
+(@pxref{Opzioni})
+
+@item
+Le opzioni brevi
+@option{-b},
+@option{-c},
+@option{-C},
+@option{-d},
+@option{-D},
+@option{-e},
+@option{-E},
+@option{-g},
+@option{-h},
+@option{-i},
+@option{-l},
+@option{-L},
+@option{-M},
+@option{-n},
+@option{-N},
+@option{-o},
+@option{-O},
+@option{-p},
+@option{-P},
+@option{-r},
+@option{-s},
+@option{-S},
+@option{-t}
+e
+@option{-V}
+. Inoltre, la
+possibilit@`a di usare opzioni in formato lungo (stile GNU) che iniziano
+con @option{--}
+e le opzioni lunghe
+@option{--assign},
+@option{--bignum},
+@option{--characters-as-bytes},
+@option{--copyright},
+@option{--debug},
+@option{--dump-variables},
+@option{--exec},
+@option{--field-separator},
+@option{--file},
+@option{--gen-pot},
+@option{--help},
+@option{--include},
+@option{--lint},
+@option{--lint-old},
+@option{--load},
+@option{--non-decimal-data},
+@option{--optimize},
+@option{--no-optimize},
+@option{--posix},
+@option{--pretty-print},
+@option{--profile},
+@option{--re-interval},
+@option{--sandbox},
+@option{--source},
+@option{--traditional},
+@option{--use-lc-numeric},
+and
+@option{--version}
+(@pxref{Opzioni}).
+@end itemize
+
+@c new ports
+
+@item
+Il supporto per i seguenti sistemi obsoleti @`e stato rimosso dal codice
+sorgente e dalla documentazione di @command{gawk} @value{PVERSION} 4.0:
+
+@c nested table
+@itemize @value{MINUS}
+@item
+Amiga
+
+@item
+Atari
+
+@item
+BeOS
+
+@item
+Cray
+
+@item
+MIPS RiscOS
+
+@item
+MS-DOS con il compilatore Microsoft
+
+@item
+MS-Windows con il compilatore Microsoft
+
+@item
+NeXT
+
+@item
+SunOS 3.x, Sun 386 (Road Runner)
+
+@item
+Tandem (non-POSIX)
+
+@item
+Compilatore pre-standard VAX C per VAX/VMS
+
+@item
+GCC per VAX e Alpha non @`e stato verificato da parecchio tempo.
+
+@end itemize
+
+@item
+Il supporto per i seguenti sistemi obsoleti @`e stato rimosso dal codice
+di @command{gawk} @value{PVERSION} 4.1:
+
+@c nested table
+@itemize @value{MINUS}
+@item
+Ultrix
+@end itemize
+
+@item
+Il supporto per i seguenti sistemi obsoleti @`e stato rimosso dal codice
+sorgente e dalla documentazione di
+@command{gawk} @value{PVERSION} 4.2:
+
+@c nested table
+@itemize @value{MINUS}
+@item
+MirBSD
+
+@item
+GNU/Linux su Alpha
+@end itemize
+
+@end itemize
+
+@c XXX ADD MORE STUFF HERE
+
+
+@c This does not need to be in the formal book.
+@ifclear FOR_PRINT
+@node Storia delle funzionalit@`a
+@appendixsec Storia delle funzionalit@`a di @command{gawk}
+
+@ignore
+See the thread:
+https://groups.google.com/forum/#!topic/comp.lang.awk/SAUiRuff30c
+This motivated me to add this section.
+@end ignore
+
+@ignore
+I've tried to follow this general order, esp.@: for the 3.0 and 3.1 sections:
+ variables
+ special files
+ language changes (e.g., hex constants)
+ differences in standard awk functions
+ new gawk functions
+ new keywords
+ new command-line options
+ behavioral changes
+ new ports
+Within each category, be alphabetical.
+@end ignore
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive le funzionalit@`a in @command{gawk}
+in aggiunta a quelle di POSIX @command{awk},
+nell'ordine in cui sono state rese disponibili in @command{gawk}.
+
+La versione 2.10 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+@item
+La variabile d'ambiente @env{AWKPATH} per specificare un percorso di ricerca
+per l'opzione @option{-f} della riga di comando
+(@pxref{Opzioni})
+
+@item
+La variabile @code{IGNORECASE} e i suoi effetti
+(@pxref{Maiuscolo-Minuscolo}).
+
+@item
+I file @file{/dev/stdin}, @file{/dev/stdout}, @file{/dev/stderr} e i
+@value{FNS} speciali @file{/dev/fd/@var{N}}
+(@pxref{File speciali})
+@end itemize
+
+La versione 2.13 di @command{gawk} ha ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+@item
+La variabile @code{FIELDWIDTHS} e i suoi effetti
+(@pxref{Dimensione costante}).
+
+@item
+Le funzioni predefinite @code{systime()} e @code{strftime()} per ottenere
+e stampare data e ora
+(@pxref{Funzioni di tempo}).
+
+@item
+Ulteriori opzioni dalla riga di comando
+(@pxref{Opzioni}):
+
+@itemize @value{MINUS}
+@item
+L'opzione @option{-W lint} per fornire controlli su possibili errori e per
+la portabilit@`a, sia a livello di codice sorgente che in fase di esecuzione.
+
+@item
+L'opzione @option{-W compat} per inibire le estensioni GNU.
+
+@item
+L'opzione @option{-W posix} per richiedere una stretta aderenza allo
+standard POSIX.
+@end itemize
+@end itemize
+
+La versione 2.14 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+@item
+L'istruzione @code{next file} per passare immediatamente al successivo
+@value{DF} (@pxref{Istruzione nextfile}).
+@end itemize
+
+La versione 2.15 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+@item
+Nuove variabili (@pxref{Variabili predefinite}):
+
+@itemize @value{MINUS}
+@item
+@code{ARGIND}, che permette di controllare la posizione di @code{FILENAME}
+nel vettore @code{ARGV}.
+
+@item
+@code{ERRNO}, che contiene il messaggio di errore del sistema quando
+@code{getline} restituisce @minus{}1 o @code{close()} non termina con successo.
+@end itemize
+
+@item
+I @value{FNS} speciali @file{/dev/pid}, @file{/dev/ppid}, @file{/dev/pgrpid}
+e @file{/dev/user}. Questo supporto @`e stato rimosso in seguito.
+
+@item
+La possibilit@`a di cancellare un intero vettore in una sola istruzione
+con @samp{delete @var{vettore}}
+(@pxref{Cancellazione}).
+
+@item
+Modifiche nelle opzioni della riga di comando
+(@pxref{Opzioni}):
+
+@itemize @value{MINUS}
+@item
+La possibilit@`a di usare opzioni in formato lungo (in stile GNU) che iniziano
+con @option{--}.
+
+@item
+L'opzione @option{--source} per combinare codice sorgente immesso nella riga
+di comando e codice sorgente proveniente da file di libreria.
+@end itemize
+@end itemize
+
+La versione 3.0 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+@item
+Variabili nuove o modificate:
+
+@itemize @value{MINUS}
+@item
+@code{IGNORECASE} modificato, diventa applicabile al confronto tra stringhe,
+come pure alle operazioni su @dfn{regexp}
+(@pxref{Maiuscolo-Minuscolo}).
+
+@item
+@code{RT}, che contiene il testo in input che @`e stato individuato da @code{RS}
+(@pxref{Record}).
+@end itemize
+
+@item
+Supporto completo sia per le @dfn{regexp} POSIX sia per quelle GNU
+@iftex
+(@pxrefil{Espressioni regolari}).
+@end iftex
+@ifnottex
+(@pxref{Espressioni regolari}).
+@end ifnottex
+
+@item
+La funzione @code{gensub()} per migliorare la manipolazione di testi
+(@pxref{Funzioni per stringhe}).
+
+@item
+La funzione @code{strftime()} prevede un formato di data e ora di default,
+in modo da poter essere chiamata senza alcun argomento.
+(@pxref{Funzioni di tempo}).
+
+@item
+La possibilit@`a che @code{FS} e il terzo argomento della funzione
+@code{split()} siano delle stringhe nulle
+(@pxref{Campi di un solo carattere}).
+
+@item
+La possibilit@`a che @code{RS} sia una @dfn{regexp}
+(@pxref{Record}).
+
+@item
+L'istruzione @code{next file} @`e diventata @code{nextfile}
+(@pxref{Istruzione nextfile}).
+
+@item
+La funzione @code{fflush()} di
+BWK @command{awk}
+(BWK allora lavorava ai Bell Laboratories;
+@pxref{Funzioni di I/O}).
+
+@item
+Nuove opzioni della riga di comando:
+
+@itemize @value{MINUS}
+@item
+L'opzione @option{--lint-old} per
+ottenere messaggi relativi a costrutti non disponibili
+nell'implementazione di @command{awk} per Unix Version 7
+(@pxref{V7/SVR3.1}).
+
+@item
+L'opzione @option{-m} da BWK @command{awk}. (Brian lavorava
+ancora ai Bell Laboratories all'epoca.) Quest'opzione @`e stata in seguito
+rimossa, sia dal suo @command{awk} che da @command{gawk}.
+
+@item
+L'opzione @option{--re-interval} per consentire di specificare
+espressioni di intervallo nelle @dfn{regexp}
+(@pxref{Operatori di espressioni regolari}).
+
+@item
+L'opzione @option{--traditional} aggiunta come maniera pi@`u intuitiva
+per richiedere l'opzione
+@option{--compat} (@pxref{Opzioni}).
+@end itemize
+
+@item
+L'uso di GNU Autoconf per controllare il processo di configurazione
+(@pxref{Installazione veloce}).
+
+@item
+Supporto per Amiga.
+Questo supporto @`e stato rimosso in seguito.
+
+@end itemize
+
+La versione 3.1 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+@item
+Nuove variabili
+(@pxref{Variabili predefinite}):
+
+@itemize @value{MINUS}
+@item
+@code{BINMODE}, per sistemi non aderenti allo standard POSIX,
+che consente I/O binario per file in input e/o output
+(@pxref{Uso su PC}).
+
+@item
+@code{LINT}, che controlla dinamicamente gli avvertimenti emessi da @dfn{lint}.
+
+@item
+@code{PROCINFO}, un vettore che fornisce informazioni correlate con il
+processo in esecuzione.
+
+@item
+@code{TEXTDOMAIN}, per impostare il dominio testuale in cui internazionalizzare
+un'applicazione (@pxref{Internazionalizzazione}).
+@end itemize
+
+@item
+La possibilit@`a di usare costanti ottali ed esadecimali nel codice
+sorgente di programmi @command{awk}.
+(@pxref{Numeri non-decimali}).
+
+@item
+L'operatore @samp{|&} per effettuare I/O bidirezionale verso un
+coprocesso
+(@pxref{I/O bidirezionale}).
+
+@item
+I file speciali @file{/inet} per interagire con reti TCP/IP usando @samp{|&}
+(@pxref{Reti TCP/IP}).
+
+@item
+Il secondo argomento opzionale della funzione @code{close()} per permettere di
+chiudere uno dei lati di una @dfn{pipe} bidirezionale aperta con un coprocesso
+(@pxref{I/O bidirezionale}).
+
+@item
+Il terzo argomento opzionale della funzione @code{match()} per
+avere a disposizione le diverse sottoespressioni individuate all'interno
+di una @dfn{regexp}
+(@pxref{Funzioni per stringhe}).
+
+@item
+Specificatori posizionali nelle stringhe di formato di @code{printf} per
+facilitare la traduzione di messaggi
+(@pxref{Ordinamento di printf}).
+
+@item
+Alcune nuove funzioni predefinite:
+
+@itemize @value{MINUS}
+@item
+Le funzioni @code{asort()} e @code{asorti()} per l'ordinamento di vettori
+(@pxref{Ordinamento di vettori}).
+
+@item
+Le funzioni @code{bindtextdomain()}, @code{dcgettext()} e @code{dcngettext()}
+per l'internationalizzazione
+(@pxref{I18N per programmatore}).
+
+@item
+La funzione @code{extension()} e la possibilit@`a di aggiungere
+nuove funzioni predefinite dinamicamente
+@iftex
+(@pxrefil{Estensioni dinamiche}).
+@end iftex
+@ifnottex
+(@pxref{Estensioni dinamiche}).
+@end ifnottex
+
+@item
+La funzione @code{mktime()} per generare date e ore
+(@pxref{Funzioni di tempo}).
+
+@item
+Le funzioni @code{and()}, @code{or()}, @code{xor()}, @code{compl()},
+@code{lshift()}, @code{rshift()} e @code{strtonum()}
+(@pxref{Funzioni a livello di bit}).
+@end itemize
+
+@item
+@cindex @code{next file} statement
+Il supporto per @samp{next file} scritto come due parole @`e stato rimosso
+completamente
+(@pxref{Istruzione nextfile}).
+
+@item
+Ulteriori opzioni sulla riga di comando
+(@pxref{Opzioni}):
+
+@itemize @value{MINUS}
+@item
+L'opzione @option{--dump-variables} per stampare una lista di tutte le
+variabili globali.
+
+@item
+L'opzione @option{--exec}, da usare in script CGI [Common Gateway Interface].
+
+@item
+L'opzione della riga di comando @option{--gen-po} e l'uso di un trattino
+basso a inizio stringa, per segnalare stringhe che dovrebbero essere tradotte
+(@pxref{Estrazione di stringhe}).
+
+@item
+L'opzione @option{--non-decimal-data} per consentire di avere dati in input
+di tipo non decimale
+(@pxref{Dati non decimali}).
+
+@item
+L'opzione @option{--profile} e @command{pgawk}, la
+versione profilatrice di @command{gawk}, per produrre profili di esecuzione
+di programmi @command{awk}
+(@pxref{Profilare}).
+
+@item
+L'opzione @option{--use-lc-numeric} per richiedere a @command{gawk}
+di usare il carattere di separazione decimale proprio della localizzazione
+nell'elaborazione dei dati in input
+(@pxref{Conversione}).
+@end itemize
+
+@item
+L'uso di GNU Automake a supporto della standardizzazione del processo
+di configurazione
+(@pxref{Installazione veloce}).
+
+@item
+L'uso di GNU @command{gettext} per i messaggi emessi da @command{gawk}
+(@pxref{Gawk internazionalizzato}).
+
+@item
+Supporto per BeOS. Rimosso in seguito.
+
+@item
+Supporto per Tandem. Rimosso in seguito.
+
+@item
+La versione per Atari ufficialmente non @`e pi@`u supportata e in seguito
+@`e stata completamente rimossa.
+
+@item
+Modifiche al codice sorgente per usare definizioni di funzione secondo lo
+stile di codifica dello standard ISO C.
+
+@item
+Aderenza alla specifica POSIX per le funzioni @code{sub()} e @code{gsub()}
+(@pxref{Dettagli ostici}).
+
+@item
+La funzione @code{length()} @`e stata estesa per accettare un vettore come
+argomento, e restituire in tal caso il numero di elementi nel vettore
+(@pxref{Funzioni per stringhe}).
+
+@item
+La funzione @code{strftime()} accetta un terzo argomento per
+dare la possibilit@`a di stampare data e ora nel formato UTC
+(@pxref{Funzioni di tempo}).
+@end itemize
+
+La versione 4.0 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+
+@item
+Aggiunta di variabili:
+
+@itemize @value{MINUS}
+@item
+@code{FPAT}, che permette di specificare una @dfn{regexp} che individua
+i campi, invece che individuare il separatore tra i campi
+(@pxref{Separazione in base al contenuto}).
+
+@item
+Se esiste l'elemento di vettore @code{PROCINFO["sorted_in"]}, il ciclo
+@samp{for(indice in pippo)} ordina
+gli indici, prima di iniziare il ciclo. Il valore di questo elemento
+permette di controllare l'ordinamento degli indici prima di iniziare il
+ciclo che li visita tutti
+(@pxref{Controllare visita}).
+
+@item
+@code{PROCINFO["strftime"]}, che contiene la stringa di formato
+di default per @code{strftime()}
+(@pxref{Funzioni di tempo}).
+@end itemize
+
+@item
+I file speciali @file{/dev/pid}, @file{/dev/ppid}, @file{/dev/pgrpid}
+e @file{/dev/user} sono stati rimossi.
+
+@item
+Il supporto per IPv6 @`e stato aggiunto attraverso il file speciale
+@file{/inet6}.
+Il file speciale @file{/inet4} consente di operare con IPv4 e @file{/inet}
+opera con il default di sistema, che probabilmente @`e IPv4
+(@pxref{Reti TCP/IP}).
+
+@item
+L'uso delle sequenze di protezione @samp{\s} e @samp{\S} nelle espressioni
+regolari
+(@pxref{Operatori di @dfn{regexp} GNU}).
+
+@item
+Le espressioni di intervallo sono consentite per default nelle espressioni
+regolari
+(@pxref{Operatori di espressioni regolari}).
+
+@item
+La classi di caratteri POSIX sono consentite anche se si @`e specificata
+l'opzione @option{--traditional}
+(@pxref{Operatori di espressioni regolari}).
+
+@item
+@code{break} e @code{continue} non sono pi@`u consentiti fuori da un ciclo,
+anche se si @`e specificata l'opzione @option{--traditional}
+(@pxref{Istruzione break} e anche la
+@ref{Istruzione continue}).
+
+@item
+@code{fflush()}, @code{nextfile} e @samp{delete @var{array}}
+sono consentite anche se @`e stata specificata l'opzione @option{--posix} o
+@option{--traditional}, poich@'e questi costrutti sono ora inclusi
+nello standard POSIX.
+
+@item
+Un terzo argomento facoltativo per le funzioni @code{asort()} e @code{asorti()}
+permette di specificare il tipo di ordinamento desiderato
+(@pxref{Funzioni per stringhe}).
+
+@item
+Il comportamento di @code{fflush()} @`e stato modificato per corrispondere
+a quello di BWK @command{awk}
+e per lo standard POSIX; ora sia @samp{fflush()} che @samp{fflush("")}
+forzano la scrittura di tutte le ridirezioni in output aperte
+(@pxref{Funzioni di I/O}).
+
+@item
+La funzione @code{isarray()}
+determina se un elemento @`e un vettore oppure no
+per rendere possibile la visita di vettori di vettori
+(@pxref{Funzioni per i tipi}).
+
+@item
+La funzione @code{patsplit()} che
+fornisce le stesse funzionalit@`a di @code{FPAT}, per suddividere delle stringhe
+(@pxref{Funzioni per stringhe}).
+
+@item
+Un quarto argomento opzionale per la funzione @code{split()},
+che indica un vettore destinato a contenere i valori dei separatori
+(@pxref{Funzioni per stringhe}).
+
+@item
+Vettori di vettori
+(@pxref{Vettori di vettori}).
+
+@item
+I criteri di ricerca speciali @code{BEGINFILE} ed @code{ENDFILE}
+(@pxref{BEGINFILE/ENDFILE}).
+
+@item
+Chiamate indirette di funzioni
+(@pxref{Chiamate indirette}).
+
+@item
+Le istruzioni @code{switch} / @code{case} sono disponibili per default
+(@pxref{Istruzione switch}).
+
+@item
+Modifiche nelle opzioni della riga di comando
+(@pxref{Opzioni}):
+
+@itemize @value{MINUS}
+@item
+Le opzioni @option{-b} e @option{--characters-as-bytes},
+che impediscono che @command{gawk} tratti l'input come composto da una
+stringa di caratteri multibyte.
+
+@item
+Rimozione delle opzioni ridondanti (in notazione lunga) @option{--compat},
+@option{--copyleft} e @option{--usage}.
+
+@item
+L'opzione @option{--gen-po} @`e stata finalmente rinominata
+@option{--gen-pot} per correttezza.
+
+@item
+L'opzione @option{--sandbox} che disabilita alcune funzionalit@`a [per operare
+in un ambiente "protetto"].
+
+@item
+Tutte le opzioni in notazione lunga hanno acquisito opzioni corrispondenti
+in notazione breve, per poter essere usate negli script di shell @samp{#!}.
+@end itemize
+
+@item
+I nomi di directory che appaiono sulla riga di comando generano adesso
+un messaggio di errore, ma non interrompono l'elaborazione, a meno che non
+siano state specificate le opzioni @option{--posix} o @option{--traditional}
+(@pxref{Directory su riga di comando}).
+
+@item
+Il codice interno di @command{gawk} @`e stato riscritto, aggiungendo la
+versione per il debug @command{dgawk},
+con un possibile miglioramento nei tempi di esecuzione
+@iftex
+(@pxrefil{Debugger}).
+@end iftex
+@ifnottex
+(@pxref{Debugger}).
+@end ifnottex
+
+@item
+In aderenza agli standard di codifica GNU, le estensioni dinamiche devono
+definire un simbolo globale che indica che sono compatibili con la
+licenza GPL
+(@pxref{Licenza delle estensioni}).
+
+@item
+In modalit@`a POSIX, i confronti tra stringhe usano le funzioni di
+libreria @code{strcoll()} / @code{wcscoll()}
+(@pxref{Confronto POSIX di stringhe}).
+
+@item
+L'opzione per usare @dfn{socket} in maniera @dfn{raw} (nativa) @`e stata
+rimossa, perch@'e non era mai stata implementata
+(@pxref{Reti TCP/IP}).
+
+@item
+Intervalli nella forma @samp{[d-h]} sono elaborati come se fossero scritti
+nella localizzazione C, a prescindere da che tipo di @dfn{regexp} @`e usata,
+anche se era stata specificata l'opzione
+@option{--posix}
+(@pxref{Intervalli e localizzazione}).
+
+@item
+@`E stato rimosso il supporto per i seguenti sistemi:
+
+@itemize @value{MINUS}
+@item
+Atari
+
+@item
+Amiga
+
+@item
+BeOS
+
+@item
+Cray
+
+@item
+MIPS RiscOS
+
+@item
+MS-DOS con Compilatore Microsoft
+
+@item
+MS-Windows con Compilatore Microsoft
+
+@item
+NeXT
+
+@item
+SunOS 3.x, Sun 386 (Road Runner)
+
+@item
+Tandem (non-POSIX)
+
+@item
+Compilatore pre-standard VAX C per VAX/VMS
+@end itemize
+@end itemize
+
+La versione 4.1 di @command{gawk} ha introdotto le seguenti funzionalit@`a:
+
+@itemize @value{BULLET}
+
+@item
+Tre nuovi vettori:
+@code{SYMTAB}, @code{FUNCTAB} e @code{PROCINFO["identifiers"]}
+(@pxref{Variabili auto-assegnate}).
+
+@item
+I tre comandi eseguibili @command{gawk}, @command{pgawk} e @command{dgawk},
+sono diventati uno solo, con il solo nome @command{gawk}. Di conseguenza
+le opzioni sulla riga di comando sono state modificate.
+
+@item
+Modifiche delle opzioni da riga di comando
+(@pxref{Opzioni}):
+
+@itemize @value{MINUS}
+@item
+L'opzione @option{-D} attiva il debugger.
+
+@item
+Le opzioni @option{-i} e @option{--include}
+caricano dei file di libreria @command{awk}.
+
+@item
+Le opzioni @option{-l} e @option{--load} caricano estensioni dinamiche
+compilate.
+
+@item
+Le opzioni @option{-M} e @option{--bignum} abilitano la libreria MPFR per
+il calcolo con un numero arbitrario di cifre significative.
+
+@item
+L'opzione @option{-o} serve solo a ottenere in output una stampa formattata
+elegantemente del programma da eseguire.
+
+@item
+L'opzione @option{-p} @`e usata per "profilare" l'esecuzione del programma.
+
+@item
+L'opzione @option{-R} @`e stata rimossa.
+@end itemize
+
+@item
+Supporto per il calcolo ad alta precisione con MPFR
+(@pxref{Calcolo con precisione arbitraria}).
+
+@item
+Le funzioni @code{and()}, @code{or()} e @code{xor()} sono state modificate
+per ammettere un numero qualsiasi di argomenti, con un minimo di due
+(@pxref{Funzioni a livello di bit}).
+
+
+@item
+L'interfaccia che rende possibile l'estensione dinamica @`e stata rifatta
+completamente
+@iftex
+(@pxrefil{Estensioni dinamiche}).
+@end iftex
+@ifnottex
+(@pxref{Estensioni dinamiche}).
+@end ifnottex
+
+@item
+La funzione @code{getline} ridiretta @`e stata resa possibile all'interno di
+@code{BEGINFILE} ed @code{ENDFILE}
+(@pxref{BEGINFILE/ENDFILE}).
+
+@item
+Il comando @code{where} @`e stato aggiunto al debugger
+(@pxref{Stack di esecuzione}).
+
+@item
+Il supporto per Ultrix @`e stato rimosso.
+
+@end itemize
+
+La versione 4.2 ha introdotto le seguenti funzionalit@`a:
+
+@itemize @bullet
+@item
+Differenze apportate alle variabili di ambiente (@code{ENVIRON}) sono riflesse in quelle
+rese disponibili a @command{gawk} e in quelle di programmi che siano da esso richiamati.
+@xref{Variabili auto-assegnate}.
+
+@item
+L'opzione @option{--pretty-print} non esegue pi@`u, dopo averlo stampato,
+il programma @command{awk}.
+@xref{Opzioni}.
+
+@item
+Il programma @command{igawk} e le relative pagine di manuale non sono
+pi@`u installati come parte dell'installazione di @command{gawk}.
+@xref{Programma igawk}.
+
+@item
+La funzione @code{intdiv()}.
+@xref{Funzioni numeriche}.
+
+@item
+Il massimo numero di cifre esadecimali permesse nelle sequenze di
+protezione @samp{\x} @`e ora limitato a due.
+@xref{Sequenze di protezione}.
+
+@item
+@code{print} e @code{printf} non terminano il programma dopo alcuni
+errori di output.
+@xref{Continuazione dopo errori}.
+
+@item
+Per molti anni, lo standard POSIX richiedeva che la separazione dei campi
+di un record fosse fatta per default
+quando si incontrano spazi e TAB, e questo @`e il comportamento di
+@command{gawk} se si specifica l'opzione @option{--posix}. Dal 2013
+il comportamento originario @`e stato ripristinato, e ora
+il default per separare i campi con l'opzione @option{--posix} ammette
+anche il ritorno a capo come separatore di campi.
+
+@item
+Il supporto per MirBSD @`e stato rimosso.
+
+@item
+Il supporto per GNU/Linux sull'architettura Alpha @`e stato rimosso.
+@end itemize
+
+@c XXX ADD MORE STUFF HERE
+@end ifclear
+
+@node Estensioni comuni
+@appendixsec Sommario Estensioni Comuni
+
+@cindex estensioni, Brian Kernighan @command{awk}
+@cindex estensioni, @command{mawk}
+La tabella seguente dettaglia le estensioni comuni supportate
+da @command{gawk}, da Brian Kernighan @command{awk} e da @command{mawk},
+le tre versioni liberamente disponibili pi@`u usate di @command{awk}
+(@pxref{Altre versioni}).
+
+@multitable {File speciale @file{/dev/stderr}} {BWK @command{awk} } {@command{mawk}} {@command{gawk}} {Standard attuale}
+@headitem Funzionalit@`a @tab BWK @command{awk} @tab @command{mawk} @tab @command{gawk} @tab Standard attuale
+@item Sequenza di protezione @samp{\x} @tab X @tab X @tab X @tab
+@item Stringa nulla come @code{FS} @tab X @tab X @tab X @tab
+@item File speciale @file{/dev/stdin} @tab X @tab X @tab X @tab
+@item File speciale @file{/dev/stdout} @tab X @tab X @tab X @tab
+@item File speciale @file{/dev/stderr} @tab X @tab X @tab X @tab
+@item @code{delete} senza indici @tab X @tab X @tab X @tab X
+@item Funzione @code{fflush()} @tab X @tab X @tab X @tab X
+@item @code{length()} di un vettore @tab X @tab X @tab X @tab
+@item Istruzione @code{nextfile} @tab X @tab X @tab X @tab X
+@item Operatori @code{**} e @code{**=} @tab X @tab @tab X @tab
+@item Parola chiave @code{func} @tab X @tab @tab X @tab
+@item Variabile @code{BINMODE} @tab @tab X @tab X @tab
+@item @code{RS} come @dfn{regexp} @tab @tab X @tab X @tab
+@item Funzioni gestione data/ora @tab @tab X @tab X @tab
+@end multitable
+
+@node Intervalli e localizzazione
+@appendixsec Intervalli @dfn{regexp} e localizzazione: una lunga e triste storia
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} descrive la storia confusionaria degli intervalli
+all'interno di espressioni regolari, le loro relazioni con la localizzazione,
+e l'effetto da ci@`o determinato su diverse versioni di @command{gawk}.
+
+Gli strumenti originali Unix aventi a che fare con espressioni regolari
+stabilivano che intervalli di caratteri (come @samp{[a-z]}) individuavano
+un carattere qualsiasi tra il primo carattere dell'intervallo e l'ultimo
+carattere dello stesso, entrambi inclusi. L'ordinamento era basato sul
+valore numerico di ogni carattere come era rappresentato all'interno
+del computer, nell'insieme di caratteri proprio di ogni macchina.
+Quindi, su sistemi che adottano la codifica ASCII, @samp{[a-z]} individua
+tutte le lettere minuscole, e solo
+quelle, in quanto i valori numerici che rappresentano le lettere dalla
+@samp{a} fino alla @samp{z} sono contigui. (In un sistema che adotta la
+codifica EBCDIC, l'intervallo @samp{[a-z]} comprende anche ulteriori
+caratteri non alfabetici.)
+
+Quasi tutti i testi di introduzione allo Unix spiegavano che le espressioni
+di intervallo funzionavano in questo modo, e in particolare insegnavano che
+la maniera ``corretta'' per individuare le lettere minuscole era con
+@samp{[a-z]} e che @samp{[A-Z]} era il modo ``corretto'' per individuare le
+lettere maiuscole.
+E, in effetti, era proprio cos@`{@dotless{i}}.@footnote{E la vita era semplice.}
+
+Lo standard POSIX 1992 introduceva l'idea di localizzazione
+(@pxref{Localizzazioni}).
+Poich@'e molte localizzazioni comprendono altre lettere, oltre alle 26
+lettere dell'alfabeto inglese, lo standard POSIX introduceva le classi
+di carattere (@pxref{Espressioni tra parentesi quadre}) per permettere
+l'individuazione di differenti insiemi di caratteri, in aggiunta a quelli
+tradizionali presenti nell'insieme di caratteri ASCII.
+
+Tuttavia, lo standard @emph{ha modificato} l'interpretazione delle
+espressioni di intervallo.
+Nelle localizzazioni @code{"C"} e @code{"POSIX"},
+un'espressione di intervallo come
+@samp{[a-dx-z]} @`e ancora equivalente a @samp{[abcdxyz]}, secondo l'ordine
+della codifica ASCII.
+Ma in tutte le altre localizzazioni l'ordinamento @`e basato su quel che
+si chiama @dfn{ordine di collazione}.
+
+Cosa vuol dire?
+In molte localizzazioni, le lettere @samp{A} e @samp{a} vengono entrambe
+prima di @samp{B}.
+In altre parole, queste localizzazioni ordinano i caratteri nel modo in cui
+sono ordinati in un dizionario,
+e @samp{[a-dx-z]} non @`e detto che equivalga a @samp{[abcdxyz]};
+invece, potrebbe essere equivalente a @samp{[ABCXYabcdxyz]}, per fare un
+esempio.
+
+Su questo punto @`e opportuno insistere: molta documentazione afferma che
+si dovrebbe usare @samp{[a-z]} per identificare un carattere minuscolo.
+Ma su sistemi con localizzazioni
+non-ASCII, un tale intervallo potrebbe includere tutti i caratteri maiuscoli
+tranne @samp{A} o @samp{Z}! Questo ha continuato a essere una fonte di
+equivoci perfino nel ventunesimo secolo.
+
+Per dare un'idea del tipo di problemi, l'esempio seguente usa la funzione
+@code{sub()}, che effettua una sostituzione di testo all'interno di una
+stringa (@pxref{Funzioni per stringhe}). Qui, l'idea @`e quella di rimuovere
+i caratteri maiuscoli a fine stringa:
+
+@example
+$ @kbd{echo qualcosa1234abc | gawk-3.1.8 '@{ sub("[A-Z]*$", ""); print @}'}
+@print{} qualcosa1234a
+@end example
+
+@noindent
+Questo non @`e l'output che ci si aspettava, perch@'e, il @samp{bc} alla fine di
+@samp{qualcosa1234abc} non dovrebbe essere individuato da @samp{[A-Z]*}.
+Un tale risultato dipende dalle impostazioni di localizzazione (e quindi
+potrebbe non succedere sul sistema che si sta usando).
+
+@cindex Unicode
+Considerazioni simili valgono per altri intervalli. Per esempio, @samp{["-/]}
+@`e perfettamente valido in ASCII, ma non @`e valido in molte localizzazioni
+Unicode, p.es. in @code{en_US.UTF-8}.
+
+Il codice delle prime versioni di @command{gawk} per individuare le
+@dfn{regexp} non teneva conto della localizzazione, e quindi gli
+intervalli potevano essere interpretati in maniera tradizionale.
+
+Quando @command{gawk} ha iniziato a usare metodi di ricerca di @dfn{regexp}
+che tengono conto della localizzazione, sono iniziati i problemi;
+a maggior ragione in quanto sia GNU/Linux che i venditori di versioni
+commerciali di Unix
+avevano iniziato a implementare localizzazioni non-ASCII,
+@emph{adottandole per default}. La domanda che forse si udiva pi@`u spesso
+era del tipo: ``Perch@'e @samp{[A-Z]} individua lettere minuscole?!?''
+
+@cindex Berry, Karl
+Questa situazione @`e in essere da circa 10 anni, se non di pi@`u, e
+il manutentore di @command{gawk} si @`e stufato di continuare a spiegare che
+@command{gawk} stava semplicemente implementando quelli che sono gli
+standard, e che il problema stava nella localizzazione dell'utente. Nella
+fase di sviluppo della @value{PVERSION} 4.0, @command{gawk} @`e stato modificato
+in modo da trattare sempre gli
+intervalli "come si faceva prima di POSIX", a meno che non si specifichi
+l'opzione @option{--posix} (@pxref{Opzioni}).@footnote{Ed
+@`e cos@`{@dotless{i}} che @`e nata la Campagna per l'Interpretazione Razionale degli
+Intervalli (in inglese, RRI [@dfn{Rational Range Interpretation}]).
+Un certo
+numero di strumenti GNU hanno gi@`a implementato questa modifica, o
+lo faranno presto. Grazie a Karl Berry per aver coniato la frase
+``Rational Range Interpretation''.}
+
+Fortunatamente, un po' prima del rilascio definitivo della versione 4.0 di
+@command{gawk}, il manutentore ha appreso che lo standard 2008 aveva
+modificato la definizione di intervallo, e che, al di fuori delle
+localizzazioni @code{"C"} e @code{"POSIX"}, il significato di espressione
+di intervallo era ora
+@emph{indefinito}.@footnote{Si veda
+@uref{http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05, lo standard}
+e
+@uref{http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap09.html#tag_21_09_03_05, le motivazioni}.}
+
+Adottando questo simpatico termine tecnico, lo standard permette agli
+implementatori di implementare gli intervalli nella maniera che preferiscono.
+Il manutentore di @command{gawk} ha deciso di implementare la regola pre-POSIX
+sia per l'individuazione di default delle @dfn{regexp} sia quando si
+specificano le opzioni @option{--traditional} o @option{--posix}.
+In ogni caso @command{gawk} aderisce allo standard POSIX.
+
+@node Contributori
+@appendixsec I principali contributori a @command{gawk}
+@cindex @command{gawk}, lista di contributori a
+@quotation
+@i{Riconoscere sempre il merito, se un merito va riconosciuto.}
+@author Anonimo
+@end quotation
+
+Questa @value{SECTION} elenca le persone che hanno maggiormente contribuito
+allo sviluppo di @command{gawk} e/o alla stesura di questo @value{DOCUMENT},
+in ordine approssimativamente cronologico:
+
+@itemize @value{BULLET}
+@item
+@cindex Aho, Alfred
+@cindex Weinberger, Peter
+@cindex Kernighan, Brian
+Il Dr.@: Alfred V.@: Aho,
+il Dr.@: Peter J.@: Weinberger, e
+il Dr.@: Brian W.@: Kernighan, tutti dei Bell Laboratories,
+hanno progettato e implementato @command{awk} per Unix,
+da cui @command{gawk} trae la maggioranza delle sue funzionalit@`a.
+
+@item
+@cindex Rubin, Paul
+Paul Rubin,
+autore del progetto e dell'implementazione iniziale del 1986, ha
+scritto la prima bozza (di circa 40 pagine) di questo @value{DOCUMENT}.
+
+@item
+@cindex Fenlason, Jay
+Jay Fenlason
+ha completato l'implementazione iniziale.
+
+@item
+@cindex Close, Diane
+Diane Close
+ha rivisto la prima bozza di questo @value{DOCUMENT}, portandolo alla
+lunghezza di circa 90 pagine.
+
+@item
+@cindex Stallman, Richard
+Richard Stallman
+ha aiutato a completare l'implementazione e la bozza iniziale di questo
+@value{DOCUMENT}.
+@`E anche il fondatore della FSF e del progetto GNU.
+
+@item
+@cindex Woods, John
+John Woods
+ha scritto porzioni di codice (volti principalmente alla correzione di
+errori) nella versione iniziale di @command{gawk}.
+
+@item
+@cindex Trueman, David
+Nel 1988,
+David Trueman
+si @`e fatto carico della manutenzione principale di @command{gawk},
+rendendolo compatibile col ``nuovo'' @command{awk} e
+migliorandone parecchio la velocit@`a di esecuzione.
+
+@item
+@cindex Kwok, Conrad
+@cindex Garfinkle, Scott
+@cindex Williams, Kent
+Conrad Kwok,
+Scott Garfinkle
+e
+Kent Williams
+hanno per primi portato il programma all'ambiente MS-DOS, usando varie
+versioni del compilatore MSC.
+
+@item
+@cindex Rankin, Pat
+Pat Rankin
+ha portato il programma all'ambiente VMS, preparando anche la relativa
+documentazione.
+
+@item
+@cindex Peterson, Hal
+Hal Peterson
+@`e stato di aiuto nel portare @command{gawk} nei sistemy Cray.
+(L'ambiente Cray non @`e pi@`u supportato.)
+
+@item
+@cindex Rommel, Kai Uwe
+Kai Uwe Rommel
+ha portato per primo il programma all'ambiente OS/2, preparando anche
+la relativa documentazione.
+
+@item
+@cindex Jaegermann, Michal
+Michal Jaegermann
+ha portato il programma all'ambiente Atari, preparando anche la relativa
+documentazione.
+(L'ambiente Atari non @`e pi@`u supportato.)
+Michal continua a effettuare controlli di portabilit@`a,
+e ha molto contribuito a consentire a @command{gawk}
+di funzionare su sistemi diversi da quelli a 32 bit.
+
+@item
+@cindex Fish, Fred
+Fred Fish
+ha portato il programma all'ambiente Amiga, preparando anche la relativa
+documentazione.
+(Purtroppo Fred non @`e pi@`u tra noi, e questo ambiente non @`e pi@`u supportato.)
+
+@item
+@cindex Deifik, Scott
+Scott Deifik
+si @`e occupato della manutenzione per MS-DOS usando il compilatore DJGPP.
+
+@item
+@cindex Zaretskii, Eli
+Eli Zaretskii
+si occupa della manutenzione della versione per MS-Windows, nell'ambiente
+MinGW.
+
+@item
+@cindex Grigera, Juan
+Juan Grigera
+@`e autore di una versione di @command{gawk} per sistemi Windows32.
+(Questa versione non @`e pi@`u supportata.)
+
+@item
+@cindex Hankerson, Darrel
+Per molti anni, il
+Dr.@: Darrel Hankerson
+ha fatto da coordinatore per le varie versioni che giravano su diverse
+piattaforme PC e ha creato distribuzioni binarie per vari sistemi operativi
+che girano sui PC.
+Il suo aiuto @`e stato importante per mantenere aggiornata la documentazione
+per le diverse piattaforme PC.
+
+@item
+@cindex Zoulas, Christos
+Christos Zoulas
+ha scritto la funzione predefinita @code{extension()} per aggiungere
+dinamicamente nuove funzioni.
+(Questa funzionalit@`a @`e divenuta obsoleta a partire da @command{gawk} 4.1.)
+
+@item
+@cindex Kahrs, J@"urgen
+J@"urgen Kahrs
+ha scritto la prima versione del codice per interagire con la rete
+TCP/IP, con la relativa documentazione, e fornito le ragioni per l'aggiunta
+dell'operatore @samp{|&}.
+
+@item
+@cindex Davies, Stephen
+Stephen Davies
+ha portato per la prima volta il programma all'ambiente Tandem, preparando
+anche la relativa documentazione.
+(Tuttavia, questa versione non @`e pi@`u supportata.)
+Stephen @`e anche stato determinante nel lavoro iniziale per integrare il codice
+interno di gestione dei byte nel
+complesso del codice di @command{gawk}.
+
+@item
+@cindex Woehlke, Matthew
+Matthew Woehlke
+ha migliorato l'aderenza allo standard POSIX nei sistemi Tandem che
+implementano lo standard.
+
+@item
+@cindex Brown, Martin
+Martin Brown
+ha portato il programma all'ambiente BeOS, preparando anche la relativa
+documentazione.
+(L'ambiente BeOS non @`e pi@`u supportato.)
+
+@item
+@cindex Peters, Arno
+Arno Peters
+ha fatto il lavoro iniziale necessario per consentire alla configurazione
+di @command{gawk} di usare GNU Automake e GNU @command{gettext}.
+
+@item
+@cindex Broder, Alan J.@:
+Alan J.@: Broder
+ha scritto la prima versione della funzione @code{asort()} e anche
+il codice per gestire il terzo argomento opzionale della funzione
+@code{match()}.
+
+@item
+@cindex Buening, Andreas
+Andreas Buening
+ha aggiornato la versione di @command{gawk} per OS/2.
+
+@item
+@cindex Hasegawa, Isamu
+Isamu Hasegawa,
+dell'IBM in Giappone, ha contribuito con il supporto per i caratteri multibyte.
+
+@item
+@cindex Benzinger, Michael
+Michael Benzinger ha sviluppato il codice iniziale per l'istruzione
+@code{switch}.
+
+@item
+@cindex McPhee, Patrick
+Patrick T.J.@: McPhee ha sviluppato il codice per il caricamento
+dinamico negli ambienti Windows32.
+(Questa funzionalit@`a non @`e pi@`u supportata.)
+
+@item
+@cindex Wallin, Anders
+Anders Wallin ha aiutato a continuare il supporto della versione VMS
+di @command{gawk} per parecchi anni.
+
+@item
+@cindex Gordon, Assaf
+Assaf Gordon ha scritto il codice per implementare
+l'opzione @option{--sandbox}.
+
+@item
+@cindex Haque, John
+John Haque @`e autore dei seguenti contributi:
+
+@itemize @value{MINUS}
+@item
+Le modifiche per convertire @command{gawk}
+in un interprete di codice a livello di byte, compreso il debugger
+
+@item
+L'aggiunta di veri vettori di vettori
+
+@item
+Le modifiche ulteriori per il supporto del calcolo a precisione
+arbitraria
+
+@item
+Il testo iniziale di
+@ref{Calcolo con precisione arbitraria}
+
+@item
+Il lavoro per unificare le tre varianti del programma @command{gawk},
+in vista della versione 4.1
+
+@item
+I miglioramenti alla gestione interna dei vettori per i vettori i cui
+indici sono dei numeri interi
+
+@item
+A John, insieme a Pat Rankin, si devono i miglioramenti alla funzionalit@`a
+di ordinamento dei vettori.
+@end itemize
+
+@cindex Papadopoulos, Panos
+@item
+Panos Papadopoulos ha scritto il testo originale per
+@ref{Includere file}.
+
+@item
+@cindex Yawitz, Efraim
+Efraim Yawitz ha scritto il testo originale per il @ref{Debugger}.
+
+@item
+@cindex Schorr, Andrew
+Lo sviluppo dell'estensione API rilasciata per la prima volta con
+@command{gawk} 4.1 @`e stata principalmente guidata da
+Arnold Robbins e Andrew Schorr, con notevoli contributi dal
+resto del team di sviluppo.
+
+@cindex Malmberg, John E.
+@item
+John Malmberg ha apportato miglioramenti significativi alla versione
+OpenVMS e alla relativa documentazione.
+
+@item
+@cindex Colombo, Antonio
+Antonio Giovanni Colombo ha riscritto diversi esempi, che non erano pi@`u
+attuali, contenuti nei primi capitoli, e gliene sono estremamente grato.
+
+@item
+@cindex Robbins, Arnold
+Arnold Robbins
+ha lavorato su @command{gawk} dal 1988, dapprima
+aiutando David Trueman e in seguito, dal 1994 circa, come
+manutentore principale.
+@end itemize
+
+@node Sommario della storia
+@appendixsec Sommario
+
+@itemize @value{BULLET}
+@item
+Il linguaggio @command{awk} si @`e evoluto col passare degli anni. La prima
+versione risale a Unix V7, circa 1978. Nel 1987, per la versione Unix
+System V Release 3.1, sono state fatte al linguaggio delle modifiche
+importanti, inclusa la possibilit@`a di avere funzioni definite dall'utente.
+Ulteriori modifiche sono state fatte per la versione System V Release 4, nel
+1989.
+Dopo di allora, sono state apportate ulteriori modifiche minori,
+per implementare lo standard POSIX.
+
+@item
+L'@command{awk} di Brian Kernighan prevede un piccolo numero di estensioni
+implementate di comune accordo con altre versioni di @command{awk}.
+
+@item
+@command{gawk} prevede un elevato numero di estensioni rispetto
+a POSIX @command{awk}.
+Queste estensioni possono essere disabilitate specificando l'opzione
+@option{--traditional} o @option{--posix}.
+
+@item
+L'interazione tra localizzazioni POSIX e individuazione di @dfn{regexp}
+in @command{gawk} @`e stata causa di malintesi nel corso degli anni. Oggi
+@command{gawk} implementa l'Interpretazione Razionale degli Intervalli
+(@dfn{Rational Range Interpretation}), dove
+intervalli nella forma @samp{[a-z]} individuano @emph{solo} i caratteri
+numericamente compresi tra
+@samp{a} e @samp{z} nella rappresentazione nativa dei caratteri in quella
+particolare macchina. Normalmente quella in uso @`e quella ASCII,
+ma pu@`o essere EBCDIC sui sistemi IBM S/390.
+
+@item
+Molte persone hanno contribuito allo sviluppo di @command{gawk} nel corso
+degli anni. Spero che l'elenco fornito in questo @value{CHAPTER} sia
+esauriente e attribuisca il giusto riconoscimento quando questo @`e dovuto.
+
+@end itemize
+
+@node Installazione
+@appendix Installare @command{gawk}
+
+@c last two commas are part of see also
+@cindex sistemi operativi, si veda anche GNU/Linux@comma{} sistemi operativi per PC@comma{} Unix
+@cindex @command{gawk}, installare
+@cindex installare @command{gawk}
+Quest'appendice contiene istruzioni per installare @command{gawk} sulle
+varie piattaforme supportate dagli sviluppatori. Lo sviluppatore
+principale supporta GNU/Linux (e Unix), mentre le altre piattaforme sono
+sono curate da altri sviluppatori.
+@xref{Bug}
+per gli indirizzi di posta elettronica di chi effettua la manutenzione
+della versione specifica di una particolare piattaforma.
+
+@menu
+* Distribuzione di Gawk:: Contenuto della distribuzione di @command{gawk}.
+* Installazione Unix:: Installare @command{gawk} su varie versioni
+ di Unix.
+* Installazione non-Unix:: Installazioni su altri Sistemi Operativi.
+* Bug:: Notificare problemi e bug.
+* Altre versioni:: Altre implementazioni di @command{awk}
+ liberamente disponibili.
+* Sommario dell'installazione:: Sommario dell'installazione.
+@end menu
+
+@node Distribuzione di Gawk
+@appendixsec La distribuzione di @command{gawk}
+@cindex codice sorgente di @command{gawk}
+@cindex sorgente, codice, @command{gawk}
+
+Questa @value{SECTION} spiega come ottenere la distribuzione
+di @command{gawk}, come scompattarla, e cosa @`e contenuto nei vari file
+e nelle sottodirectory risultanti.
+
+@menu
+* Scaricare:: Come ottenere la distribuzione.
+* Scompattazione:: Come estrarre la distribuzione.
+* Contenuti della distribuzione:: Cosa c'@`e nella distribuzione.
+@end menu
+
+@node Scaricare
+@appendixsubsec Ottenere la distribuzione di @command{gawk}
+@cindex @command{gawk}, codice sorgente@comma{} ottenere il
+@cindex codice sorgente di @command{gawk}, ottenere il
+Ci sono due modi per ottenere del software GNU:
+
+@itemize @value{BULLET}
+@item
+Copiarlo da qualcuno che ce l'abbia gi@`a.
+
+@cindex FSF (Free Software Foundation)
+@cindex Free Software Foundation (FSF)
+@item
+Ottenere @command{gawk}
+dal sito Internet
+@code{ftp.gnu.org}, nella directory @file{/gnu/gawk}.
+@`E possibile accedere al sito sia via @command{ftp} anonimo che via @code{http}.
+Se si dispone del programma @command{wget}, si pu@`o utilizzarlo digitando un
+comando simile a questo:
+
+@example
+wget http://ftp.gnu.org/gnu/gawk/gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz
+@end example
+@end itemize
+
+L'archivio che contiene il software GNU @`e disponibile in vari cloni
+(@dfn{mirror}) in tutto il mondo.
+La lista aggiornata dei siti clone @`e disponibile nel
+@uref{http://www.gnu.org/order/ftp.html, sito web principale della FSF}.
+Si tenti di usare uno dei siti-clone; dovrebbero essere meno trafficati, ed @`e
+possibile che ce ne sia uno pi@`u vicino.
+
+Si pu@`o anche scaricare la distribuzione del sorgente di @command{gawk}
+dal deposito Git ufficiale; per maggiori informazioni, si veda
+@ref{Accedere ai sorgenti}.
+
+@node Scompattazione
+@appendixsubsec Scompattare la distribuzione
+@command{gawk} @`e distribuito sotto forma di parecchi file @code{tar}
+compressi con differenti programmi di compressione: @command{gzip},
+@command{bzip2}
+e @command{xz}. Per amor di semplicit@`a, il resto di queste istruzioni
+presuppone che si stia usando quella compressa col programma GNU Gzip
+(@command{gzip}).
+
+Una volta che si ha a disposizione la distribuzione (p.es.,
+@file{gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz}),
+va usato @code{gzip} per scompattare il file e quindi @code{tar} per estrarne i
+file. Si pu@`o usare la seguente @dfn{pipe} per produrre la distribuzione
+@command{gawk}:
+
+@example
+gzip -d -c gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz | tar -xvpf -
+@end example
+
+In un sistema che abbia la versione GNU di @command{tar}, si
+pu@`o far effettuare la scompattazione direttamente a @command{tar}:
+
+@example
+tar -xvpzf gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz
+@end example
+
+@noindent
+L'estrazione dei file dall'archivio
+crea una directory di nome @file{gawk-@value{VERSION}.@value{PATCHLEVEL}}
+nella directory corrente.
+
+Il @value{FN} della distribuzione @`e nella forma
+@file{gawk-@var{V}.@var{R}.@var{P}.tar.gz}.
+La @var{V} rappresenta la versione maggiore di @command{gawk},
+la @var{R} rappresenta il rilascio corrente della versione @var{V}, e
+la @var{P} rappresenta un @dfn{patch level}, che sta a indicare che
+correzioni a errori minori sono state incluse nel rilascio.
+Il @dfn{patch level} corrente @`e @value{PATCHLEVEL}, ma quando ci si procura
+una distribuzione, andr@`a ottenuta quella con il livello pi@`u alto di
+versione, rilascio e @dfn{patch}.
+(Si noti, comunque, che livelli di @dfn{patch} maggiori o uguali a 70
+denotano versioni ``beta'', ossia versioni non destinate a essere usate
+in produzione; non si dovrebbero utilizzare tali versioni, se non si @`e
+disposti a sperimentare.)
+Se non si sta usando un sistema Unix o GNU/Linux, i modi per ottenere
+e scompattare la distribuzione di @command{gawk} sono differenti.
+Si dovrebbe sentire un esperto di quel sistema.
+
+@node Contenuti della distribuzione
+@appendixsubsec Contenuti della distribuzione @command{gawk}
+@cindex @command{gawk}, distribuzione di
+@cindex distribuzione di @command{gawk}
+
+La distribuzione di @command{gawk} contiene un certo numero di file
+sorgente in C, di file di documentazione, di sottodirectory, e di file
+utilizzati durante il processo di configurazione
+(@pxref{Installazione Unix}),
+come pure parecchie sottodirectory relative a diversi sistemi operativi
+non-Unix:
+
+@table @asis
+@item Vari file @samp{.c}, @samp{.y} e @samp{.h}
+Questi file contengono il codice sorgente vero e proprio di @command{gawk}.
+@end table
+
+@table @file
+@item support/*
+Intestazioni C e file sorgente per routine che @command{gawk}
+usa, ma che non sono parte della sua funzionalit@`a
+fondamentale. Per esempio, analisi di argomenti, controlli
+di corrispondenze di espressioni regolari, e routine per
+generare numeri casuali sono tutti mantenuti qui.
+
+@item ABOUT-NLS
+Un file contenente informazioni sul comando GNU @command{gettext} e
+sulle traduzioni.
+
+@item AUTHORS
+Un file con alcune informazioni su chi ha scritto @command{gawk}.
+Esiste solo per placare i pedanti della Free Software Foundation.
+
+@item README
+@itemx README_d/README.*
+File descrittivi: vari @file{README} ("leggimi") per @command{gawk} sotto Unix e per
+tutte le varie altre combinazioni hardware e software.
+
+@item INSTALL
+Un file che fornisce una panoramica sul processo di configurazione e installazione.
+
+@item ChangeLog
+Una lista dettagliata delle modifiche apportate al codice sorgente,
+ai problemi risolti e ai miglioramenti introdotti.
+
+@item ChangeLog.0
+Una lista meno recente di modifiche al codice sorgente.
+
+@item NEWS
+Una lista di modifiche a @command{gawk} a partire dall'ultimo rilascio
+o @dfn{patch}.
+
+@item NEWS.0
+Una lista meno recente di modifiche a @command{gawk}.
+
+@item COPYING
+La @dfn{GNU General Public License}.
+
+@item POSIX.STD
+Una descrizione di comportamenti nello standard POSIX per @command{awk} che
+sono lasciati indefiniti, o ai quali @command{gawk} non pu@`o conformarsi
+pienamente, come pure una lista di specifiche che lo standard POSIX dovrebbe
+contenere, ma che non sono presenti.
+
+@cindex intelligenza artificiale, @command{gawk} e
+@cindex @command{gawk} e l'intelligenza artificiale
+@item doc/awkforai.txt
+Puntatori alla bozza originale di un breve articolo
+che spiega perch@'e @command{gawk} @`e un linguaggio adatto alla
+programmazione nel campo dell'intelligenza artificiale (AI).
+
+@item doc/bc_notes
+Una breve descrizione della struttura interna a livello di byte di
+@command{gawk} [``byte code''].
+
+@item doc/README.card
+@itemx doc/ad.block
+@itemx doc/awkcard.in
+@itemx doc/cardfonts
+@itemx doc/colors
+@itemx doc/macros
+@itemx doc/no.colors
+@itemx doc/setter.outline
+Il sorgente @command{troff} per una scheda di riferimento a cinque colori
+di @command{awk}.
+Per ottenere la versione a colori @`e richiesta una versione recente di
+@command{troff}, come la versione GNU di @command{troff} (@command{groff}).
+Si veda il file @file{README.card} per istruzioni su come comportarsi se @`e
+disponibile solo una versione pi@`u vecchia di @command{troff}.
+
+@item doc/gawk.1
+Il sorgente @command{troff} di una pagina di manuale [@dfn{man}]
+che descrive @command{gawk}.
+Questa pagina @`e distribuita a beneficio degli utenti Unix.
+
+@cindex Texinfo
+@item doc/gawktexi.in
+@itemx doc/sidebar.awk
+Il file sorgente Texinfo di questo @value{DOCUMENT}.
+Dovrebbe venire elaborato da @file{doc/sidebar.awk}
+prima di essere elaborato con @command{texi2dvi} o @command{texi2pdf}
+per produrre un documento stampato, o
+con @command{makeinfo} per produrre un file Info o HTML.
+Il @file{Makefile} si occupa di questa elaborazione e produce
+la versione stampabile tramite i comandi
+@command{texi2dvi} o @command{texi2pdf}.
+
+@item doc/gawk.texi
+Il file prodotto elaborando @file{gawktexi.in}
+tramite @file{sidebar.awk}.
+
+@item doc/gawk.info
+Il file Info generato per questo @value{DOCUMENT}.
+
+@item doc/gawkinet.texi
+Il file sorgente Texinfo per
+@ifinfo
+@inforef{Top, , Introduzione generale, gawkinet, @value{GAWKINETTITLE}}.
+@end ifinfo
+@ifnotinfo
+@cite{@value{GAWKINETTITLE}}.
+@end ifnotinfo
+Dovrebbe venire elaborato con @TeX{}
+(tramite @command{texi2dvi} o @command{texi2pdf})
+per produrre un documento stampato o
+con @command{makeinfo} per produrre un file Info o HTML.
+
+@item doc/gawkinet.info
+Il file Info generato per
+@cite{@value{GAWKINETTITLE}}.
+
+@item doc/igawk.1
+Il sorgente @command{troff} per una pagina di manuale relativa al
+programma @command{igawk} descritto
+@ifnottex
+in
+@end ifnottex
+@iftex
+nella
+@end iftex
+@ref{Programma igawk}.
+(Poich@'e @command{gawk} prevede ora internamente l'uso della direttiva
+@code{@@include},
+n@'e @command{igawk} n@'e @file{igawk.1} sono effettivamente installati.)
+
+@item doc/Makefile.in
+Il file in input usato durante la procedura di configurazione per
+generare l'effettivo @file{Makefile} da usare per creare la documentazione.
+
+@item Makefile.am
+@itemx */Makefile.am
+File usati dal software GNU Automake per generare
+il file @file{Makefile.in} usato da Autoconf e dallo script
+@command{configure}.
+
+@item Makefile.in
+@itemx aclocal.m4
+@itemx bisonfix.awk
+@itemx config.guess
+@itemx configh.in
+@itemx configure.ac
+@itemx configure
+@itemx custom.h
+@itemx depcomp
+@itemx install-sh
+@itemx missing_d/*
+@itemx mkinstalldirs
+@itemx m4/*
+Questi file e sottodirectory sono usati per configurare e compilare
+@command{gawk} per vari sistemi Unix. L'uso di molti tra questi file @`e spiegato
+@iftex
+nella
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Installazione Unix}. I rimanenti hanno una funzione di supporto
+per l'infrastruttura.
+
+@item po/*
+La directory @file{po} contiene la traduzione in varie lingue
+dei messaggi emessi da @command{gawk}.
+
+@item awklib/extract.awk
+@itemx awklib/Makefile.am
+@itemx awklib/Makefile.in
+@itemx awklib/eg/*
+La directory @file{awklib} contiene una copia di @file{extract.awk}
+(@pxref{Programma extract}),
+che pu@`o essere usato per estrarre i programmi di esempio dal file sorgente
+Texinfo di questo @value{DOCUMENT}. Contiene anche un file
+@file{Makefile.in}, che
+@command{configure} usa per generare un @file{Makefile}.
+@file{Makefile.am} @`e usato da GNU Automake per creare @file{Makefile.in}.
+Le funzioni di libreria descritte
+@iftex
+nel
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Funzioni di libreria},
+sono incluse come file pronti per l'uso nella distribuzione @command{gawk}.
+Essi sono installati come parte della procedura di installazione.
+I rimanenti programmi contenuti in questo @value{DOCUMENT} sono disponibili
+nelle appropriate sottodirectory di @file{awklib/eg}.
+
+@item extension/*
+Il codice sorgente, le pagine di manuale, e i file di infrastruttura per
+gli esempi di estensione incluse con @command{gawk}.
+@xref{Estensioni dinamiche}, per ulteriori dettagli.
+
+@item extras/*
+Ulteriori file, non-essenziali. Al momento, questa directory contiene
+alcuni file da eseguire al momento di iniziare una sessione,
+da installare nella directory @file{/etc/profile.d}
+per essere di aiuto nella gestione delle variabili di ambiente
+@env{AWKPATH} e @env{AWKLIBPATH}.
+@xref{File da usare a inizio sessione}, per ulteriori informazioni.
+
+@item posix/*
+File necessari per compilare @command{gawk} su sistemi conformi allo
+standard POSIX.
+
+@item pc/*
+File necessari per compilare @command{gawk} sotto MS-Windows
+(@pxref{Installazione su PC} per i dettagli).
+
+@item vms/*
+File necessari per compilare @command{gawk} sotto Vax/VMS e OpenVMS
+(@pxref{Installazione su VMS} per i dettagli).
+
+@item test/*
+Una serie di test per
+@command{gawk}. Si pu@`o usare @samp{make check} dalla directory principale
+di @command{gawk} per provare se la serie di test funziona con la
+versione in uso di @command{gawk}.
+Se @command{gawk} supera senza errori @samp{make check}, si pu@`o essere
+sicuri che sia stato installato e configurato correttamente su un dato
+sistema.
+@end table
+
+@node Installazione Unix
+@appendixsec Compilare e installare @command{gawk} su sistemi di tipo Unix
+
+Normalmente, si pu@`o compilare e installare @command{gawk} immettendo
+solo un paio di comandi. Comunque, se si ci si trova in un sistema
+insolito, pu@`o essere necessario
+dover configurare @command{gawk} per quel dato sistema.
+
+@menu
+* Installazione veloce:: Compilare @command{gawk} sotto Unix.
+* File da usare a inizio sessione:: Funzioni di personalizzazione della
+ shell.
+* Ulteriori opzioni di configurazione:: Altre opzioni utilizzabili in fase di
+ compilazione.
+* Filosofia della configurazione:: Come si suppone che tutto funzioni.
+@end menu
+
+@node Installazione veloce
+@appendixsubsec Compilare @command{gawk} per sistemi di tipo Unix
+
+Questi normali passi di installazione dovrebbero essere sufficienti in
+tutti i moderni sistemi in commercio derivati da Unix, ossia
+GNU/Linux, sistemi basati su BSD, e l'ambiente Cygwin sotto MS-Windows.
+
+Dopo aver estratto la distribuzione di @command{gawk}, posizionarsi con
+@command{cd} nella directory
+@file{gawk-@value{VERSION}.@value{PATCHLEVEL}}. Come per la maggior parte dei
+programmi GNU, occorre configurare @command{gawk} per il sistema in uso,
+eseguendo il programma @command{configure}. Questo programma @`e
+uno script della shell Bourne, che @`e stato generato automaticamente
+usando il comando GNU Autoconf.
+@ifnotinfo
+(Il software Autoconf @`e
+descritto in dettaglio in
+@cite{Autoconf---Generating Automatic Configuration Scripts},
+che pu@`o essere trovato in rete sul sito
+@uref{http://www.gnu.org/software/autoconf/manual/index.html,
+della Free Software Foundation}.)
+@end ifnotinfo
+@ifinfo
+(Il software Autoconf @`e descritto in dettaglio a partire da
+@inforef{Top, , Autoconf, autoconf,Autoconf---Generating Automatic Configuration Scripts}.)
+@end ifinfo
+
+Per configurare @command{gawk} basta eseguire @command{configure}:
+
+@example
+sh ./configure
+@end example
+
+Questo produce i file @file{Makefile} e @file{config.h} adatti al sistema
+in uso.
+Il file @file{config.h} descrive varie situazioni relative al sistema in uso.
+@`E possibile modificare il @file{Makefile} per
+cambiare la variabile @code{CFLAGS}, che controlla
+le opzioni di riga di comando da passare al compilatore C (come i livelli
+di ottimizzazione o la richiesta di generare informazioni per il @dfn{debug}).
+
+In alternativa, si possono specificare dei valori a piacere per
+molte delle variabili di @command{make} sulla riga di comando,
+come @code{CC} e @code{CFLAGS}, quando
+ si chiama il programma
+@command{configure}:
+
+@example
+CC=cc CFLAGS=-g sh ./configure
+@end example
+
+@noindent
+Si veda il file @file{INSTALL} nella distribuzione di @command{gawk} per
+tutti i dettagli.
+
+Dopo aver eseguito @command{configure} ed eventualmente modificato
+@file{Makefile},
+va dato il comando:
+
+@example
+make
+@end example
+
+@noindent
+Poco dopo, si dovrebbe avere a disposizione una versione eseguibile
+di @command{gawk}.
+Questo @`e tutto!
+Per verificare se @command{gawk} funziona correttamente,
+va dato il comando @samp{make check}. Tutti i test dovrebbero terminare con
+successo.
+Se questi passi non producono il risultato desiderato, o se qualche
+test fallisce, controllare i file nella directory @file{README_d}
+per determinare se quello che @`e capitato @`e un problema noto.
+Se il problema capitato non @`e descritto l@`{@dotless{i}},
+inviare una segnalazione di @dfn{bug} (@pxref{Bug}).
+
+Naturalmente, dopo aver compilato @command{gawk}, verosimilmente
+andr@`a installato. Per fare ci@`o, occorre eseguire il comando
+@samp{make install}, disponendo delle autorizzazioni necessarie.
+Come acquisirle varia da sistema a sistema, ma su molti sistemi si pu@`o
+usare il comando @command{sudo} per ottenerle. Il comando da immettere
+diventa in questo caso @samp{sudo make install}. @`E probabile che sia
+necessario fornire una password, ed essere stati messi nella lista degli
+utenti che possono utilizzare il comando @command{sudo}.
+
+@node File da usare a inizio sessione
+@appendixsubsec File di inizializzazione della shell
+
+La distribuzione contiene i file da usare a inizio sessione
+@file{gawk.sh} e
+@file{gawk.csh}, che contengono funzioni che possono essere di aiuto
+nel gestire le variabili di ambiente
+@env{AWKPATH} e @env{AWKLIBPATH}.
+Su un sistema Fedora GNU/Linux, questi file dovrebbero essere installati
+nella directory @file{/etc/profile.d};
+su altre piattaforme, la posizione corretta pu@`o essere differente.
+
+@table @command
+
+@cindex @command{gawkpath_default}, funzione della shell
+@cindex funzione della shell @command{gawkpath_default}
+@item gawkpath_default
+Ripristina la variabile d'ambiente @env{AWKPATH} al suo valore di default.
+
+@cindex @command{gawkpath_prepend}, funzione della shell
+@cindex funzione della shell @command{gawkpath_prepend}
+@item gawkpath_prepend
+Aggiunge l'argomento all'inizio della variabile d'ambiente @env{AWKPATH}.
+
+@cindex @command{gawkpath_append}, funzione della shell
+@cindex funzione della shell @command{gawkpath_append}
+@item gawkpath_append
+Aggiunge l'argomento alla fine della variabile d'ambiente @env{AWKPATH}.
+
+@cindex @command{gawklibpath_default}, funzione della shell
+@cindex funzione della shell @command{gawklibpath_default}
+@item gawklibpath_default
+Reimposta la variabile d'ambiente @env{AWKLIBPATH} al suo valore di default.
+
+@cindex @command{gawklibpath_prepend}, funzione della shell
+@cindex funzione della shell @command{gawklibpath_prepend}
+@item gawklibpath_prepend
+Aggiunge l'argomento all'inizio della variabile d'ambiente
+@env{AWKLIBPATH}.
+
+@cindex @command{gawklibpath_append}, funzione della shell
+@cindex funzione della shell @command{gawklibpath_append}
+@item gawklibpath_append
+Aggiunge l'argomento alla fine della variabile d'ambiente
+@env{AWKLIBPATH}.
+
+@end table
+
+
+@node Ulteriori opzioni di configurazione
+@appendixsubsec Ulteriori opzioni di configurazione
+@cindex @command{gawk}, configurazione, opzioni di
+@cindex configurazione di @command{gawk}, opzioni di
+
+Ci sono parecchie altre opzioni che si possono utilizzare sulla riga
+di comando di @command{configure}
+quando si compila @command{gawk} a partire dai sorgenti, tra cui:
+
+@table @code
+
+@cindex @option{--disable-extensions}, opzione di configurazione
+@cindex opzione di configurazione @code{--disable-extensions}
+@item --disable-extensions
+Richiede di non configurare e generare le estensioni di esempio nella
+directory @file{extension}. Questo @`e utile quando si genera
+@command{gawk} per essere eseguito su un'altra piattaforma.
+L'azione di default @`e di controllare dinamicamente se le estensioni
+possono essere configurate e compilate.
+
+@cindex @option{--disable-lint}, opzione di configurazione
+@cindex opzione di configurazione @code{--disable-lint}
+@item --disable-lint
+Disabilita i controlli @dfn{lint} all'interno di @command{gawk}. Le opzioni
+@option{--lint} e @option{--lint-old}
+(@pxref{Opzioni})
+sono accettate, ma non fanno nulla, e non emettono alcun messaggio di
+avvertimento.
+Analogamente, se si imposta la variabile @code{LINT}
+(@pxref{Variabili modificabili dall'utente})
+questa non ha alcun effetto sul programma @command{awk} in esecuzione.
+
+Se si specifica l'opzione del compilatore GNU Compiler Collection (GCC) che
+elimina il codice non eseguito, quest'opzione riduce di quasi
+23K byte la dimensione del programma eseguibile @command{gawk}
+su sistemi GNU/Linux x86_64. I risultati su altri sistemi e con
+altri compilatori sono probabilmente diversi.
+L'uso di questa opzione pu@`o apportare qualche piccolo miglioramento nei
+tempi di esecuzione di un programma.
+
+@quotation ATTENZIONE
+Se si usa quest'opzione alcuni dei test di funzionalit@`a non avranno successo.
+Quest'opzione potr@`a essere rimossa in futuro.
+@end quotation
+
+@cindex @option{--disable-nls}, opzione di configurazione
+@cindex opzione di configurazione @code{--disable-nls}
+@item --disable-nls
+Non attiva la traduzione automatica dei messaggi.
+Ci@`o normalmente non @`e consigliabile, ma pu@`o apportare qualche lieve
+miglioramento nei tempi di esecuzione di un programma.
+
+@cindex @option{--with-whiny-user-strftime}, opzione di configurazione
+@cindex opzione di configurazione @code{--with-whiny-user-strftime}
+@item --with-whiny-user-strftime
+Forza l'uso della versione della funzione C @code{strftime()} inclusa nella
+distribuzione di @command{gawk}, per i sistemi in cui la funzione stessa
+non sia disponibile.
+@end table
+
+Si usi il comando @samp{./configure --help} per ottenere la lista completa
+delle opzioni disponibili in @command{configure}.
+
+@node Filosofia della configurazione
+@appendixsubsec Il processo di configurazione
+
+@cindex @command{gawk}, configurazione di
+@cindex configurazione di @command{gawk}
+Questa @value{SECTION} interessa solo a chi abbia un minimo di familiarit@`a con
+il linguaggio C e con i sistemi operativi di tipo Unix.
+
+Il codice sorgente di @command{gawk}, in generale, cerca di aderire, nei limiti
+del possibile, a degli standard formali. Ci@`o significa che @command{gawk} usa
+routine di libreria che sono specificate nello standard ISO C e nello standard
+POSIX per le interfacce dei sistemi operativi. Il codice sorgente di
+@command{gawk} richiede l'uso di un compilatore ISO C (standard 1990).
+
+Molti sistemi Unix non aderiscono completamente n@'e allo standard ISO n@'e a
+quello POSIX. La sottodirectory @file{missing_d} nella distribuzione di
+@command{gawk} contiene delle versioni sostitutive per quelle funzioni che pi@`u
+frequentemente risultano essere non disponibili.
+
+Il file @file{config.h} creato da @command{configure} contiene definizioni che
+elencano funzionalit@`a del particolare sistema operativo nel quale si tenta di
+compilare @command{gawk}. Le tre cose descritte da questo file sono: quali
+file di intestazione sono disponibili, in modo da poterli includere correttamente,
+quali funzioni (presumibilmente) standard sono realmente disponibili nelle
+librerie C, e varie informazioni assortite riguardo al sistema operativo
+corrente. Per esempio, pu@`o non esserci l'elemento @code{st_blksize} nella
+struttura @code{stat}. In questo caso, @samp{HAVE_STRUCT_STAT_ST_BLKSIZE} @`e
+indefinito.
+
+@cindex @code{custom.h}, file
+@`E possible che il compilatore C del sistema in uso "tragga in inganno"
+@command{configure}. Pu@`o succedere nel caso in cui non viene restituito
+un errore se una funzione di libreria non @`e disponibile. Per superare questo
+problema, si pu@`o modificare il file @file{custom.h}. Basta usare una direttiva
+@samp{#ifdef} appropriata per il sistema corrente, e definire, tramite
+@code{#define}, tutte le costanti che @command{configure} avrebbe dovuto
+definire, ma non @`e riuscito a farlo, oppure, usando @code{#undef} annullare le
+costanti che @command{configure} ha definito, ma non avrebbe dovuto farlo. Il
+file @file{custom.h} @`e automaticamente incluso dal file @file{config.h}.
+
+@`E anche possibile che il programma @command{configure} generato da Autoconf non
+funzioni in un dato sistema per una ragione differente. Se c'@`e un problema, si
+tenga presente che il file @file{configure.ac} @`e quello preso in input da
+Autoconf. @`E possibile modificare questo file e generare una nuova versione di
+@command{configure} che funzioni sul sistema corrente (@pxref{Bug} per
+informazioni su come segnalare problemi nella configurazione di
+@command{gawk}). Lo stesso meccanismo si pu@`o usare per inviare aggiornamenti
+al file @file{configure.ac} e/o a @file{custom.h}.
+
+@node Installazione non-Unix
+@appendixsec Installazione su altri Sistemi Operativi
+
+Questa @value{SECTION} descrive come installare @command{gawk} su
+vari sistemi non-Unix.
+
+@menu
+* Installazione su PC:: Installare e compilare @command{gawk}
+ su Microsoft Windows.
+* Installazione su VMS:: Installare @command{gawk} su VMS.
+@end menu
+
+@node Installazione su PC
+@appendixsubsec Installazione su MS-Windows
+
+@cindex PC, @command{gawk} su sistemi operativi
+@cindex sistemi operativi per PC, @command{gawk} su
+@cindex installare @command{gawk} su sistemi operativi per PC
+Questa @value{SECTION} tratta dell'installazione e uso di @command{gawk}
+su macchine con architettura Intel che eseguono qualsiasi versione di
+MS-Windows.
+In questa @value{SECTION}, il termine ``Windows32''
+si riferisce a una qualsiasi versione di Microsoft Windows
+95/98/ME/NT/2000/XP/Vista/7/8/10.
+
+Si veda anche il file @file{README_d/README.pc} nella distribuzione.
+
+@menu
+* Installazione binaria su PC:: Installare una distribuzione pronta
+ all'uso.
+* Compilazione su PC:: Compilare @command{gawk} per Windows32.
+* Uso su PC:: Eseguire @command{gawk} su Windows32.
+* Cygwin:: Compilare ed eseguire @command{gawk}
+ per Cygwin.
+* MSYS:: Usare @command{gawk} nell'ambiente MSYS.
+@end menu
+
+@node Installazione binaria su PC
+@appendixsubsubsec Installare una distribuzione predisposta per sistemi MS-Windows
+
+La sola distribuzione binaria predisposta supportata per i sistem MS-Windows
+@`e quella messa a disposizione da Eli Zaretskii
+@uref{https://sourceforge.net/projects/ezwinports/, progetto ``ezwinports''}.
+Si parta da l@`{@dotless{i}} per installare il comando @command{gawk} precompilato.
+
+@node Compilazione su PC
+@appendixsubsubsec Compilare @command{gawk} per sistemi operativi di PC
+
+@command{gawk} pu@`o essere compilato per Windows32, usando MinGW
+(per Windows32).
+Il file @file{README_d/README.pc} nella distribuzione @command{gawk}
+contiene ulteriori annotazioni, e il file @file{pc/Makefile} contiene
+informazioni importanti sulle opzioni di compilazione.
+
+@cindex compilare @command{gawk} per MS-Windows
+Per compilare @command{gawk} per Windows32, occorre copiare i file
+dalla directory @file{pc} (@emph{tranne} il file @file{ChangeLog}) alla
+directory che contiene il resto dei sorgenti di @command{gawk}, e quindi
+chiamare @command{make}, specificando il nome appropriato di obiettivo come
+argomento, per generare @command{gawk}. Il @file{Makefile} copiato dalla
+directory @file{pc} contiene una sezione di configurazione con commenti, e pu@`o
+essere necessario modificarlo perch@'e funzioni con il programma di utilit@`a
+@command{make} corrente.
+
+Il @file{Makefile} contiene un certo numero di alternative, che permettono di
+generare @command{gawk} per diverse
+versioni MS-DOS e Windows32. Se il comando @command{make} @`e richiamato senza
+specificare alcun argomento viene stampata una lista delle alternative
+disponibili. Per esempio,
+per generare un codice binario di @command{gawk} nativo per MS-Windows
+usando gli strumenti MinGW, scrivere @samp{make mingw32}.
+
+@node Uso su PC
+@appendixsubsubsec Usare @command{gawk} su sistemi operativi PC
+@cindex PC, @command{gawk} su sistemi operativi
+@cindex sistemi operativi PC, @command{gawk} su
+
+Sotto MS-Windows, gli ambienti Cygwin e MinGW consentono di usare
+sia l'operatore @samp{|&} che le operazioni su rete TCP/IP
+(@pxref{Reti TCP/IP}).
+
+@cindex percorso di ricerca
+@cindex percorso di ricerca per file sorgente
+@cindex @command{gawk}, versione MS-Windows di
+@cindex @code{;} (punto e virgola), @env{AWKPATH} variabile e
+@cindex punto e virgola (@code{;}), @env{AWKPATH} variabile e
+@cindex @env{AWKPATH}, variabile d'ambiente
+@cindex variabile d'ambiente @env{AWKPATH}
+Le versioni MS-Windows di @command{gawk} ricercano i file di
+programma come descritto in @ref{AWKPATH (Variabile)}. Comunque, gli elementi
+della variabile @env{AWKPATH} sono separati tra di loro da un punto e virgola
+(anzich@'e da due punti (@code{:})).
+Se @env{AWKPATH} @`e non impostata o ha per valore la stringa nulla, il percorso
+di ricerca di default @`e @samp{@w{.;c:/lib/awk;c:/gnu/lib/awk}}.
+
+@cindex estensioni comuni, variabile @code{BINMODE}
+@c @cindex extensions, common@comma{} @code{BINMODE} variable
+@cindex differenze tra @command{awk} e @command{gawk}, variabile @code{BINMODE}
+@cindex @code{BINMODE}, variabile
+@cindex variabile @code{BINMODE}
+Sotto MS-Windows,
+@command{gawk} (come molti altri programmi di trattamento testi) converte
+automaticamente la stringa di fine riga @samp{\r\n} in @samp{\n} leggendo dall'input
+e @samp{\n} in @samp{\r\n} scrivendo sull'output.
+La variabile speciale @code{BINMODE} @value{COMMONEXT} permette di controllare
+come avvengono queste conversioni, ed @`e interpretata come segue:
+
+@itemize @value{BULLET}
+@item
+Se @code{BINMODE} @`e @code{"r"} o uno,
+la modalit@`a binaria @`e impostata
+in lettura (cio@`e, nessuna conversione in lettura).
+
+@item
+Se @code{BINMODE} @`e @code{"w"} o due,
+la modalit@`a binaria @`e impostata
+in scrittura (cio@`e, nessuna conversione in scrittura).
+
+@item
+Se @code{BINMODE} @`e @code{"rw"} o @code{"wr"} o tre,
+la modalit@`a binaria @`e impostata sia in lettura che in scrittura.
+
+@item
+@code{BINMODE=@var{stringa-non-nulla}} equivale a specificare
+@samp{BINMODE=3} (cio@`e, nessuna conversione in
+lettura e scrittura). Tuttavia, @command{gawk} emette un messaggio di
+avviso se la stringa non @`e @code{"rw"} o @code{"wr"}.
+@end itemize
+
+@noindent
+La modalit@`a di trattamento dello standard input e standard output sono
+impostate una volta sola
+(dopo aver letto la riga di comando, ma prima di iniziare a elaborare
+qualsiasi programma @command{awk}).
+L'impostazione di @code{BINMODE} per standard input o
+standard output va fatta usando
+un'appropriata opzione @samp{-v BINMODE=@var{N}} sulla riga di comando.
+@code{BINMODE} @`e impostato nel momento in cui un file o @dfn{pipe} @`e aperto
+e non pu@`o essere cambiato in corso di elaborazione.
+
+Il nome @code{BINMODE} @`e stato scelto in analogia con @command{mawk}
+(@pxref{Altre versioni}).
+@command{mawk} e @command{gawk} gestiscono @code{BINMODE} in maniera simile;
+tuttavia, @command{mawk} prevede un'opzione @samp{-W BINMODE=@var{N}} e una
+variabile d'ambiente che pu@`o impostare @code{BINMODE}, @code{RS}, e @code{ORS}.
+I file @file{binmode[1-3].awk} (nella directory @file{gnu/lib/awk} in alcune
+delle distribuzioni binarie gi@`a predisposte) sono stati inclusi per rendere
+disponibile l'opzione di @command{mawk} @samp{-W BINMODE=@var{N}}. Questi
+possono essere modificati o ignorati; in particolare, quale sia l'impostazione
+di @code{RS} che d@`a meno ``sorprese'' rimane una questione aperta.
+@command{mawk} usa @samp{RS = "\r\n"} se si imposta la modalit@`a binaria in
+lettura, il che @`e appropriato per file che abbiano i caratteri di fine riga in
+stile MS-DOS.
+
+Per chiarire, gli esempi seguenti impostano la modalit@`a binaria in
+scrittura per lo standard output e altri file, e impostano @code{ORS} in modo
+da ottenere la fine riga ``normale'' in stile MS-DOS:
+
+@example
+gawk -v BINMODE=2 -v ORS="\r\n" @dots{}
+@end example
+
+@noindent
+o:
+
+@example
+gawk -v BINMODE=w -f binmode2.awk @dots{}
+@end example
+
+@noindent
+Questi comandi danno lo stesso risultato dell'opzione
+@samp{-W BINMODE=2} in @command{mawk}.
+Quanto segue modifica il separatore di record a @code{"\r\n"} e imposta
+la modalit@`a binaria in lettura, senza modificare le letture da standard input:
+
+@example
+gawk -v RS="\r\n" -e "BEGIN @{ BINMODE = 1 @}" @dots{}
+@end example
+
+@noindent
+o:
+
+@example
+gawk -f binmode1.awk @dots{}
+@end example
+
+@noindent
+Usando i caratteri di protezione appropriati, nel primo
+esempio l'impostazione di @code{RS} pu@`o essere spostata in una regola
+@code{BEGIN}.
+
+@node Cygwin
+@appendixsubsubsec Usare @command{gawk} in ambiente Cygwin
+@cindex compilare @command{gawk} per Cygwin
+@cindex Cygwin, compilare @command{gawk} per
+
+@command{gawk} pu@`o essere compilato e usato ``cos@`{@dotless{i}} com'@`e'' sotto MS-Windows se
+si opera all'interno dell'ambiente @uref{http://www.cygwin.com, Cygwin}.
+Questo ambiente consente un'eccellente simulazione di GNU/Linux, con l'uso di
+Bash, GCC, GNU Make, e altri programmi GNU. La compilazione e l'installazione
+per Cygwin @`e la stessa usata nei sistemi di tipo Unix:
+
+@example
+tar -xvpzf gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz
+cd gawk-@value{VERSION}.@value{PATCHLEVEL}
+./configure
+make && make check
+@end example
+
+In confronto a un sistema GNU/Linux sulla stessa macchina, l'esecuzione
+del passo di @samp{configure} sotto Cygwin richiede molto pi@`u tempo. Tuttavia
+si conclude regolarmente, e poi @samp{make} funziona come ci si aspetta.
+
+@node MSYS
+@appendixsubsubsec Usare @command{gawk} in ambiente MSYS
+
+Nell'ambiente MSYS sotto MS-Windows, @command{gawk} automaticamente usa la
+modalit@`a binaria per leggere e scrivere file. Non @`e quindi necessario usare la
+variabile @code{BINMODE}.
+
+Questo pu@`o causare problemi con altri componenti di tipo Unix che sono stati
+resi disponibile in MS-Windows, che si aspettano che @command{gawk} faccia
+automaticamente la conversione di @code{"\r\n"}, mentre cos@`{@dotless{i}} non @`e.
+
+@node Installazione su VMS
+@appendixsubsec Compilare e installare @command{gawk} su Vax/VMS e OpenVMS
+
+@c based on material from Pat Rankin <rankin@eql.caltech.edu>
+@c now rankin@pactechdata.com
+@c now r.pat.rankin@gmail.com
+
+@cindex @command{gawk}, versione VMS di
+@cindex installare @command{gawk} su VMS
+@cindex VMS, installare @command{gawk} su
+Questa @value{SUBSECTION} descrive come compilare e installare @command{gawk}
+sotto VMS. Il termine classico ``VMS'' @`e usato qui anche per designare
+OpenVMS.
+
+@menu
+* Compilazione su VMS:: Come compilare @command{gawk} su VMS.
+* Estensioni dinamiche su VMS:: Compilare estensioni dinamiche
+ di @command{gawk} su VMS.
+* Dettagli installazione su VMS:: Come installare @command{gawk} su VMS.
+* Esecuzione su VMS:: Come eseguire @command{gawk} su VMS.
+* GNV su VMS:: Il progetto VMS GNV.
+* Vecchio Gawk su VMS:: Una versione non aggiornata arriva
+ con alcune versioni di VMS.
+@end menu
+
+@node Compilazione su VMS
+@appendixsubsubsec Compilare @command{gawk} su VMS
+@cindex compilare @command{gawk} per VMS
+@cindex VMS, compilare @command{gawk} per
+
+Per compilare @command{gawk} sotto VMS, esiste una procedura di comandi
+@code{DCL} che esegue tutti i comandi @code{CC} e @code{LINK} necessari. C'@`e
+anche un @file{Makefile} da usare con i programmi di utilit@`a @code{MMS} e
+@code{MMK}. A partire della directory che contiene i file sorgente, si usi:
+
+@example
+$ @kbd{@@[.vms]vmsbuild.com}
+@end example
+
+@noindent
+o:
+
+@example
+$ @kbd{MMS/DESCRIPTION=[.vms]descrip.mms gawk}
+@end example
+
+@noindent
+o:
+
+@example
+$ @kbd{MMK/DESCRIPTION=[.vms]descrip.mms gawk}
+@end example
+
+Il comando @command{MMK} @`e un quasi-clone, a codice aperto e gratuito, di
+@command{MMS}, che gestisce in maniera migliore i volumi ODS-5 con @value{FNS}
+a caratteri maiuscoli e minuscoli. @command{MMK} @`e disponibile da
+@uref{https://github.com/endlesssoftware/mmk}.
+
+Avendo a che fare con volumi ODS-5 e con l'analisi sintattica estesa abilitata,
+il nome del parametro che specifica l'obiettivo pu@`o dover essere scritto
+digitando esattamente le lettere maiuscole e minuscole.
+
+@command{gawk} @`e stato testato sotto VAX/VMS 7.3 e Alpha/VMS 7.3-1 usando il
+compilatore Compaq C V6.4, e sotto Alpha/VMS 7.3, Alpha/VMS 7.3-2, e IA64/VMS
+8.3. Le compilazioni pi@`u recenti hanno usato il compilatore HP C V7.3 su Alpha
+VMS 8.3 e su VMS 8.4, sia Alpha che IA64, hanno usato il compilatore HP C
+7.3.@footnote{L'architettura IA64 @`e anche nota come ``Itanium''.}
+
+@xref{GNV su VMS} per informazioni su come compilare
+@command{gawk} come un kit PCSI compatible con il prodotto GNV.
+
+@node Estensioni dinamiche su VMS
+@appendixsubsubsec Compilare estensioni dinamiche di @command{gawk} in VMS
+
+Le estensioni che sono state rese disponibile su VMS possono essere
+costruite dando uno dei comandi seguenti:
+
+@example
+$ @kbd{MMS/DESCRIPTION=[.vms]descrip.mms extensions}
+@end example
+
+@noindent
+o:
+
+@example
+$ @kbd{MMK/DESCRIPTION=[.vms]descrip.mms extensions}
+@end example
+
+@command{gawk} usa @code{AWKLIBPATH} come una variabile d'ambiente
+oppure come un nome logico per trovare le estensioni dinamiche.
+
+Le estensioni dinamiche devono essere compilate con le stesse opzioni del
+compilatore usate per compilare @command{gawk} riguardanti numeri in virgola
+mobile, dimensione dei puntatori e trattamento dei nomi simbolici. I computer
+con architettura Alpha e Itanium dovrebbero usare i numeri in virgola mobile
+col formato IEEE. La dimensione dei puntatori @`e 32 bit, e il trattamento dei nomi
+simbolici dovrebbe richiedere il rispetto esatto di maiuscole/minuscole, con le
+abbreviazioni CRC per simboli pi@`u lunghi di 32 bit.
+
+Per Alpha e Itanium:
+
+@example
+/name=(as_is,short)
+/float=ieee/ieee_mode=denorm_results
+@end example
+
+Per VAX:
+
+@example
+/name=(as_is,short)
+@end example
+
+Le macro da usare al momento della compilazione devono essere definite prima di
+includere il primo file di intestazione proveniente da VMS, come segue:
+
+@example
+#if (__CRTL_VER >= 70200000) && !defined (__VAX)
+#define _LARGEFILE 1
+#endif
+
+#ifndef __VAX
+#ifdef __CRTL_VER
+#if __CRTL_VER >= 80200000
+#define _USE_STD_STAT 1
+#endif
+#endif
+#endif
+@end example
+
+Se si scrivono delle estensioni utente da eseguire su VMS, vanno fornite anche
+queste definizioni. Il file @file{config.h} creato quando si compila
+@command{gawk} su VMS lo fa gi@`a; se invece si usa qualche altro file simile,
+occorre ricordarsi di includerlo prima di qualsiasi file di intestazione
+proveniente da VMS.
+
+@node Dettagli installazione su VMS
+@appendixsubsubsec Installare @command{gawk} su VMS
+
+Per usare @command{gawk}, tutto ci@`o che serve @`e un comando ``esterno'', che @`e
+un simbolo @code{DCL} il cui valore inizia col segno del dollaro.
+Per esempio:
+
+@example
+$ @kbd{GAWK :== $disk1:[gnubin]gawk}
+@end example
+
+@noindent
+Si sostituisca la posizione corrente di @command{gawk.exe} a
+@samp{$disk1:[gnubin]}. Il simbolo dovrebbe essere posto nel file
+@file{login.com} di ogni utente che desideri eseguire @command{gawk},
+in modo che sia definito ogni volta che l'utente inizia una sessione.
+Alternativamente, il simbolo pu@`o essere messo nella procedura di sistema
+@file{sylogin.com},
+in modo da permettere a tutti gli utenti di eseguire @command{gawk}.
+
+Se @command{gawk} @`e stato installato da un kit PCSI nell'albero di
+directory @file{GNV$GNU:}, il programma avr@`a come nome
+@file{GNV$GNU:[bin]gnv$gawk.exe}, e il file di aiuto sar@`a chiamato
+@file{GNV$GNU:[vms_help]gawk.hlp}.
+
+Il kit PCSI installa anche un file @file{GNV$GNU:[vms_bin]gawk_verb.cld}
+che pu@`o essere usato per aggiungere @command{gawk} e @command{awk}
+alla lista dei comandi DCL.
+
+Per farlo solo nella sessione corrente si pu@`o usare:
+
+@example
+$ @kbd{set command gnv$gnu:[vms_bin]gawk_verb.cld}
+@end example
+
+Oppure il sistemista VMS pu@`o usare @file{GNV$GNU:[vms_bin]gawk_verb.cld} per
+aggiungere @command{gawk} e @command{awk} alla tabella @samp{DCLTABLES}
+valida per tutto il sistema.
+
+La sintassi DCL @`e documentata nel file @file{gawk.hlp}.
+
+In alternativa, l'elemento @file{gawk.hlp} pu@`o essere caricato in una
+libreria di aiuto VMS:
+
+@example
+$ @kbd{LIBRARY/HELP sys$help:helplib [.vms]gawk.hlp}
+@end example
+
+@noindent
+(Una libreria specifica dell'installazione potrebbe venir usata invece
+della libreria standard VMS library @samp{HELPLIB}.) Dopo aver installato
+il testo di aiuto, il comando:
+
+@example
+$ @kbd{HELP GAWK}
+@end example
+
+@noindent
+fornisce informazioni sia sull'implementazione di @command{gawk}
+sia sul linguaggio di programmazione @command{awk}.
+
+Il nome logico @samp{AWK_LIBRARY} pu@`o designare una posizione di default per i
+file di programma @command{awk}. Riguardo all'opzione @option{-f}, se il
+@value{FN} specificato non contiene un dispositivo o un percorso di directory,
+@command{gawk} cerca dapprima nella directory corrente, poi nella directory
+specificata dalla traduzione di @samp{AWK_LIBRARY} se il file non @`e stato
+trovato. Se, dopo aver cercato in entrambe queste directory, il file non @`e
+ancora stato trovato, @command{gawk} appone il suffisso @samp{.awk} al
+@value{FN} e ritenta la ricerca del file. Se @samp{AWK_LIBRARY} non @`e
+definita, si usa per essa il valore di default @samp{SYS$LIBRARY:}.
+
+@node Esecuzione su VMS
+@appendixsubsubsec Eseguire @command{gawk} su VMS
+
+L'elaborazione della riga di comando e le convenzioni per proteggere i
+caratteri sono significativamente differenti in VMS, e quindi gli esempi
+presenti in questo @value{DOCUMENT} o provenienti da altre fonti necessitano
+piccole modifiche. Le modifiche, tuttavia, @emph{sono} veramente piccole, e
+tutti i programmi @command{awk} dovrebbero funzionare correttamente.
+
+Ecco un paio di semplici test:
+
+@example
+$ @kbd{gawk -- "BEGIN @{print ""Hello, World!""@}"}
+$ @kbd{gawk -"W" version}
+! ma anche -"W version" o "-W version"
+@end example
+
+@noindent
+Si noti che il testo con caratteri maiuscoli e misti maiuscoli/minuscoli
+dev'essere incluso tra doppi apici.
+
+La versione VMS di @command{gawk} comprende un'interfaccia in stile @code{DCL},
+oltre a quella originale, di tipo shell (si veda il file di aiuto per ulteriori
+dettagli). Un effetto indesiderato della duplice analisi della riga
+di comando @`e che se c'@`e solo un unico parametro (come nel programma con le
+righe contenenti doppi apici), il comando diviene ambiguo. Per evitare questo
+inconveniente, il flag, normalmente non necessario, @option{--} @`e necessario
+per forzare un esame dei parametri in stile Unix, piuttosto che nella modalit@`a
+@code{DCL}. Se qualsiasi altra opzione preceduta dal segno @option{-} (o pi@`u
+parametri, per esempio, pi@`u @value{DF} in input) @`e presente, non c'@`e ambiguit@`a,
+e l'opzione @option{--} pu@`o essere omessa.
+
+@cindex exit, codice di ritorno, in VMS
+Il valore di @code{exit} @`e un valore in stile Unix e viene trasformato in
+una condizione VMS all'uscita del programma.
+
+I bit di severit@`a di VMS saranno impostati a partire dal valore dell'istruzione
+@code{exit}. Un errore grave @`e indicato da 1, e VMS imposta la condizione
+@code{ERROR}. Un errore fatale @`e indicato da 2, e VMS imposta la condizione
+@code{FATAL}. Ogni altro valore imposta la condizione @code{SUCCESS}. Il
+valore d'uscita @`e codificato per aderire agli standard di codifica VMS e avr@`a
+un @code{C_FACILITY_NO} di @code{0x350000} con il codice costante @code{0xA000}
+aggiunto al numero spostato a sinistra di 3 bit per far posto al codice di
+severit@`a.
+
+Per estrarre il codice reale di ritorno dell'istruzione @code{exit}
+di @command{gawk} dalla condizione impostata da VMS, si usi:
+
+@example
+unix_status = (vms_status .and. %x7f8) / 8
+@end example
+
+@noindent
+Un programma C che usa @code{exec()} per chiamare @command{gawk}
+ricever@`a il valore originale della exit in stile Unix.
+
+Precedenti versioni di @command{gawk} per VMS consideravano un codice di
+ritorno a Unix di 0 come 1, un errore come 2, un errore fatale come 4, e tutti
+gli altri valori erano restituiti immodificati. Questa era una violazione
+rispetto alle specifiche di codifica delle condizioni di uscita di VMS.
+
+@cindex numeri in virgola mobile, VAX/VMS
+@cindex VAX/VMS, numeri in virgola mobile,
+L'aritmetica in virgola mobile VAX/VMS usa un arrotondamento statistico.
+@xref{Funzione round}.
+
+VMS restituisce data e ora in formato GMT, a meno che non siano stati impostati
+i nomi logici @code{SYS$TIMEZONE_RULE} o @code{TZ}. Precedenti versioni di
+VMS, come VAX/VMS 7.3, non impostano questi nomi logici.
+
+@c @cindex directory search
+@c @cindex path, search
+@cindex percorso di ricerca
+@cindex percorso di ricerca per file sorgente
+Il percorso di ricerca di default, nella ricerca dei file di programma per
+@command{awk} specificati dall'opzione @option{-f}, @`e
+@code{"SYS$DISK:[],AWK_LIBRARY:"}. Il nome logico @env{AWKPATH} pu@`o essere
+usato per sostituire questo di default. Il formato di @env{AWKPATH} @`e una lista
+di directory, separate da virgola. Nel definirla, il valore dovrebbe essere
+incluso tra doppi apici, in modo che consenta una sola traduzione, e non una
+lista di ricerca multitraduzione @code{RMS}.
+
+@cindex ridirezione in VMS
+
+Questa restrizione vale anche se si esegue @command{gawk} sotto GNV,
+in quanto la ridirezione @`e sempre verso un comando DCL.
+
+Se si ridirigono dati verso un comando o un programma di utilit@`a VMS,
+l'implementazione corrente richiede la creazione di un comando VMS esterno che
+esegua un file di comandi, prima di invocare @command{gawk}.
+(Questa restrizione potrebbe essere rimossa in una futura versione di
+@command{gawk} per VMS.)
+
+Senza un tale file di comandi, i dati in input saranno presenti anche
+in output, prima dei dati di output veri e propri.
+
+Ci@`o consente la simulazione di comandi POSIX non disponibili in VMS
+o l'uso di programmi di utilit@`a GNV.
+
+L'esempio seguente mostra come ridirigere dati da @command{gawk} verso il
+comando VMS @command{sort}.
+
+@example
+$ sort = "@@device:[dir]vms_gawk_sort.com"
+@end example
+
+Il file di comandi deve avere il formato dell'esempio seguente.
+
+La prima riga serve a evitare che i dati in input siano presenti anche
+nell'output. Dev'essere nel formato mostrato nell'esempio.
+
+La riga seguente crea un comando esterno che prevale sul comando esterno
+superiore, che serve a prevenire una ricorsione infinita di file di comandi.
+
+Il penultimo comando ridirige @code{sys$input} su @code{sys$command},
+per poter ottenere i dati che sono ridiretti verso il comando.
+
+L'ultima riga esegue il comando vero e proprio. Dev'essere l'ultimo
+comando, perch@'e i dati ridiretti da @command{gawk} saranno letti
+quando il file di comandi finisce di essere eseguito.
+
+@example
+$!'f$verify(0,0)'
+$ sort := sort
+$ define/user sys$input sys$command:
+$ sort sys$input: sys$output:
+@end example
+
+
+@node GNV su VMS
+@appendixsubsubsec Il progetto VMS GNV
+
+Il pacchetto VMS GNV fornisce un ambiente di sviluppo simile
+a POSIX tramite una collezione di strumenti @dfn{open source}.
+Il @command{gawk} presente nel pacchetto base GNV @`e una vecchia versione.
+Attualmente, il progetto GNV @`e in fase di riorganizzazione, con l'obiettivo
+di offrire pacchetti PCSI separati per ogni componente.
+Si veda @w{@uref{https://sourceforge.net/p/gnv/wiki/InstallingGNVPackages/}.}
+
+La procedura normale per compilare @command{gawk} produce un programma
+adatto a essere usato con GNV.
+
+Il file @file{vms/gawk_build_steps.txt} nella distribuzione documenta
+la procedura per compilare un pacchetto PCSI compatible con GNV.
+
+@ignore
+@c The VMS POSIX product, also known as POSIX for OpenVMS, is long defunct
+@c and building gawk for it has not been tested in many years, but these
+@c old instructions might still work if anyone is still using it.
+
+@node VMS POSIX
+@appendixsubsubsec Compilare e usare @command{gawk} su VMS POSIX
+
+Le istruzioni appena viste vanno ignorate, sebbene @file{vms/gawk.hlp}
+dovrebbe ancora essere reso disponibile in una libreria di aiuto.
+L'albero del codice sorgente dovrebbe essere scompattato in un sottosistema
+contenitore di file, e non nel normale @dfn{filesystem} VMS.
+Occorre accertarsi che i due script, @file{configure} e
+@file{vms/posix-cc.sh}, siano eseguibile; si usi @samp{chmod +x} per farlo,
+se necessario. Poi vanno eseguiti i seguenti due comandi:
+
+@example
+psx> @kbd{CC=vms/posix-cc.sh configure}
+psx> @kbd{make CC=c89 gawk}
+@end example
+
+@noindent
+Il primo comando costruisce i file @file{config.h} e @file{Makefile},
+a partire da dei modelli, usando uno script per fare s@`{@dotless{i}} che il
+compilatore C soddisfi le aspettative di @command{configure}. Il secondo
+comando compila e collega @command{gawk} chiamando direttamente il
+compilatore C; gli eventuali messaggi di @command{make} che dicono di non
+riuscire a ridefinire @code{CC} vanno ignorati. @command{configure}
+impiega molto tempo a completarsi, ma in compenso continua a fornire
+messaggi che permettono di seguirne l'avanzamento.
+
+Questo @`e stato testato con VAX/VMS V6.2, VMS POSIX V2.0, e DEC C V5.2.
+
+Una volta installato, @command{gawk} funziona come ogni altro programma
+di utilit@`a della shell. A differenza della normale versione VMS di
+@command{gawk}, neesuna manipolazione speciale della riga di comando @`e
+necessaria nell'ambiente VMS POSIX.
+@end ignore
+
+@node Vecchio Gawk su VMS
+@appendixsubsubsec Vecchia versione di @command{gawk} su sistemi VMS
+
+
+@c Thanks to "gerard labadie" <gerard.labadie@gmail.com>
+
+Alcune versioni di VMS includono una vecchia versione di @command{gawk}.
+Per utilizzarla, occorre definire un simbolo, come segue:
+
+@example
+$ @kbd{gawk :== $sys$common:[syshlp.examples.tcpip.snmp]gawk.exe}
+@end example
+
+La versione appare essere la @value{PVERSION} 2.15.6, che @`e molto vecchia.
+Si raccomanda di compilare e usare la versione corrente.
+
+@node Bug
+@appendixsec Segnalazione di problemi e bug
+@cindex archeologi
+@quotation
+@i{Non c'@`e niente di pi@`u pericoloso di un archeologo annoiato.}
+@author Douglas Adams, @cite{Guida galattica per autostoppisti}
+@end quotation
+@c the radio show, not the book. :-)
+
+@cindex debug, @command{gawk}, segnalare bug
+@cindex risoluzione problemi @command{gawk}, segnalare bug
+Se si incontrano problemi con @command{gawk} o se si ritiene di aver trovato un
+bug, si raccomanda di segnalarlo agli sviluppatori;
+non c'@`e un impegno preciso a intervenire, ma c'@`e una buona possibilit@`a che ci
+si sforzi di risolverlo.
+
+@menu
+* Indirizzo Bug:: Dove inviare le segnalazioni.
+* Usenet:: Dove non inviare le segnalazioni.
+* Manutentori:: Manutentori di version non-*nix.
+@end menu
+
+@node Indirizzo Bug
+@appendixsubsec Segnalare Bug
+
+Prima di segnalare un bug, occorre assicurarsi che sia davvero un bug. La
+documentazione va riletta attentamente, per controllare se dice che @`e possibile
+fare quel che si sta tentando di fare. Se non @`e chiaro se sia possibile
+fare quella particolare cosa o no, occorre segnalarlo; in questo caso si tratta
+di un bug nella documentazione!
+
+Prima di segnalare un bug o di tentare di risolverlo personalmente, si tenti
+di isolarlo preparando un programma @command{awk} il pi@`u piccolo possibile, con
+un @value{DF} in input che possa riprodurre il problema. Dopo averlo fatto, si
+spedisca il programma e il @value{DF}, insieme a informazioni sul tipo di
+sistema Unix in uso, il compilatore usato per compilare @command{gawk}, e i
+risultati esatti che @command{gawk} ha prodotto. Inoltre andrebbe specificato
+cosa ci si aspettava che il programma facesse; questo @`e di aiuto per decidere
+se il problema @`e un problema di documentazione.
+
+@`E importante includere il numero di versione di @command{gawk} in uso.
+Questa informazione si pu@`o ottenere con il comando @samp{gawk --version}.
+
+@cindex @code{bug-gawk@@gnu.org} indirizzo per la segnalazione dei bug
+@cindex email, indirizzo per segnalare bug, @code{bug-gawk@@gnu.org}
+@cindex indirizzo email per segnalare bug, @code{bug-gawk@@gnu.org}
+@cindex bug, segnalare, indirizzo email, @code{bug-gawk@@gnu.org}
+@cindex segnalare bug, indirizzo email, @code{bug-gawk@@gnu.org}
+Una volta pronta la descrizione precisa del problema, si spedisca un messaggio
+di posta elettronica a @EMAIL{bug-gawk@@gnu.org,bug-gawk at gnu dot org}.
+
+I manutentori di @command{gawk} sono i destinatari, e riceveranno la
+segnalazione di errore. Sebbene sia possibile spedire messaggi direttamente ai
+manutentori, @`e preferibile usare l'indirizzo sopra fornito perch@'e quella
+mailing list rimane in archivio presso il Progetto GNU. @emph{Tutti i messaggi
+devono essere in inglese. @`E questo il solo linguaggio che tutti i manutentori
+conoscono.} Inoltre, occorre accertarsi di spedire tutti i messaggi in formato
+@emph{testo}, e non (o non soltanto) in formato HTML.
+
+@quotation NOTA
+Molte distribuzioni di GNU/Linux e i vari sistemi operativi basati su
+BSD hanno un loro proprio canale per segnalare i bug. Se si segnala un
+bug usando il canale della distribuzione, una copia del messaggio andrebbe
+inviata anche a @EMAIL{bug-gawk@@gnu.org,bug-gawk at gnu dot org}.
+
+Questo per due ragioni. La prima @`e che, sebbene alcune distribuzioni inoltrino
+i messaggi sui problemi ``verso l'alto'' alla mailing list GNU, molte non lo
+fanno, e quindi c'@`e una buona probabilit@`a che i manutentori di @command{gawk}
+non vedano affatto il messaggio relativo al bug! La seconda ragione @`e che la
+posta diretta alla mailing list GNU @`e archiviata, e il poter disporre di ogni
+cosa all'interno del progetto GNU consente di avere a disposizione tutte le
+informazioni rilevanti senza dover dipendere da altre organizzazioni.
+@end quotation
+
+Suggerimenti non correlati a bug sono pure sempre benvenuti. Se si hanno
+domande riguardo a qualcosa di non chiaro nella documentazione o a proposito
+di funzionalit@`a oscure, si scriva alla mailing list dei bug; si prover@`a
+a essere di aiuto nei limiti del possibile.
+
+@node Usenet
+@appendixsubsec Non segnalare bug a USENET!
+
+@quotation
+@c Date: Sun, 17 May 2015 19:50:14 -0400
+@c From: Chet Ramey <chet.ramey@case.edu>
+@c Reply-To: chet.ramey@case.edu
+@c Organization: ITS, Case Western Reserve University
+@c To: Aharon Robbins <arnold@skeeve.com>
+@c CC: chet.ramey@case.edu
+Ho iniziato a ignorare Usenet un paio di anni fa, e non me ne sono mai
+pentito. @`E come quando si parla di sport alla radio---ci si sente
+pi@`u intelligenti per aver lasciato perdere.
+@author Chet Ramey
+@end quotation
+
+@cindex @code{comp.lang.awk} gruppo di discussione
+@cindex newsgroup @code{comp.lang.awk}
+@cindex gruppo di discussione @code{comp.lang.awk}
+Siete pregati di @emph{non} provare a notificare bug di @command{gawk}
+scrivendo al gruppo di discussione Usenet/Internet @code{comp.lang.awk}.
+Sebbene alcuni degli sviluppatori di @command{gawk} leggano talora i
+messaggi di questo gruppo di discussione, il manutentore principale di
+@command{gawk} non lo fa pi@`u. Quindi @`e praticamente certo che un
+messaggio inviato l@`a @emph{non} sia da lui letto.
+La procedura qui descritta @`e la sola maniera ufficialmente riconosciuta
+per notificare problemi. Davvero!
+
+@ignore
+And another one:
+
+Date: Thu, 11 Jun 2015 09:00:56 -0400
+From: Chet Ramey <chet.ramey@case.edu>
+
+My memory was imperfect. Back in June 2009, I wrote:
+
+"That's the nice thing about open source, right? You can take your ball
+and run to another section of the playground. Then, if you like mixing
+metaphors, you can throw rocks from there."
+@end ignore
+
+@node Manutentori
+@appendixsubsec Notificare problemi per versioni non-Unix
+
+Se si riscontrano bug in una delle versioni non-Unix di @command{gawk}, una
+copia del messaggio inviato alla mailing list dei bug andrebbe spedita alla
+persona che si occupa di quella versione. I manutentori sono elencati nella
+lista seguente, come pure nel file @file{README} nella distribuzione
+@command{gawk}. Le informazioni nel file @file{README} dovrebbero essere
+considerate come le pi@`u aggiornate, se risultano in conflitto con questo
+@value{DOCUMENT}.
+
+Le persone che si occupano delle varie versioni di @command{gawk} sono:
+
+@c put the index entries outside the table, for docbook
+@cindex Buening, Andreas
+@cindex Deifik, Scott
+@cindex Malmberg, John E.
+@cindex Pitts, Dave
+@cindex G., Daniel Richard
+@cindex Robbins, Arnold
+@cindex Zaretskii, Eli
+@ifset SMALLPRINT
+@multitable {MS-Windows} {123456789012345678901234567890123456789001234567890}
+@end ifset
+@ifclear SMALLPRINT
+@multitable {MS-Windows con MinGW} {123456789012345678901234567890123456789001234567890}
+@end ifclear
+@item Unix e sistemi POSIX @tab Arnold Robbins, @EMAIL{arnold@@skeeve.com,arnold at skeeve dot com}
+
+@c @item MS-DOS con DJGPP @tab Scott Deifik, @EMAIL{scottd.mail@@sbcglobal.net,scottd dot mail at sbcglobal dot net}
+
+@item MS-Windows con MinGW @tab Eli Zaretskii, @EMAIL{eliz@@gnu.org,eliz at gnu dot org}
+
+@c Leave this in the document on purpose.
+@c OS/2 is not mentioned anywhere else though.
+@item OS/2 @tab Andreas Buening, @EMAIL{andreas.buening@@nexgo.de,andreas dot buening at nexgo dot de}
+
+@item VMS @tab John Malmberg, @EMAIL{wb8tyw@@qsl.net,wb8tyw at qsl.net}
+
+@item z/OS (OS/390) @tab Daniel Richard G.@: @EMAIL{skunk@@iSKUNK.ORG,skunk at iSKUNK.ORG}
+@item @tab Dave Pitts (Maintainer Emeritus), @EMAIL{dpitts@@cozx.com,dpitts at cozx dot com}
+@end multitable
+
+Se il problema riscontrato @`e riproducibile anche sotto Unix,
+si dovrebbe spedire una copia del messaggio anche alla mailing list
+@EMAIL{bug-gawk@@gnu.org,bug-gawk at gnu dot org}.
+
+La versione generata usando gli strumenti DJGPP non @`e pi@`u supportata;
+il codice relativo rester@`a nella distribuzione ancora per qualche tempo,
+nel caso che qualche volontario desideri prenderla in carico.
+Se questo non dovesse succedere, la parte di codice relativa questa
+versione sar@`a rimossa dalla distribuzione.
+
+@node Altre versioni
+@appendixsec Altre implementazioni di @command{awk} liberamente disponibili
+@cindex @command{awk}, implementazioni di
+@cindex implementazioni di @command{awk}
+@ignore
+From: emory!amc.com!brennan (Michael Brennan)
+Subject: C++ comments in awk programs
+To: arnold@gnu.ai.mit.edu (Arnold Robbins)
+Date: Wed, 4 Sep 1996 08:11:48 -0700 (PDT)
+
+@end ignore
+@cindex Brennan, Michael
+@ifnotdocbook
+@quotation
+@i{@`E piuttosto divertente mettere commenti simili nel vostro codice awk:}@*
+@ @ @ @ @ @ @code{// Funzionano i commenti in stile C++? Risposta: s@`{@dotless{i}}! certo}
+@author Michael Brennan
+@end quotation
+@end ifnotdocbook
+
+@docbook
+<blockquote><attribution>Michael Brennan</attribution>
+<literallayout><emphasis>
+@`E piuttosto divertente mettere commenti simili nel vostro codice awk.
+</emphasis>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<literal>
+// Funzionano i commenti in stile C++? Risposta: s@`{@dotless{i}}! certo
+</literal></literallayout>
+</blockquote>
+@end docbook
+
+Ci sono alcune altre implementazioni di @command{awk} disponibili
+gratuitamente.
+Questa @value{SECTION} descrive in breve dove @`e possibile trovarle:
+
+@table @asis
+@cindex Kernighan, Brian
+@cindex sorgente, codice, Brian Kernighan @command{awk}
+@cindex codice sorgente, Brian Kernighan @command{awk}
+@cindex @command{awk}, versioni di, si veda anche Brian Kernighan, @command{awk} di
+@cindex Brian Kernighan, @command{awk} di, codice sorgente
+@item Unix @command{awk}
+Brian Kernighan, uno degli sviluppatori originali di Unix @command{awk},
+ha reso disponibile liberamente la sua implementazione di @command{awk}.
+Si pu@`o scaricare questa versione dalla
+@uref{http://www.cs.princeton.edu/~bwk, sua pagina principale}.
+@`E disponibile in parecchi formati compressi:
+
+@table @asis
+@item Archivio Shell
+@uref{http://www.cs.princeton.edu/~bwk/btl.mirror/awk.shar}
+
+@item File @command{tar} compresso
+@uref{http://www.cs.princeton.edu/~bwk/btl.mirror/awk.tar.gz}
+
+@item File Zip
+@uref{http://www.cs.princeton.edu/~bwk/btl.mirror/awk.zip}
+@end table
+
+@cindex @command{git}, programma di utilit@`a
+@cindex programma di utilit@`a @command{git}
+@`E anche disponbile in GitHub:
+
+@example
+git clone git://github.com/onetrueawk/awk bwkawk
+@end example
+
+@noindent
+Questo comando crea una copia del deposito @uref{http://git-scm.com, Git}
+in una directory chiamata @file{bwkawk}. Se si omette questo argomento della
+riga di comando @command{git}, la copia del deposito @`e creata nella
+directory di nome @file{awk}.
+
+Questa versione richiede un compilatore ISO C (standard 1990); il compilatore
+C contenuto in GCC (la collezione di compilatori GNU) @`e pi@`u che sufficiente.
+
+@xref{Estensioni comuni}
+per una lista di estensioni in questo @command{awk} che non sono in
+POSIX @command{awk}.
+
+Incidentalmente, Dan Bornstein ha creato un deposito Git che contiene tutte le
+versioni di BWK @command{awk} che @`e riuscito a trovare. @`E disponibile in
+@uref{git://github.com/danfuzz/one-true-awk}.
+
+@cindex Brennan, Michael
+@cindex @command{mawk}, programma di utilit@`a
+@cindex programma di utilit@`a @command{mawk}
+@cindex codice sorgente, @command{mawk}
+@item @command{mawk}
+Michael Brennan ha scritto un'implementazione indipendente di @command{awk},
+di nome @command{mawk}. @`E disponibile sotto la licenza
+@ifclear FOR_PRINT
+GPL (@pxref{Copia}),
+@end ifclear
+@ifset FOR_PRINT
+GPL,
+@end ifset
+proprio come @command{gawk}.
+
+Il sito di distribuzione originale di @command{mawk} non contiene pi@`u
+il codice sorgente. Una copia @`e disponibile in
+@uref{http://www.skeeve.com/gawk/mawk1.3.3.tar.gz}.
+
+Dal 2009 @`e Thomas Dickey a occuparsi della manutenzione di @command{mawk}.
+Le informazioni di base sono disponibili nella
+@uref{http://www.invisible-island.net/mawk, pagine web del progetto}.
+Il puntatore URL da cui scaricare @`e
+@url{http://invisible-island.net/datafiles/release/mawk.tar.gz}.
+
+Una volta scaricato,
+per scompattare questo file pu@`o essere usato @command{gunzip}.
+L'installazione @`e simile a quella di @command{gawk}
+(@pxref{Installazione Unix}).
+
+@xref{Estensioni comuni}
+per una lista di estensioni in @command{mawk} che non sono in POSIX @command{awk}.
+
+@cindex Sumner, Andrew
+@cindex @command{awka}, compilatore per @command{awk}
+@cindex compilatore per @command{awk}, @command{awka}
+@cindex sorgente, codice, @command{awka}
+@cindex codice sorgente di @command{awka}
+@item @command{awka}
+Scritto da Andrew Sumner,
+@command{awka} traduce i programmi @command{awk} in C, li compila,
+e prepara il codice eseguibile usando una libreria di funzioni che
+implementano le funzionalit@`a di base di @command{awk}.
+Comprende anche un certo numero di estensioni.
+
+Il traduttore di @command{awk} @`e rilasciato sotto la licenza GPL, e la
+relativa libreria sotto la licenza LGPL.
+
+Per ottenere @command{awka}, si visiti
+il sito @url{http://sourceforge.net/projects/awka}.
+@c You can reach Andrew Sumner at @email{andrew@@zbcom.net}.
+@c andrewsumner@@yahoo.net
+
+Il progetto sembra essere stato congelato; non ci sono state modifiche nel
+codice sorgente dal 2001 circa.
+
+@cindex Beebe, Nelson H.F.@:
+@cindex @command{pawk} (versione con profilatura di Brian Kernighan @command{awk})
+@cindex codice sorgente, @command{pawk}
+@cindex sorgente, codice, @command{pawk}
+@item @command{pawk}
+Nelson H.F.@: Beebe all'Universit@`a dello Utah ha modificato
+BWK @command{awk} per fornire informazioni di temporizzazione e profilatura.
+Questo @`e differente dall'usare @command{gawk} con l'opzione @option{--profile}
+(@pxref{Profilare})
+nel senso che fornisce un profilo basato sul consumo di CPU, non sul
+numero di esecuzioni di una data riga di codice.
+Sia pu@`o trovare sia in
+@uref{ftp://ftp.math.utah.edu/pub/pawk/pawk-20030606.tar.gz}
+che in
+@uref{http://www.math.utah.edu/pub/pawk/pawk-20030606.tar.gz}.
+
+@item BusyBox @command{awk}
+@cindex BusyBox Awk
+@cindex codice sorgente, BusyBox Awk
+@cindex sorgente, codice, BusyBox Awk
+BusyBox @`e un programma distribuito con licenza GPL che fornisce versioni
+ridotte di parecchie piccole applicazioni, all'interno di un singolo modulo
+eseguibile. @`E stato ideato per sistemi
+integrati.
+Include un'implementazione completa di POSIX @command{awk}. Quando lo si
+compila occorre prestare attenzione a non eseguire @samp{make install}, perch@'e
+in questo modo si andrebbero a sostituire copie di altre applicazioni nella
+directory @file{/usr/local/bin} del sistema corrente. Per ulteriori
+informazioni, si veda @uref{http://busybox.net, la pagina principale del progetto}.
+
+@cindex OpenSolaris
+@cindex Solaris, versione POSIX @command{awk}
+@cindex codice sorgente, Solaris @command{awk}
+@cindex sorgente, codice, Solaris @command{awk}
+@item POSIX @command{awk} per OpenSolaris
+Le versioni di @command{awk} in @file{/usr/xpg4/bin} e @file{/usr/xpg6/bin} su
+Solaris sono @dfn{grosso modo} conformi allo standard POSIX. Sono basate sul
+comando @command{awk} preparato per i PC dalla ditta Mortice Kern. @`E stato
+possibile compilare e far funzionare questo codice sotto GNU/Linux dopo 1--2
+ore di lavoro. Rendere questo codice pi@`u generalmente portabile (usando gli
+strumenti GNU Autoconf e/o Automake) richiederebbe ulteriore lavoro, che non @`e
+stato fin qui compiuto, almeno per quel che risulta a chi scrive.
+
+@cindex Illumos
+@cindex Illumos, @command{awk} conforme a POSIX e
+@cindex codice sorgente, Illumos @command{awk}
+@cindex sorgente, codice, Illumos @command{awk}
+Il codice sorgente era un tempo disponibile dal sito web OpenSolaris.
+Tuttavia, il progetto @`e terminato, e il sito web chiuso. Fortunatamente,
+il progetto
+@uref{http://wiki.illumos.org/display/illumos/illumos+Home, Illumos}
+mette a disposizione questa implementazione. Si possono vedere i singoli file in
+@uref{https://github.com/joyent/illumos-joyent/blob/master/usr/src/cmd/awk_xpg4}.
+
+@cindex @command{jawk}
+@cindex Java, implementazione di @command{awk}
+@cindex implementazione Java di @command{awk}
+@cindex codice sorgente, @command{jawk}
+@cindex sorgente, codice, @command{jawk}
+@item @command{jawk}
+Questo @`e un interprete per @command{awk} scritto in Java. Dichiara di
+essere un interprete completo, anche se, poich@'e usa funzionalit@`a di Java
+per l'I/O e per la ricerca di @dfn{regexp}, il linguaggio che supporta
+@`e differente da @command{awk} POSIX.
+Ulteriori informazioni sono disponibili sulla
+@uref{http://jawk.sourceforge.net, pagina principale del progetto}.
+
+@item Libmawk
+@cindex @command{libmawk}
+@cindex codice sorgente, @command{libmawk}
+@cindex sorgente, codice, @command{libmawk}
+Questo @`e un interprete @command{awk} incorporabile, derivato da
+@command{mawk}. Per ulteriori informazioni, si veda
+@uref{http://repo.hu/projects/libmawk/}.
+
+@item @code{pawk}
+@cindex codice sorgente, @command{pawk} (versione Python)
+@cindex sorgente, codice, @command{pawk} (versione Python)
+@cindex @code{pawk}, implementazione simile ad @command{awk} per Python
+Questo @`e un modulo Python che intende introdurre funzionalit@`a di tipo
+@command{awk} in Python. Si veda @uref{https://github.com/alecthomas/pawk} per
+ulteriori informazioni. (Questo programma non @`e correlato con la versione
+modificata da Nelson Beebe di BWK @command{awk}, descritta prima.)
+
+@item @w{QSE @command{awk}}
+@cindex QSE @command{awk}
+@cindex codice sorgente, QSE @command{awk}
+@cindex sorgente, codice, QSE @command{awk}
+Questo @`e un interprete di @command{awk} incorporabile. Per ulteriori
+informazioni, si veda
+@uref{http://code.google.com/p/qse/} e @uref{http://awk.info/?tools/qse}.
+
+@item @command{QTawk}
+@cindex QuikTrim Awk
+@cindex codice sorgente, QuikTrim Awk
+@cindex sorgente, codice, QuikTrim Awk
+Questa @`e un'implementazione indipendente di @command{awk} distribuita con la
+licenza GPL. Ha un gran numero di estensioni rispetto ad @command{awk}
+standard, e pu@`o non essere sintatticamente compatibile al 100% con esso. Si
+veda @uref{http://www.quiktrim.org/QTawk.html} per ulteriori informazioni,
+compreso il manuale. Il puntatore per scaricare QuikTrim non punta all'ultima
+versione: si veda @uref{http://www.quiktrim.org/#AdditionalResources} per un
+puntatore alla versione corrente.
+
+Il progetto sembra essere fermo; non ci sono nuove versioni del codice
+a partire dal 2014 circa.
+
+@item Altre versioni
+Si veda anche [in inglese] la sezione ``Versions and implementations''
+della voce di
+@uref{http://en.wikipedia.org/wiki/Awk_language#Versions_and_implementations,
+Wikipedia} su @command{awk} per informazioni su ulteriori versioni.
+
+@end table
+
+@node Sommario dell'installazione
+@appendixsec Sommario
+
+@itemize @value{BULLET}
+@item
+La distribuzione di @command{gawk} @`e disponibile dal sito principale
+di distribuzione del Progetto GNU
+@code{ftp.gnu.org}. La maniera canonica per scaricarlo e installarlo @`e:
+
+@example
+wget http://ftp.gnu.org/gnu/gawk/gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz
+tar -xvpzf gawk-@value{VERSION}.@value{PATCHLEVEL}.tar.gz
+cd gawk-@value{VERSION}.@value{PATCHLEVEL}
+./configure && make && make check
+@end example
+
+@item
+@command{gawk} pu@`o essere installato anche su sistemi non-POSIX. I sistemi
+correntemente supportati sono MS-Windows, usando
+MSYS, MinGW, e Cygwin,
+e sia Vax/VMS che OpenVMS. Le istruzioni per ognuno di questi sistemi sono
+incluse in questa @value{APPENDIX}.
+
+@item
+Le segnalazioni di errori (bug) dovrebbero essere spedite tramite email a
+@email{bug-gawk@@gnu.org}. Le segnalazioni di errore dovrebbero essere scritte
+in inglese e dovrebbero specificare la versione di @command{gawk} in uso, come
+@`e stata compilata, un breve programma e un @value{DF} che permettono di
+riprodurre il problema.
+
+@item
+Ci sono alcune altre implementazioni di @command{awk} disponibili
+gratuitamente. Molte rispettano lo standard POSIX; altre un po' meno.
+
+@end itemize
+
+
+@ifclear FOR_PRINT
+@node Note
+@appendix Note di implementazione
+@cindex @command{gawk}, problemi di implementazione
+@cindex problemi di implementazione, @command{gawk}
+
+Quest'appendice contiene informazioni che interessano soprattutto le persone
+che aggiornano e mantengono @command{gawk}. L'intero contenuto si applica
+specificatamente a @command{gawk} e non ad altre implementazioni.
+
+@menu
+* Modalit@`a di compatibilit@`a:: Come inibire alcune estensioni di
+ @command{gawk}.
+* Aggiunte:: Fare aggiunte a @command{gawk}.
+* Future estensioni:: Nuove funzionalit@`a che potranno
+ essere implementate in futuro.
+* Limitazioni dell'implementazione:: Alcune limitazioni
+ dell'implementazione.
+* Progetto delle estensioni:: Note di progetto sull'estensione API.
+* Meccanismo delle vecchie estensioni:: Alcune compatibilit@`a per le vecchie
+ estensioni.
+* Sommario delle note:: Sommario delle note di
+ implementazione.
+@end menu
+
+@node Modalit@`a di compatibilit@`a
+@appendixsec Compatibilit@`a all'indietro e debug
+@cindex @command{gawk}, problemi di implementazione, compatibilit@`a all'indietro
+@cindex @command{gawk}, problemi di implementazione, debug
+@cindex risoluzione di problemi, @command{gawk}
+@cindex problemi, risoluzione di, @command{gawk}
+@cindex problemi di implementazione@comma{} @command{gawk}, debug
+
+@xref{POSIX/GNU},
+per un compendio delle estensioni GNU per il linguaggio e il programma
+@command{awk}. Tutte queste funzionalit@`a possono essere inibite invocando
+@command{gawk} con l'opzione @option{--traditional} o con l'opzione
+@option{--posix}.
+
+Se @command{gawk} @`e stato compilato per il debug con @samp{-DDEBUG}, @`e
+possibile specificare un'ulteriore opzione sulla riga di comando:
+
+@table @code
+@item -Y
+@itemx --parsedebug
+Stampa l'informazione contenuta nella pila di analisi, durante la fase di
+analisi iniziale del programma.
+@end table
+
+Quest'opzione @`e utile solo a chi sviluppa @command{gawk} e non all'utente
+occasionale. @`E probabile che non sia neppure disponibile nella versione di
+@command{gawk} che si sta usando, perch@'e rallenta l'esecuzione del programma.
+
+@node Aggiunte
+@appendixsec Fare aggiunte a @command{gawk}
+
+Se si desidera migliorare @command{gawk} in maniera significativa, c'@`e la
+massima libert@`a di farlo. @`E questo lo scopo del software libero; il codice
+sorgente @`e disponibile, ed @`e possibile modificarlo a piacere
+(@pxref{Copia}).
+
+@ifnotinfo
+Questa
+@end ifnotinfo
+@ifinfo
+Questo
+@end ifinfo
+@value{SECTION} tratta di come @`e possibile modificare @command{gawk},
+ed espone alcune considerazioni che si dovrebbero tenere presenti.
+
+@menu
+* Accedere ai sorgenti:: Accedere al deposito dei sorgenti Git.
+* Aggiungere codice:: Aggiungere codice al programma
+ principale @command{gawk}.
+* Nuovi sistemi:: Portare @command{gawk} su un nuovo sistema
+ operativo.
+* File derivati:: Perch@'e i file derivati sono tenuti
+ nel deposito @command{git}.
+@end menu
+
+@node Accedere ai sorgenti
+@appendixsubsec Accedere al deposito dei sorgenti Git di @command{gawk}
+
+Poich@'e @command{gawk} @`e Software Libero, il codice sorgente @`e sempre
+disponibile.
+@iftex
+La
+@end iftex
+@ref{Distribuzione di Gawk} descrive come scaricare e installare
+le versioni ufficiali rilasciate di @command{gawk}.
+
+@cindex @command{git}, programma di utilit@`a
+@cindex programma di utilit@`a @command{git}
+Peraltro, se si intende modificare @command{gawk} e mettere a disposizione le
+modifiche, @`e preferibile lavorare sulla versione in via di sviluppo. Per far
+ci@`o @`e necessario accedere al deposito del codice sorgente di @command{gawk}.
+Il codice @`e mantenuto usando il @uref{http://git-scm.com, sistema distribuito
+di controllo delle versioni Git}. Sar@`a necessario installarlo se non @`e gi@`a
+presente nel sistema. Quando @command{git} @`e disponibile, va usato il comando:
+
+@example
+git clone git://git.savannah.gnu.org/gawk.git
+@end example
+
+@noindent
+Questo comando scarica in locale una copia esatta del deposito dei
+sorgenti di @command{gawk}. Se si sta usando un @dfn{firewall}
+che non consente l'uso del protocollo nativo di Git, @`e possibile accedere
+ugualmente al deposito usando il comando:
+
+@example
+git clone http://git.savannah.gnu.org/r/gawk.git
+@end example
+
+Una volta modificato il sorgente, @`e posibile usare @samp{git diff} per
+produrre una @dfn{patch}, e spedirla al manutentore di @command{gawk}; si veda
+@ref{Bug}, per come farlo.
+
+In passato era disponibile un'interfaccia Git--CVS
+utilizzabile da persone che non avevano a disposizione Git. Purtroppo,
+quest'interfaccia non funziona pi@`u, ma si potrebbe avere maggior fortuna usando
+un sistema di controllo versioni pi@`u moderno, come Bazaar, che @`e dotato di
+un'estensione Git per lavorare con depositi di sorgenti Git.
+
+@node Aggiungere codice
+@appendixsubsec Aggiungere nuove funzionalit@`a
+
+@cindex @command{gawk}, aggiungere funzionalit@`a a
+@cindex funzionalit@`a, aggiungere a @command{gawk}
+@cindex aggiungere funzionalit@`a a @command{gawk}
+Ognuno @`e libero di aggiungere tutte le nuove funzionalit@`a che vuole a
+@command{gawk}. Comunque, se si desidera che tali modifiche siano incorporate
+nella distribuzione di @command{gawk}, ci sono parecchi passi da fare per
+rendere possibile la loro inclusione:
+
+@enumerate 1
+@item
+Prima di inserire la nuova funzionalit@`a all'interno di @command{gawk},
+prendere in considerazione la possibilit@`a di scriverla sotto forma di
+estensione (@pxref{Estensioni dinamiche}).
+Se ci@`o non @`e possibile, continuare con i passi rimanenti descritti in questa
+lista.
+
+@item
+Essere disposti a firmare un documento liberatorio appropriato.
+Se l'FSF deve poter distribuire le modifiche, queste vanno dichiarate
+di pubblico dominio, tramite la firma di un documento apposito, oppure
+attribuendo il copyright delle modifiche all'FSF.
+Entrambe queste azioni sono semplici da fare, e @emph{molte} persone gi@`a
+l'hanno fatto. Se ci sono domande da fare, mettersi in contatto con me
+(@pxref{Bug}),
+oppure @EMAIL{assign@@gnu.org,assign chiocciola gnu punto org}.
+
+@item
+Utilizzare l'ultima versione.
+@`E molto pi@`u semplice per me integrare modifiche se sono basate sull'ultima
+versione disponibile di @command{gawk} o, meglio ancora, sull'ultimo codice
+sorgente presente nel deposito Git. Se la versione di @command{gawk} @`e molto
+vecchia, potrei non essere affatto in grado di integrare le modifiche.
+(@xref{Scaricare},
+per informazioni su come ottenere l'ultima versione di @command{gawk}.)
+
+@item
+@ifnotinfo
+Seguire gli @cite{Standard di codifica GNU}.
+@end ifnotinfo
+@ifinfo
+Si veda @inforef{Top, , Version, standards, Standard di Codifica GNU}.
+@end ifinfo
+Questo documento descrive come dovrebbe essere scritto il software GNU.
+Se non lo si @`e letto, @`e bene farlo, preferibilmente @emph{prima}
+di iniziare a modificare @command{gawk}.
+(Gli @cite{Standard di codifica GNU} sono disponibili nel sito web del
+@uref{http://www.gnu.org/prep/standards/, Progetto GNU}.
+Sono disponibili anche versioni in formato Texinfo, Info, e DVI.)
+
+@cindex @command{gawk}, stile di codifica in
+@item
+Usare lo stile di codifica @command{gawk}.
+Il codice sorgente in C di @command{gawk} segue le istruzioni dello
+@cite{Standard di codifica GNU}, con qualche piccola eccezione. Il codice @`e
+formattato usando lo stile tradizionale ``K&R'', in particolare per ci@`o che
+riguarda il posizionamento delle parentesi graffe e l'uso del carattere TAB.
+In breve, le regole di codifica per @command{gawk}
+sono le seguenti:
+
+@itemize @value{BULLET}
+@item
+Usare intestazioni di funzione (prototipi) in stile ANSI/ISO quando
+si definiscono delle funzioni.
+
+@item
+Mettere il nome della funzione all'inizio della riga in cui la si sta definendo.
+
+@item
+Usare @samp{#elif} invece di nidificare istruzioni @samp{#if} all'interno
+di un'istruzione @samp{#else}.
+
+@item
+Mettere il tipo di codice di ritorno della funzione, anche se @`e @code{int},
+sulla riga immediatamente sopra quella che contiene il nome e gli argomenti
+della funzione.
+
+@item
+Mettere degli spazi attorno alle parentesi usate nelle strutture di controllo
+(@code{if}, @code{while}, @code{for}, @code{do}, @code{switch}
+e @code{return}).
+
+@item
+Non mettere spazi davanti alle parentesi usate nelle chiamate di funzione.
+
+@item
+Mettere spazi attorno a tutti gli operatori C e dopo le virgole,
+nelle chiamate di funzione.
+
+@item
+Non usare l'operatore @dfn{virgola} per produrre degli effetti collaterali
+multipli, tranne che nelle parti di inizializzazione e incremento dei cicli
+@code{for}, e nel corpo delle macro.
+
+@item
+Usare dei caratteri TAB per l'indentazione, e non dei semplici spazi.
+
+@item
+Usare lo stile ``K&R'' per formattare le parti di programma incluse fra
+parentesi graffe.
+
+@item
+Usare confronti con @code{NULL} e @code{'\0'} per le condizioni
+contenute nelle istruzioni @code{if}, @code{while} e @code{for}, e anche
+nelle varie clausole @code{case} delle istruzioni @code{switch}, invece
+del semplice puntatore o il semplice valore del carattere.
+
+@item
+Usare i valori @code{true} e @code{false} per le variabili @code{booleane},
+la costante simbolica @code{NULL} per i valori dei puntatori,
+e la costante carattere @code{'\0'} quando @`e il caso, invece dei valori @code{1}
+e @code{0}.
+
+@item
+Fornire un commento descrittivo di una riga per ogni funzione.
+
+@item
+Non usare la funzione @code{alloca()} per allocare memoria dalla @dfn{stack}.
+Il farlo genera dei problemi di portabilit@`a che non giustificano il vantaggio
+secondario di non doversi preoccupare di liberare la memoria. Usare invece
+@code{malloc()} e @code{free()}.
+
+@item
+Non usare confronti nella forma @samp{! strcmp(a, b)} o simili.
+Come disse una volta Henry Spencer, ``@code{strcmp()} non @`e una funzione
+booleana!'' Usare invece @samp{strcmp(a, b) == 0}.
+
+@item
+Per aggiungere nuovi valori a @dfn{flag} binari, usare costanti esadecimali
+esplicite (@code{0x001}, @code{0x002}, @code{0x004}, etc.) invece che
+spostare di un bit a sinistra in incrementi successivi
+(@samp{(1<<0)}, @samp{(1<<1)}, etc.).
+@end itemize
+
+@quotation NOTA
+Qualora fossi costretto a riformattare completamente il codice per
+farlo aderire allo stile di codifica usato in @command{gawk}, potrei anche
+decidere di ignorare del tutto le modifiche proposte.
+@end quotation
+
+@cindex Texinfo
+@item
+Aggiornare la documentazione.
+Insieme col nuovo codice, fornire nuove sezioni e/o capitoli per questo
+@value{DOCUMENT}. Per quanto possibile, usare il formato Texinfo, invece
+di fornire soltanto del testo ASCII non formattato (sebbene un semplice testo
+sia gi@`a meglio che nessuna documentazione). Le convenzioni da seguire in
+@cite{@value{TITLE}} sono elencate dopo la parole chiave @samp{@@bye} alla fine
+del file sorgente Texinfo. Se possibile, aggiornare anche la pagina di manuale
+in formato @command{man}.
+
+Si dovr@`a anche firmare un documento liberatorio relativo alle
+modifiche apportate alla documentazione.
+
+@cindex @command{git}, programma di utilit@`a
+@cindex programma di utilit@`a @command{git}
+@item
+Inviare le modifiche come file di differenze nel formato contestuale unificato.
+Usare @samp{diff -u -r -N} per confrontare i sorgenti originali dell'albero
+di sorgenti @command{gawk} con la versione proposta.
+Si raccomanda di usare la versione GNU di @command{diff} o, ancora meglio,
+@samp{git diff} o @samp{git format-patch}.
+Per inviare le modifiche proposte spedire l'output prodotto da @command{diff}.
+(@xref{Bug}, per l'indirizzo di posta elettronica.)
+
+L'uso di questo formato rende semplice per me l'applicazione delle modifiche
+alla versione principale del sorgente di @command{gawk} (usando il programma di
+utilit@`a @code{patch}). Se invece tocca a me applicare le modifiche a mano,
+con un editor di testo, potrei decidere di non farlo, specialmente
+se le modifiche sono molte.
+
+@item
+Includere una descrizione da aggiungere al file @file{ChangeLog} riguardo alla
+modifica da voi proposta. Questo serve a minimizzare l'attivit@`a a me
+richiesta, rendendo pi@`u facile per me l'accettazione delle modifiche, che
+diventa pi@`u semplice se si include anche questa parte nel file di differenze
+(nel formato @dfn{diff}).
+@end enumerate
+
+Sebbene questa possa sembrare una richiesta molto esigente, si tenga presente
+che, anche se il nuovo codice non @`e opera mia, tocca poi a me manutenerlo e
+correggere eventuali errori. Se non @`e possibile per me farlo senza perderci
+troppo tempo, potrei anche lasciar perdere la modifica.
+
+@node Nuovi sistemi
+@appendixsubsec Portare @command{gawk} su un nuovo Sistema Operativo
+@cindex portabilit@`a, @command{gawk}
+@cindex sistemi operativi, portare @command{gawk} su altri
+
+@cindex portare @command{gawk}
+Se si vuol portare @command{gawk} su di un nuovo sistema operativo, sono
+necessari parecchi passi:
+
+@enumerate 1
+@item
+Seguire le linee-guida contenute
+@ifinfo
+in @ref{Aggiungere codice},
+@end ifinfo
+@ifnotinfo
+nella precedente @value{SECTION}
+@end ifnotinfo
+relative allo stile di codifica, all'invio delle differenze proposte, etc.
+
+@item
+Essere disposti a firmare un documento liberatorio appropriato.
+Se l'FSF deve poter distribuire le modifiche, queste vanno dichiarate
+di pubblico dominio, tramite la firma di un documento apposito, oppure
+attribuendo il copyright delle modifiche all'FSF.
+Entrambe queste azioni sono semplici da fare, e @emph{molte} persone gi@`a
+l'hanno fatto. Se ci sono domande da fare, scrivere a me
+oppure all'indirizzo @email{gnu@@gnu.org}.
+
+@item
+Nel realizzare un @dfn{port}, tener presente che il codice
+deve coesistere pacificamente con il resto di @command{gawk} e con le
+versioni per altri sistemi operativi.
+Evitare modifiche non necessarie alla parte di codice che @`e indipendente
+dal sistema operativo. Se possibile, evitare di disseminare @samp{#ifdef},
+utili solo per il proprio @dfn{port}, all'interno del codice sorgente.
+
+Se le modifiche necessarie per un particolare sistema coinvolgono una parte
+troppo rilevante del codice, @`e probabile che io non le accetti.
+In questo caso si possono, naturalmente, distribuire le modifiche per
+proprio conto, basta che si rispettino i vincoli della GPL
+(@pxref{Copia}).
+
+@item
+Un certo numero di file che fanno parte della distribuzione di @command{gawk}
+sono mantenuti da terze persone e non dagli sviluppatori di @command{gawk}.
+Quindi, non si dovrebbero cambiare, se non per ragioni molto
+valide; vale a dire, modifiche a questi file non sono impossibili, ma
+le modifiche a questi file saranno controllate con estrema attenzione.
+I file sono
+@file{dfa.c},
+@file{dfa.h},
+@file{getopt.c},
+@file{getopt.h},
+@file{getopt1.c},
+@file{getopt_int.h},
+@file{gettext.h},
+@file{regcomp.c},
+@file{regex.c},
+@file{regex.h},
+@file{regex_internal.c},
+@file{regex_internal.h}
+e
+@file{regexec.c}.
+
+@item
+Un certo numero di altri file sono prodotti dagli Autotool [comandi di
+configurazione] di GNU (Autoconf, Automake, e GNU @command{gettext}).
+Neppure questi file dovrebbero essere modificati, se non per ragioni molto
+valide. I file sono
+@file{ABOUT-NLS},
+@file{config.guess},
+@file{config.rpath},
+@file{config.sub},
+@file{depcomp},
+@file{INSTALL},
+@file{install-sh},
+@file{missing},
+@file{mkinstalldirs},
+@file{xalloc.h}
+e
+@file{ylwrap}.
+
+@item
+Essere disponibili a continuare a manutenere il @dfn{port}.
+I sistemi operativi non-Unix sono supportati da volontari che tengono
+aggiornato il codice necessario per compilare ed eseguire @command{gawk}
+nei loro sistemi. Se nessuno @`e disponibile a tener aggiornato un @dfn{port},
+questo diventa non pi@`u supportato, e pu@`o essere necessario rimuoverlo dalla
+distribuzione.
+
+@item
+Fornire un appropriato file @file{gawkmisc.???}.
+Ogni @dfn{port} ha il proprio @file{gawkmisc.???} che implementa alcune
+funzioni specifiche per quel sistema operativo. Questa @`e una soluzione pi@`u
+pulita, rispetto a una quantit@`a di @samp{#ifdef} sparsi nel codice. Il file
+@file{gawkmisc.c} nella directory principale dei sorgenti include gli
+appropriati file @file{gawkmisc.???} da ogni sottodirectory. Anche
+quest'ultimo file va aggiornato.
+
+Ogni file @file{gawkmisc.???} del @dfn{port} ha un suffisso esplicativo
+del tipo di macchina o del sistema operativo in questione---per esempio,
+@file{pc/gawkmisc.pc} e @file{vms/gawkmisc.vms}. L'uso di suffissi distinti
+invece di un semplice @file{gawkmisc.c}, rende possibile spostare file da
+una sottodirectory propria del @dfn{port} nella sottodirectory principale,
+senza cancellare incidentalmente il file @file{gawkmisc.c} vero e proprio.
+(Al momento, questo rappresenta un problema solo per i @dfn{port} ai
+sistemi operativi dei PC.)
+
+@item
+Fornire un @file{Makefile} e ogni altro file sorgente o di intestazione in C
+che sia necessario per il proprio sistema operativo. Tutto il codice dovrebbe
+stare in una sottodirectory a parte, il cui nome sia lo stesso, o
+sia indicativo, del proprio sistema operativo o del tipo di computer.
+Se possibile, tentare di strutturare il codice in modo che non sia necessario
+spostare file dalla propria sottodirectory nella directory principale del
+codice sorgente. Se ci@`o non @`e possibile, evitare nel modo pi@`u assoluto di
+usare nomi per i file che siano duplicati di nomi di file presenti nella
+directory principale del codice sorgente.
+
+@item
+Aggiornare la documentazione.
+Scrivere una sezione (o pi@`u sezioni) per questo @value{DOCUMENT}
+che descriva i passi di installazione e compilazione necessari per compilare
+e/o installare @command{gawk} per il sistema desiderato.
+@end enumerate
+
+Seguire queste indicazioni facilita molto l'integrazione delle
+modifiche in @command{gawk} e la loro felice coesistenza con il codice di
+altri sistemi operativi gi@`a presenti.
+
+Nel codice che viene fornito e tenuto aggiornato, si possono
+tranquillamente usare uno stile di codifica e una disposizione delle
+parentesi graffe di proprio gradimento.
+
+@node File derivati
+@appendixsubsec Perch@'e i file generati sono tenuti in Git
+
+@cindex Git, uso per il codice sorgente di @command{gawk}
+@c From emails written March 22, 2012, to the gawk developers list.
+
+Se si esaminano i sorgenti di @command{gawk} nel deposito Git
+si noter@`a che sono inclusi file generati automaticamente dagli strumenti
+dell'infrastruttura GNU, come @file{Makefile.in} generato da Automake e
+anche @file{configure} proveniente da Autoconf.
+
+Questo comportamento @`e differente da quello di molti progetti di
+Libero Software che non memorizzano i file derivati, per mantenere pi@`u
+sgombro il deposito Git, rendendo cos@`{@dotless{i}} pi@`u facile comprendere quali sono le
+modifiche sostanziali confrontando differenti versioni, nel tentativo di
+capire cosa @`e cambiato tra una modifica e la precedente.
+
+Tuttavia, ci sono parecchie ragioni per le quali il manutentore di
+@command{gawk} preferisce mantenere ogni cosa nel deposito Git.
+
+Innanzitutto, perch@'e in questo modo @`e facile generare completamente ogni
+data versione, senza doversi preoccupare di avere a disposizione altri
+strumenti (pi@`u vecchi, probabilmente obsoleti, e in qualche caso
+perfino impossibili da trovare).
+
+Come esempio estremo, se solo si pensa di tentare di compilare, diciamo, la
+versione Unix V7 di @command{awk}, ci si accorge che non solo @`e necessario
+scaricare e ricompilare la versione V7 del comando @command{yacc} per farlo, ma
+anche che serve la versione V7 del comando @command{lex}. E quest'ultima @`e
+praticamente impossibile farla funzionare in un sistema GNU/Linux dei giorni
+nostri.@footnote{Ci abbiamo provato. @`E stata un'esperienza dolorosa.}
+
+(Oppure, diciamo che la versione 1.2 di @command{gawk} richiede il comando
+@command{bison} come funzionava nel 1989, e non @`e presente il file
+@file{awkgram.c} [generato tramite @command{bison}] nel deposito Git. Che cosa
+ci garantisce di riuscire a trovare quella versione di @command{bison}? O che
+@emph{quella} riesca a generarlo?)
+
+Se il deposito Git comprende tutti i file derivati,
+@`e facile, dopo averli scaricati, ricostruire il programma. (Oppure @`e @emph{pi@`u
+facile}, a seconda di quanto si vuole risalire indietro nel tempo).
+
+E qui arriviamo alla seconda (e pi@`u valida) ragione per cui tutti i file
+devono essere proprio nel deposito Git. Domandiamoci a chi ci si rivolge:
+agli sviluppatori di @command{gawk}, oppure a un utilizzatore che intende
+solo scaricare una data versione e provarla?
+
+Il manutentore di @command{gawk} desidera che per tutti gli utenti
+@command{awk} interessati sia possibile limitarsi a clonare il deposito sul
+proprio computer, selezionare la variante che lo interessa e costruirla. Senza
+doversi preoccupare di avere a disposizione le versioni corrette degli Autotool
+GNU.@footnote{Ecco un programma GNU che (secondo noi) @`e estremamente difficile
+da estrarre dal deposito Git e compilare. Per esempio, in un vecchio (ma
+ancora funzionante) PowerPC Macintosh, con il sistema operativo Mac Os X 10.5,
+@`e stato necessario scaricare e compilare una tonnellata di software,
+incominciando dallo stesso programma Git, per riuscire a lavorare con l'ultima
+versione del codice. Non @`e un'esperienza piacevole e, specie sui vecchi
+sistemi, @`e una notevole perdita di tempo.
+
+Neppure partire dall'ultimo archivio @command{tar} compresso @`e stata una
+passeggiata: i manutentori avevano eliminato i file compressi in formato
+@file{.gz} e @file{.bz2} sostituendoli con file di tipo @file{.tar.xz}.
+Bisognava quindi per prima cosa scaricare e compilare @command{xz}}.
+A questo serve il file @file{bootstrap.sh}. Va a "toccare"
+[tramite il comando @command{touch}] vari altri file nell'ordine richiesto
+in modo che
+
+@example
+# La formula canonica per compilare il software GNU:
+./bootstrap.sh && ./configure && make
+@end example
+
+@noindent
+tutto @emph{funzioni senza problemi}.
+
+Questo @`e estremamente importante per i rami
+@code{master} e @code{gawk-@var{X}.@var{Y}-stable}.
+
+Inoltre, il manutentore di @command{gawk} potrebbe sostenere che
+ci@`o @`e importante anche per gli sviluppatori di @command{gawk}. Tentando di
+scaricare il ramo @code{xgawk}@footnote{Un ramo (non pi@`u presente) creato da
+uno degli altri sviluppatori, e che non includeva i file generati.} per
+compilarlo, non ci riusc@`{@dotless{i}}. (Mancava il file @file{ltmain.sh}, ed egli non
+aveva idea di come crearlo, e c'erano anche ulteriori problemi.)
+
+La cosa lo lasci@`o in uno stato di frustrazione @emph{estrema}. Riguardo a quel
+ramo, il manutentore @`e in una posizione non differente da quella di un utente
+generico che voglia tentare di compilare @code{gawk-4.1-stable} o @code{master}
+dal deposito Git.
+
+Quindi, il manutentore ritiene che sia non solo importante, ma cruciale, che
+per ogni dato ramo la formula canonica evocata prima
+@emph{funzioni senza problemi}.
+
+@c Added 9/2014:
+Una terza ragione per avere tutti i file @`e che senza di essi, usare @samp{git
+bisect} per tentare di trovare quale modifica ha introdotto un errore diventa
+estremamente difficile. Il manutentore ha tentato di farlo su un altro
+progetto che richiede di eseguire @dfn{script} di inizializzazione allo scopo
+di creare lo @dfn{script} @command{configure} e cos@`{@dotless{i}} via; @`e stata un'esperienza
+veramente dolorosa. Se invece il deposito Git contiene tutto il necessario,
+usare @command{git bisect} al suo interno @`e molto facile.
+
+@c So - that's my reasoning and philosophy.
+
+Quali sono, quindi, alcune delle conseguenze e/o delle cose da fare?
+
+@enumerate 1
+@item
+Non importa se ci sono file differenti nei diversi rami
+prodotti da versioni differenti degli Autotool.
+
+@enumerate A
+@item
+Spetta al manutentore integrarli tra loro, e se ne occuper@`a lui.
+
+@item
+@`E facile per lui eseguire @samp{git diff x y > /tmp/diff1 ; gvim /tmp/diff1}
+per rimuovere le differenze che non sono rilevanti ai fini della revisione
+del codice sorgente.
+@end enumerate
+
+@item
+Sarebbe sicuramente d'aiuto se tutti usassero le stesse versioni degli Autotool
+GNU che lui usa, che in generale sono le ultime versioni rilasciate di
+Automake,
+Autoconf,
+@command{bison}
+e
+GNU @command{gettext}.
+
+@ignore
+If it would help if I sent out an ``I just upgraded to version x.y
+of tool Z'' kind of message to this list, I can do that. Up until
+now it hasn't been a real issue since I'm the only one who's been
+dorking with the configuration machinery.
+@end ignore
+
+@c @enumerate A
+@c @item
+Installare a partire dal sorgente @`e abbastanza facile. @`E il modo con cui il
+manutentore ha lavorato per anni (e ancora lavora).
+Egli aveva @file{/usr/local/bin} all'inizio del suo @env{PATH} e dava i
+seguenti comandi:
+
+@example
+wget http://ftp.gnu.org/gnu/@var{package}/@var{package}-@var{x}.@var{y}.@var{z}.tar.gz
+tar -xpzvf @var{package}-@var{x}.@var{y}.@var{z}.tar.gz
+cd @var{package}-@var{x}.@var{y}.@var{z}
+./configure && make && make check
+make install # come utente root
+@end example
+
+@c @item
+@ignore
+These days the maintainer uses Ubuntu 12.04 which is medium current, but
+he is already doing the above for Automake, Autoconf, and @command{bison}.
+@end ignore
+
+@ignore
+(C. Rant: Recent Linux versions with GNOME 3 really suck. What
+ are all those people thinking? Fedora 15 was such a bust it drove
+ me to Ubuntu, but Ubuntu 11.04 and 11.10 are totally unusable from
+ a UI perspective. Bleah.)
+@end ignore
+@c @end enumerate
+
+@ignore
+@item
+If someone still feels really strongly about all this, then perhaps they
+can have two branches, one for their development with just the clean
+changes, and one that is buildable (xgawk and xgawk-buildable, maybe).
+Or, as I suggested in another mail, make commits in pairs, the first with
+the "real" changes and the second with "everything else needed for
+ building".
+@end ignore
+@end enumerate
+
+La maggior parte del testo precedente fa parte di messaggi scritti
+originalmente dal manutentore agli altri sviluppatori @command{gawk}.
+Da uno degli sviluppatori @`e stata avanzata l'obiezione
+``@dots{} che chi scarica il sorgente da Git
+non @`e un utente finale''.
+
+Tuttavia, questo non @`e esatto. Ci sono ``utenti avanzati di @command{awk}''
+che possono installare @command{gawk} (usando la formula canonica vista sopra)
+ma che non conoscono il linguaggio C. Quindi, i rami pi@`u rilevanti
+dovrebbero essere sempre compilabili.
+
+@`E stato proposto poi di lanciare ogni notte uno @dfn{script} tramite il
+programma di utilit@`a @command{cron} per creare archivi in formato @command{tar}
+contenenti tutto ``il codice sorgente.'' Il problema in questo caso @`e che
+ci sono differenti alberi di sorgenti, che corrispondono ai vari rami!
+Quindi gli archivi notturni in questione non sono una risposta valida, anche
+per il fatto che il deposito Git pu@`o rimanere senza alcuna modifica
+significativa per settimane intere.
+
+Fortunatamente, il server Git pu@`o rispondere a questa esigenza. Per ogni
+dato ramo chiamato @var{nome-ramo}, basta usare:
+
+@example
+wget http://git.savannah.gnu.org/cgit/gawk.git/snapshot/gawk-@var{nome-ramo}.tar.gz
+@end example
+
+@noindent
+per ottenere una copia utilizzabile del ramo in questione.
+
+@node Future estensioni
+@appendixsec Probabili estensioni future
+@ignore
+From emory!scalpel.netlabs.com!lwall Tue Oct 31 12:43:17 1995
+Return-Path: <emory!scalpel.netlabs.com!lwall>
+Message-Id: <9510311732.AA28472@scalpel.netlabs.com>
+To: arnold@skeeve.atl.ga.us (Arnold D. Robbins)
+Subject: Re: May I quote you?
+In-Reply-To: Your message of "Tue, 31 Oct 95 09:11:00 EST."
+ <m0tAHPQ-00014MC@skeeve.atl.ga.us>
+Date: Tue, 31 Oct 95 09:32:46 -0800
+From: Larry Wall <emory!scalpel.netlabs.com!lwall>
+
+: Greetings. I am working on the release of gawk 3.0. Part of it will be a
+: thoroughly updated manual. One of the sections deals with planned future
+: extensions and enhancements. I have the following at the beginning
+: of it:
+:
+: @cindex PERL
+: @cindex Wall, Larry
+: @display
+: @i{AWK is a language similar to PERL, only considerably more elegant.} @*
+: Arnold Robbins
+: @sp 1
+: @i{Hey!} @*
+: Larry Wall
+: @end display
+:
+: Before I actually release this for publication, I wanted to get your
+: permission to quote you. (Hopefully, in the spirit of much of GNU, the
+: implied humor is visible... :-)
+
+I think that would be fine.
+
+Larry
+@end ignore
+@cindex Perl
+@cindex Wall, Larry
+@cindex Robbins, Arnold
+@quotation
+@i{AWK @`e un linguaggio simile a PERL, solo che @`e notevolmente pi@`u elegante.}
+@author Arnold Robbins
+@end quotation
+
+@quotation
+@i{Hey!}
+@author Larry Wall
+@end quotation
+
+Il file @file{TODO} nel ramo @code{master} del deposito Git di @command{gawk}
+contiene un elenco di possibili futuri miglioramenti. Alcuni di questi
+riguardano il codice sorgente, e altri possibili nuove funzionalit@`a.
+Consultare quel file per esaminare la lista.
+@xref{Aggiunte},
+se si @`e interessati a intraprendere qualcuno dei progetti col@`a elencati.
+
+@node Limitazioni dell'implementazione
+@appendixsec Alcune limitazioni dell'implementazione
+
+La tabella seguente specifica i limiti di @command{gawk} in un sistema di
+tipo Unix (sebbene anche tra questi ci potrebbero essere variazioni). Altri
+sistemi operativi possono avere limiti differenti.
+
+@multitable @columnfractions .40 .60
+@headitem Caratteristica @tab Limiti
+@item Caratteri in una classe di caratteri @tab 2^(numero di bit per byte)
+@item Lunghezza di un record in input @tab @code{MAX_INT}
+@item Lunghezza di un record in output @tab Illimitata
+@item Lunghezza di una riga di codice sorgente @tab Illimitata
+@item Numero di campi in un record @tab @code{MAX_LONG}
+@item Numero di ridirezioni di file @tab Illimitata
+@item Numero di record in input in un singolo file @tab @code{MAX_LONG}
+@item Numero totale di record in input @tab @code{MAX_LONG}
+@item Numero di ridirezioni via @dfn{pipe} @tab min(numero processi per utente, numero di file aperti)
+@item Valori numerici @tab Numeri a virgola mobile in doppia precisione (se non si usa la funzionalit@`a MPFR)
+@item Dimensione di un campo @tab @code{MAX_INT}
+@item Dimensione di una stringa letterale @tab @code{MAX_INT}
+@item Dimensione di una stringa di @dfn{printf} @tab @code{MAX_INT}
+@end multitable
+
+@node Progetto delle estensioni
+@appendixsec Note di progetto dell'estensione API
+
+Questa @value{SECTION} documenta l'architettura dell'estensione API,
+inclusa una trattazione sommaria della progettazione e dei problemi che
+andavano risolti.
+
+La prima versione delle estensioni per @command{gawk} @`e stata sviluppata
+a met@`a degli anni '90, e distribuita con la versione 3.1 di @command{gawk},
+verso la fine degli anni '90.
+Il meccanismo e l'architettura sono rimasti gli stessi per quasi 15 anni,
+fino al 2012.
+
+Il vecchio meccanismo delle estensioni usava tipi di dati e funzioni dello
+stesso @command{gawk}, con un ``abile trucco'' per installare le funzioni
+di estensione.
+
+La distribuzione @command{gawk} conteneva alcuni esempi di estensioni, solo
+poche delle quali erano realmente utili. Tuttavia era chiaro fin da
+principio che il meccanismo di estensione era un'aggiunta improvvisata, e
+non era realmente ben concepito.
+
+@menu
+* Problemi con le vecchie estensioni:: Problemi col vecchio meccanismo.
+* Obiettivi delle estensioni:: Obiettivi del nuovo meccanismo.
+* Altre scelte progettuali per le estensioni:: Qualche altra scelta progettuale.
+* Futuri sviluppi delle estensioni:: Possibilit@`a di crescita futura.
+@end menu
+
+@node Problemi con le vecchie estensioni
+@appendixsubsec Problemi con le vecchie estensioni
+
+Il vecchio meccanismo delle estensioni presentava parecchi problemi:
+
+@itemize @value{BULLET}
+@item
+Dipendeva eccessivamente dalla struttura interna di @command{gawk}. Ogni volta
+che la struttura @code{NODE}@footnote{Una struttura di dati fondamentale
+all'interno di @command{gawk}.} veniva modificata, ogni estensione doveva
+essere ricompilata. Inoltre, la scrittura di estensioni richiedeva una
+certa familiarit@`a con le funzioni interne di @command{gawk}. Esisteva
+un po' di documentazione in questo @value{DOCUMENT}, ma era ridotta al minimo.
+
+@item
+Per poter utilizzare servizi di @command{gawk} da un'estensione era necessario
+disporre di funzionalit@`a del @dfn{linker}
+normalmente disponibili in ambiente di tipo Unix, ma non implementate
+nei sistemi MS-Windows; chi voleva utilizzare estensioni in
+MS-Windows doveva aggiungerle al modulo eseguibile di @command{gawk},
+anche se MS-Windows supporta il caricamento dinamico di oggetti condivisi.
+
+@item
+L'API di tanto in tanto veniva modificata, in parallelo ai cambiamenti di
+@command{gawk}; nessuna compatibilit@`a tra le versioni @`e stata mai prevista o
+resa disponibile.
+@end itemize
+
+Nonostante questi inconvenienti, gli sviluppatori del progetto @command{xgawk}
+si basarono su @command{gawk} per sviluppare parecchie estensioni
+significative. Inoltre, migliorarono le capacit@`a, in @command{gawk}, di
+includere file e di accedere a oggetti condivisi.
+
+Una nuova API @`e rimasta un desiderio per lungo tempo, ma solo nel 2012
+il manutentore di @command{gawk} e gli sviluppatori di @command{xgawk}
+iniziarono finalmente a lavorare insieme. Ulteriori informazioni riguardanti
+il progetto @command{xgawk} sono forniti nella @ref{gawkextlib}.
+
+@node Obiettivi delle estensioni
+@appendixsubsec Obiettivi per un nuovo meccanismo
+
+Alcuni obiettivi per la nuova API sono:
+
+@itemize @value{BULLET}
+@item
+L'API dovrebbe essere indipendente dalla struttura interna di @command{gawk}.
+Le modifiche alla struttura interna di @command{gawk} dovrebbero essere
+irrilevanti per chi scrive una funzione di estensione.
+
+@item
+L'API dovrebbe consentire una compatibilit@`a @emph{binaria} [ossia a livello
+di codice eseguibile, e non solo a livello di codice sorgente] tra diverse
+versioni di @command{gawk}, se la stessa API rimane invariata.
+
+@item
+L'API dovrebbe consentire che le estensioni scritte in C o C++ abbiano
+all'incirca la stessa ``struttura'', per il codice awk,
+di quella che hanno le funzioni di @command{awk}. Questo vuol dire che le
+estensioni dovrebbero avere:
+
+@itemize @value{MINUS}
+@item
+La capacit@`a di accedere ai parametri delle funzioni.
+
+@item
+La capacit@`a di trasformare un parametro indefinito in un vettore
+(chiamata per riferimento [@dfn{by reference}]).
+
+@item
+La capacit@`a di creare, leggere e aggiornare variabili globali.
+
+@item
+Un accesso facile a tutti gli elementi di un vettore simultaneamente
+(``appiattimento del vettore'') in modo da poter visitare tutti gli elementi
+del vettore in una maniera semplice per un programma scritto in C.
+
+@item
+La capacit@`a di creare vettori (compresi i veri "vettori di vettori" di
+@command{gawk}).
+@end itemize
+@end itemize
+
+Alcuni ulteriori obiettivi rilevanti sono:
+
+@itemize @value{BULLET}
+@item
+L'API dovrebbe usare solo funzionalit@`a disponibili nella specifica ISO C 90, in
+modo da consentire estensioni scritte con una vasta gamma di compilatori C e
+C++. L'intestazione dovrebbe includere le appropriate direttive
+@samp{#ifdef __cplusplus} e @samp{extern "C"}, in modo da poter utilizzare un
+compilatore C++. (Se si usa C++, il sistema operativo in uso dev'essere in
+grado di invocare dei costruttori e dei distruttori, poich@'e @command{gawk} @`e un
+programma scritto in C. Al momento in cui queste note sono scritte, la cosa
+non @`e stata verificata).
+
+@item
+Il meccanismo API non dovrebbe aver bisogno di accedere ai simboli di
+@command{gawk}@footnote{I @dfn{simboli} sono le variabili e le funzioni
+definite all'interno di @command{gawk}. Accedere a questi simboli da parte
+di codice esterno a @command{gawk} caricato dinamicamente al momento
+dell'esecuzione @`e problematico in ambiente MS-Windows.} da parte del
+@dfn{linker} statico, usato in fase di compilazione, o di quello dinamico,
+in modo da rendere possibile la creazione di estensioni che funzionino anche
+in ambiente MS-Windows.
+@end itemize
+
+In fase di sviluppo, @`e apparso evidente che dovevano essere disponibili alle
+estensioni anche altre funzionalit@`a, che sono state
+successivamente implementate:
+
+@itemize @value{BULLET}
+@item
+Le estensioni dovrebbero essere in grado di agganciarsi al meccanismo di
+ridirezione dell'I/O di @command{gawk}. In particolare, gli sviluppatori di
+@command{xgawk} hanno programmato un cosiddetto ``gancio aperto'' (@dfn{open
+hook}) per gestire autonomamente la lettura dei record. In fase di sviluppo,
+questo meccanismo @`e stato generalizzato, per consentire alle estensioni di
+agganciarsi sia all'elaborazione dell'input, che a quella dell'output, nonch@'e
+all'I/O bidirezionale.
+
+@item
+Un'estensione dovrebbe poter rendere disponibile una funzione di ``call back''
+(richiamo) per effettuare operazioni di pulizia all'uscita di @command{gawk}.
+
+@item
+Un'estensione dovrebbe poter rendere disponibile una stringa di versione
+cos@`{@dotless{i}} che l'opzione @option{--version}
+di @command{gawk} possa informare anche sulle versioni delle estensioni.
+@end itemize
+
+Il vincolo di evitare di accedere ai simboli di @command{gawk} pu@`o parere a
+prima vista piuttosto difficile da rispettare.
+
+Un tipo di architettura, apparentemente usato da Perl e Ruby e forse da altri
+programmi, potrebbe consistere nel mettere il codice principale di
+@command{gawk} in una libreria, limitando il programma di utilit@`a
+@command{gawk} a una piccola funzione @code{main()} in C che richiamerebbe
+dinamicamente la libreria.
+
+Questo inverte i ruoli del programma principale e della sua estensione, e
+complica sia la compilazione che l'installazione, trasformando la semplice
+copia del programma eseguibile @command{gawk} da un sistema all'altro (o da una
+posizione all'altra all'interno dello stesso sistema) in un'operazione ad alto
+rischio.
+
+Pat Rankin ha suggerito la soluzione che @`e stata adottata.
+@xref{Panoramica sul meccanismo delle estensioni}, per maggiori dettagli.
+
+@node Altre scelte progettuali per le estensioni
+@appendixsubsec Altre scelte progettuali
+
+Per una scelta progettuale arbitraria, le estensioni possono accedere ai valori
+delle variabili e dei vettori predefiniti (come @code{ARGV} e @code{FS}), ma
+non possono modificarli, con la sola eccezione di @code{PROCINFO}.
+
+Il motivo di questa scelta @`e di impedire a una funzione di estensione di
+alterare il flusso di un programma @command{awk} togliendogli il controllo.
+Mentre una vera funzione di @command{awk} pu@`o fare quel che vuole, a
+discrezione del programmatore, una funzione di estensione dovrebbe fornire un
+servizio, o rendere disponibile un'API C da utilizzare all'interno di
+@command{awk}, senza interferire con le variabili @code{FS} o @code{ARGC} e
+@code{ARGV}.
+
+Inoltre, diverrebbe facile avviarsi su un sentiero scivoloso. Quante
+funzionalit@`a di @command{gawk} dovrebbero essere disponibili alle estensioni?
+Devono poter usare @code{getline}? Oppure richiamare @code{gsub()} o compilare
+espressioni regolari? Oppure richiamare funzioni interne di @command{awk}?
+(@emph{Questo} potrebbe creare molta confusione.)
+
+Per evitare questi problemi, gli sviluppatori di @command{gawk} hanno scelto di
+iniziare con le funzionalit@`a pi@`u semplici e di base, che sono comunque
+veramente utili.
+
+Sebbene @command{gawk} consenta cose interessanti come l'MPFR,
+e vettori indicizzati internamente con numeri interi,
+un'altra decisione @`e stata quella di non rendere disponibili all'API queste
+funzionalit@`a, per amor di semplicit@`a e per restare fedeli alla tradizionale
+semantica di @command{awk}. (In effetti, i vettori indicizzati internamente
+con numeri interi sono talmente trasparenti che non sono neppure documentati!)
+
+In pi@`u, tutte le funzioni nell'API controllano che i puntatori ai parametri
+passati loro in input non siano @code{NULL}. Se lo sono, viene emesso un
+messaggio di errore. (@`E bene che il codice di estensione verifichi
+che i puntatori ricevuti da @command{gawk} non siano @code{NULL}. Ci@`o non
+dovrebbe succedere, ma gli sviluppatori di @command{gawk} sono solo degli
+esseri umani, e capita anche a loro di commettere degli errori, di tanto in
+tanto.)
+
+Col tempo, l'API si svilupper@`a certamente; gli sviluppatori di @command{gawk}
+si aspettano che questo avvenga in base alle necessit@`a degli utenti. Per ora,
+l'API disponbile sembra fornire un insieme di funzionalit@`a minimo, eppure
+potente, per creare estensioni.
+
+@node Futuri sviluppi delle estensioni
+@appendixsubsec Possibilit@`a di sviluppo futuro
+
+L'API pu@`o ancora essere ampliata, in due modi:
+
+@itemize @value{BULLET}
+@item
+@command{gawk} passa un ``identificativo di estensione'' all'estensione in fase
+di caricamente dell'estensione. L'estensione a sua volta restituisce questo
+identificativo a @command{gawk} a ogni chiamata di funzione. Questo meccanismo
+consente a @command{gawk} di identificare l'estensione che lo chiama, se la
+cosa dovesse risultare necessaria.
+
+@item
+Analogamente, l'estensione passa uno ``spazio dei nomi'' a @command{gawk}
+in fase di registrazione di ogni funzione estesa. Questo @`e fatto in vista di
+un possibile futuro meccanismo per raggruppare funzioni di estensione, e per
+evitare in questo modo possibili conflitti nei nomi di funzione.
+@end itemize
+
+Naturalmente, al momento in cui queste righe sono state scritte, nessuna
+decisione @`e stata presa riguardo ai punti sopra descritti.
+
+@node Meccanismo delle vecchie estensioni
+@appendixsec Compatibilit@`a per le vecchie estensioni
+
+@iftex
+Il
+@end iftex
+@ref{Estensioni dinamiche}, descrive le API supportate e i meccanismi
+per scrivere estensioni per @command{gawk}. Quest'API @`e stata introdotta
+nella @value{PVERSION} 4.1. Peraltro, gi@`a da molti anni @command{gawk}
+metteva a disposizione un meccanismo di estensione che richiedeva una
+familiarit@`a con la struttura interna di @command{gawk} e che non era stato
+progettato altrettanto bene.
+
+Per garantire un periodo di transizione, @command{gawk} @value{PVERSION} 4.1
+continua a supportare il meccanismo di estensione originale.
+Questo rimarr@`a disponibile per la durata di una sola versione principale.
+Il supporto cesser@`a, e sar@`a rimosso dal codice sorgente, al rilascio
+della prossima versione principale.
+
+In breve, le estensioni in stile originale dovrebbero essere compilate
+includendo il file di intestazione @file{awk.h} nel codice sorgente
+dell'estensione. Inoltre, va definito l'identificativo @samp{GAWK} durante la
+preparazione (si usi @samp{-DGAWK} con compilatori in stile Unix). Se non lo
+si fa, le definizioni in @file{gawkapi.h} risulteranno in conflitto con quelle
+in @file{awk.h} e l'estensione non sar@`a compilabile.
+
+Come nelle versioni precedenti, un'estensione vecchio stile sar@`a caricata
+usando la funzione predefinita @code{extension()} (che non viene ulteriormente
+documentata). Questa funzione, a sua volta, trova e carica il file oggetto
+condiviso che contiene l'estensione e chiama la sua routine C @code{dl_load()}.
+
+Poich@'e le estensioni in stile originale e quelle nello stile nuovo usano
+differenti routine di inizializzazione(@code{dl_load()} e @code{dlload()},
+rispettivamente), esse possono tranquillamente essere installate nella stessa
+directory (il cui nome deve essere contenuto nella variabile @env{AWKLIBPATH})
+senza problemi di conflitti.
+
+Il @dfn{team} di sviluppo di @command{gawk} raccomanda caldamente di convertire
+ogni estensione del vecchio tipo ancora in uso, in modo da utilizzare la nuova
+API descritta
+@iftex
+nel
+@end iftex
+@ifnottex
+in
+@end ifnottex
+@ref{Estensioni dinamiche}.
+
+@node Sommario delle note
+@appendixsec Sommario
+
+@itemize @value{BULLET}
+@item
+Le estensioni di @command{gawk} possono essere disabilitata sia con
+l'opzione @option{--traditional} che con l'opzione @option{--posix}.
+L'opzione @option{--parsedebug} @`e disponibile se @command{gawk} @`e stato
+compilato con @samp{-DDEBUG}.
+
+@item
+Il codice sorgente di @command{gawk} @`e conservato in un deposito Git
+pubblicamente accessibile. Tutti possono scaricarlo e visualizzare il
+codice sorgente.
+
+@item
+I contributi a @command{gawk} sono benvenuti. Seguire le istruzioni
+delineate in questo @value{CHAPTER} render@`a pi@`u agevole integrare
+i contributi degli utenti nel codice principale.
+Questo vale sia per il contributo di nuove funzionalit@`a che per il
+@dfn{porting} a ulteriori sistemi operativi.
+
+@item
+@command{gawk} ha alcuni limiti: generalmente quelli imposti
+dall'architettura hardware della macchina.
+
+@item
+La progettazione dell'estensione API @`e volta a risolvere alcuni problemi
+riscontrati nel precedente meccanismo di estensione, ad abilitare
+funzionalit@`a richieste dal progetto @code{xgawk}, e a fornire una
+compatibilit@`a binaria in futuro.
+
+@item
+Il precedente meccanismo di estensione @`e ancora supportato
+nella @value{PVERSION} 4.1
+di @command{gawk}, ma sar@`a @emph{rimosso} nella prossima versione principale.
+
+@end itemize
+
+
+@node Concetti fondamentali
+@appendix Concetti fondamentali di programmazione
+@cindex programmazione, concetti di
+@cindex programmazione, concetti di
+
+Quest'@value{APPENDIX} si propone di definire alcuni dei concetti
+e termini fondamentali usati nel resto di questo @value{DOCUMENT}.
+Poich@'e questo @value{DOCUMENT} @`e dedicato ad @command{awk},
+e non riguarda la programmazione al computer in generale, la trattazione
+@`e necessariamente piuttosto generica e semplificata.
+(Se serve qualcosa di pi@`u approfondito, ci sono molti
+altri testi introduttivi che si possono consultare.)
+
+@menu
+* Fondamenti ad alto livello:: Una visione dall'alto.
+* Fondamenti sui tipi di dati:: Una velocissima introduzione ai tipi di dati.
+@end menu
+
+@node Fondamenti ad alto livello
+@appendixsec Quel che fa un programma
+
+@cindex elaborazione dati
+Al livello pi@`u fondamentale, il compito di un programma @`e di elaborare
+alcuni dati in input e produrre dei risultati.
+@ifnotdocbook
+Si veda la @ref{figura-generica-flusso}.
+@end ifnotdocbook
+@ifdocbook
+Si veda la @inlineraw{docbook, <xref linkend="figura-generica-flusso"/>}.
+@end ifdocbook
+
+@ifnotdocbook
+@float Figura,figura-generica-flusso
+@caption{Flusso generico di un programma}
+@ifclear SMALLPRINT
+@center @image{programma-generico, , , Flusso generico di un programma}
+@end ifclear
+@ifset SMALLPRINT
+@center @image{programma-generico, 11cm, , Flusso generico di un programma}
+@end ifset
+@end float
+@end ifnotdocbook
+
+@docbook
+<figure id="figura-generica-flusso" float="0">
+<title>Flusso generico di un programma</title>
+<mediaobject>
+<imageobject role="web"><imagedata fileref="programma-generico.png" format="PNG"/></imageobject>
+</mediaobject>
+</figure>
+@end docbook
+
+@cindex programmi compilati
+@cindex programmi interpretati
+Il ``programma'' nella figura pu@`o essere sia un programma
+compilato@footnote{I programmi compilati sono normalmente scritti
+in linguaggi di programmazione di livello pi@`u basso, come C, C++, o Ada,
+e quindi tradotti, o @dfn{compilati}, in una forma che
+il computer pu@`o eseguire direttamente.}
+(come @command{ls}),
+sia un programma @dfn{interpretato}. In quest'ultimo caso, un programma
+direttamente eseguibile dal computer, come @command{awk}, legge il
+programma, e quindi usa le istruzioni in esso contenute per elaborare i dati.
+
+@cindex programmazione, passi fondamentali
+Quando si scrive un programma, esso @`e composto normalmente
+dai seguenti insiemi di istruzioni di base,
+@ifnotdocbook
+come si vede nella @ref{figura-flusso-elaborazione}:
+@end ifnotdocbook
+@ifdocbook
+come si vede nella @inlineraw{docbook, <xref linkend="figura-flusso-elaborazione"/>}:
+@end ifdocbook
+
+@ifnotdocbook
+@float Figura,figura-flusso-elaborazione
+@caption{Fasi di un programma generico}
+@ifclear SMALLPRINT
+@center @image{flusso-elaborazione, , , Fasi di un programma generico}
+@end ifclear
+@ifset SMALLPRINT
+@center @image{flusso-elaborazione, 11cm , , Fasi di un programma generico}
+@end ifset
+@end float
+@end ifnotdocbook
+
+@docbook
+<figura id="figura-flusso-elaborazione" float="0">
+<title>Fasi di un programma generico</title>
+<mediaobject>
+<imageobject role="web"><imagedata fileref="flusso-elaborazione.png" format="PNG"/></imageobject>
+</mediaobject>
+</figure>
+@end docbook
+
+@table @asis
+@item Inizializzazione
+Queste sono le cose da fare prima di iniziare la reale elaborazione dei
+dati, per esempio controllare gli argomenti con cui @`e stato invocato il
+programma, inizializzare dei dati di cui si potr@`a aver bisogno per la
+successiva elaborazione, e cos@`{@dotless{i}} via.
+Questa fase corrisponde alla regola @code{BEGIN} di @command{awk}
+(@pxref{BEGIN/END}).
+
+Nella preparazione di una torta, questa fase corrisponde a quella di
+tirar fuori tutti i contenitori in cui mischiare gli ingredienti, e la
+teglia in cui cuocerla, e nell'assicurarsi di avere a disposizione tutti gli
+ingredienti necessari.
+
+@item Elaborazione
+Questa fase @`e quella in cui si svolge il lavoro vero e proprio. Il programma
+legge i dati, raggruppati in ``pezzi logici'', e li elabora secondo necessit@`a.
+
+In quasi tutti i linguaggi di programmazione, la lettura dei dati va gestita
+manualmente, controllando dopo ogni lettura se @`e
+rimasto ancora qualcosa d'altro da leggere. Il paradigma @dfn{criterio di
+ricerca--azione} di @command{awk}
+@iftex
+(@pxrefil{Per iniziare})
+@end iftex
+@ifnottex
+(@pxref{Per iniziare})
+@end ifnottex
+gestisce automaticamente la parte di lettura dati.
+
+Nella preparazione di una torta, l'elaborazione corrisponde all'attivit@`a
+vera e propria: rompere le uova, mescolare la farina, l'acqua e gli altri
+ingredienti, e quindi mettere la torta a cuocere nel forno.
+
+@item Pulizia
+Una volta elaborati tutti i dati, ci sono attivit@`a da svolgere prima di aver
+finito. Questa fase corrisponde alla regola @code{END} di @command{awk}.
+(@pxref{BEGIN/END}).
+
+Dopo che la torta @`e stata tirata fuori dal forno, va fatta raffreddare e
+avvolta in una pellicola trasparente per evitare che qualcuno la assaggi,
+e inoltre vanno lavati i contenitori e le posate.
+@end table
+
+@cindex Algoritmi
+Un @dfn{algoritmo} @`e la descrizione dettagliata della procedura necessaria per
+svolgere un compito o per elaborare dati. Lo si pu@`o paragonare alla ricetta
+per preparare una torta. I programmi sono il modo con cui un
+algoritmo viene eseguito da un computer.
+Spesso @`e compito del programmatore sia sviluppare un algoritmo, sia
+programmarlo.
+
+@cindex record
+@cindex campi
+I ``pezzi logici'' nominati precedentemente sono chiamati @dfn{record}
+(registrazioni), in analogia con le registrazioni del personale di una ditta,
+degli studenti di una scuola, o dei pazienti di un dottore.
+Ogni record @`e composto di molte parti, per esempio nome, cognome, data di
+nascita, indirizzo, e cos@`{@dotless{i}} via. Le parti di cui @`e composto un record sono
+chiamate @dfn{campi} del record.
+
+L'atto di leggere i dati @`e noto come @dfn{input}, e quello di generare
+risultati @`e, come facilmente prevedibile, chiamato @dfn{output}. Spesso i due
+sono riuniti sotto il nome di ``input/output'' e, ancor pi@`u spesso, con
+l'abbreviazione ``I/O''. (In inglese ``input'' e ``output'' sono spesso usati
+come verbi, nel gergo informatico, al posto di leggere e scrivere.)
+
+@cindex guidato-dai-dati, linguaggio di programmazione
+@cindex linguaggio di programmazione, guidato dai dati
+@command{awk} gestisce la lettura dei dati, come anche la divisione in
+record e campi. Lo scopo del programma dell'utente @`e di dire ad @command{awk}
+cosa fare con i dati. Questo vien fatto descrivendo @dfn{modelli} da
+ricercare nei dati e @dfn{azioni} da eseguire qualora si siano trovati questi
+modelli. Questa caratteristica dei programmi @command{awk}, di essere
+@dfn{guidati-dai-dati}, di solito li rende pi@`u facili sia da scrivere che da
+leggere.
+
+@node Fondamenti sui tipi di dati
+@appendixsec Valore dei dati in un computer
+
+@cindex variabili
+In un programma si tiene traccia di informazioni e valori in contenitori
+chiamati @dfn{variabili}. Una variabile @`e solo un nome per designare un certo
+valore, come @code{nome}, @code{cognome}, @code{indirizzo}, e cos@`{@dotless{i}} via.
+@command{awk} ha molte variabili predefinite, e ha dei nomi speciali per
+designare il record in input corrente e i campi che compongono il record
+stesso. Si possono inoltre raggruppare molti valori associati tra di loro
+sotto un unico nome, utilizzando un vettore.
+
+@cindex valori numerici
+@cindex valori tipo stringa
+@cindex valori scalari
+@cindex scalari, valori
+I dati, in particolare in @command{awk}, possono avere valori numerici, come 42
+o 3.1415927, o avere come valore delle stringhe. Un valore di tipo stringa @`e
+essenzialmente qualsiasi cosa che non sia un numero, per esempio un nome. Le
+stringhe sono talora chiamate @dfn{dati di tipo carattere}, poich@'e memorizzano
+i singoli caratteri che le formano. Le singole variabili, come pure le
+variabili numeriche e di tipo stringa, sono definite come valori
+@dfn{scalari}. Raggruppamenti di valori, come i vettori, non sono scalari.
+
+@iftex
+La
+@end iftex
+@ref{Aritmetica del computer}, ha fornito un'introduzione di base ai tipi
+numerici (interi e a virgola mobile) e a come questi sono usati in un computer.
+Si consiglia di rileggere quelle informazioni, comprese le numerose avvertente
+l@`a esposte.
+
+@cindex stringhe nulle
+Mentre @`e probabile che ci si sia abituati all'idea di un numero senza un valore
+(cio@`e, allo zero), richiede un po' pi@`u di riflessione abituarsi all'idea di
+dati di tipo carattere a lunghezza zero. Nonostante ci@`o, questo tipo di dato
+esiste. @`E chiamato @dfn{stringa nulla}. La stringa nulla @`e un dato di tipo
+carattere che non ha un valore. In altre parole, @`e vuoto. Si scrive cos@`{@dotless{i}} nei
+programmi @command{awk}: @code{""}.
+
+Gli esseri umani sono abituati a usare il sistema decimale, cio@`e a base 10.
+In base 10, i numeri vanno da 0 a 9, e poi ``vengono riportati'' nella
+colonna successiva. (Chi si ricorda la scuola elementare? 42 = 4 x 10 + 2.)
+
+Ma esistono anche altre basi per i numeri. I computer normalmente usano
+la base 2 o @dfn{binaria}, la base 8 o @dfn{ottale}, e la base 16 o
+@dfn{esadecimale}. Nella numerazione binaria, ogni colonna rappresenta il
+doppio del valore della colonna alla sua destra. Ogni colonna pu@`o contenere
+solo uno 0 o un 1. Quindi, il numero binario 1010 rappresenta (1 x 8) + (0 x
+4) + (1 x 2) + (0 x 1), ossia il numero decimale 10. Le numerazioni ottale ed
+esadecimale sono trattate pi@`u ampiamente
+@ifnottex
+in
+@end ifnottex
+@iftex
+nella
+@end iftex
+@ref{Numeri non-decimali}.
+
+Al livello pi@`u basso possibile, i computer memorizzano i valori come gruppi di
+cifre binarie, o @dfn{bit}. I computer moderni raggruppano i bit in gruppi di
+otto, detti @dfn{byte}. Applicazioni avanzate talora hanno necessit@`a di
+manipolare i bit direttamente, e @command{gawk} @`e dotato di apposite funzioni.
+
+I programmi sono scritti nei linguaggi di programmazione. Esistono centinaia,
+se non migliaia, di linguaggi di programmazione. Uno dei pi@`u diffusi @`e il
+linguaggio di programmazione C. Il linguaggio C ha esercitato un'influsso
+molto forte nella progettazione del linguaggio @command{awk}.
+
+@cindex Kernighan, Brian
+@cindex Ritchie, Dennis
+Ci sono state parecchie versioni di C. La prima @`e spesso designata come
+``K&R'' C, dalle iniziali di Brian Kernighan e Dennis Ritchie,
+gli autori del primo libro sul C. (Dennis Ritchie ha creato il linguaggio,
+e Brian Kernighan @`e stato uno dei creatori di @command{awk}.)
+
+A met@`a degli anni '80 @`e iniziato uno sforzo rivolto a produrre uno
+standard internazionale per il C. Questo lavoro ha raggiunto un punto di
+arrivo nel 1989 con la produzione dello standard ANSI per il C.
+Questo standard @`e diventato uno standard ISO nel 1990.
+Nel 1999, uno standard ISO C revisionato @`e stato approvato e pubblicato.
+Dove @`e opportuno, POSIX @command{awk} @`e compatible con lo standard
+ISO C del 1999.
+
+
+@node Glossario
+@unnumbered Glossario
+
+@table @asis
+@item Abbraccio mortale
+La situazione in cui due processi che comunicano tra loro sono entrambi bloccati, in
+attesa che l'altro processo faccia qualcosa.
+
+@cindex Ada, linguaggio di programmazione
+@cindex linguaggio di programmazione, Ada
+@item Ada
+Un linguaggio di programmazione originalmente definito dal Department of
+Defense U.S.A.@: per la programmazione integrata. @`E stato progettato per
+favorire dei buoni metodi da seguire nell'ingegneria del software.
+
+@item Ambiente
+Si veda ``Variabili d'ambiente''.
+
+@item @`Ancora
+I metacaratteri @dfn{regexp} @samp{^} e @samp{$}, che richiedono che la
+corrispondenza che si sta cercando si trovi all'inizio o alla fine di una
+stringa, rispettivamente.
+
+@cindex angolo buio
+@item Angolo buio
+Un'area del linguaggio le cui specifiche spesso non erano (o ancora non
+sono) chiare, col risultato di ottenere un comportamente inatteso o non
+desiderabile.
+Tali aree sono segnalate in questo @value{DOCUMENT} con
+@iftex
+il disegno di una torcia a margine
+@end iftex
+@ifnottex
+``(a.b.)'' nel testo
+@end ifnottex
+e sono riportate nell'indice analitico sotto la voce ``angolo buio''.
+
+@cindex ANSI
+@item ANSI
+L'American National Standards Institute. Questo ente produce
+parecchi standard, e tra questi gli standard per i linguaggi di
+programmazione C e C++.
+Questi standard spesso diventano anche internazionali. Si veda anche
+``ISO''.
+
+@item Argomento
+Un argomento pu@`o essere due cose differenti. Pu@`o essere un'opzione o un
+@value{FN} passato a un comando mentre lo si invoca dalla riga dei comandi,
+oppure pu@`o essere qualcosa passato a una @dfn{funzione} all'interno di un
+programma, per esempio all'interno di @command{awk}.
+
+In quest'ultimo caso, un argomento pu@`o essere passato a una funzione in
+due modi. Nel primo modo @`e passato come valore alla funzione chiamata,
+ossia una copia del valore della variabile @`e reso disponibile alla funzione
+chiamata, ma la variabile originale non pu@`o essere modificata dalla
+funzione stessa. Nel secondo modo l'argomento @`e passato per riferimento,
+ossia un puntatore alla variabile in questione @`e passato alla funzione, che
+pu@`o quindi modificarla direttamente. In @command{awk} le variabili scalari
+sono passate per valore, e i vettori sono passati per riferimento.
+Si veda ``Passaggio per valore/riferimento''.
+
+@item Arrotondamento
+Arrotondare il risultato di un'operazione aritmetica pu@`o essere difficile.
+C'@`e pi@`u di un modo di arrotondare, e in @command{gawk} @`e possibile scegliere
+quale metodo dovrebbe essere usato all'interno di un programma.
+@xref{Impostare modi di arrotondare}.
+
+@item Assegnamento
+Un'espressione @command{awk} che cambia il valore di qualche variabile o
+dato oggetto di @command{awk}. Un oggetto a cui si pu@`o assegnare un valore
+@`e detto un @dfn{lvalue}. I valori
+assegnati sono chiamati @dfn{rvalue}.
+@xref{Operatori di assegnamento}.
+
+@cindex Spencer, Henry
+@cindex @command{sed}, programma di utilit@`a
+@cindex programma di utilit@`a @command{sed}
+@cindex incredibile assembler (@command{aaa}) scritto in @command{awk}
+@item Assembler incredibilmente scritto in @command{awk}
+Henry Spencer dell'Universit@`a di Toronto ha scritto un assembler adatto a
+molti diversi hardware, usando solo @dfn{script} @command{sed} e
+@command{awk}. @`E lungo migliaia di righe, e include
+la descrizione dell'hardware di
+numerosi micro-computer a 8 bit. @`E un
+buon esempio di programma per cui sarebbe stato
+meglio utilizzare un altro linguaggio.
+Si pu@`o scaricare da @uref{http://awk.info/?awk100/aaa}.
+
+@item Asserzione
+Un'istruzione in un programma che afferma che una condizione @`e verificata in
+un dato punto di un programma.
+Utile per ragionare su come si suppone funzioni un programma.
+
+@item Azione
+Una serie di istruzioni @command{awk} associate a una regola. Se
+l'espressione di ricerca della regola individua un record in input,
+@command{awk} esegue su quel record l'azione relativa. Le azioni sono
+sempre racchiuse tra parentesi graffe.
+(@xref{Panoramica sulle azioni}).
+
+@item Bash
+La versione GNU della shell standard
+@ifnotinfo
+(il @b{B}ourne-@b{A}gain @b{SH}ell).
+@end ifnotinfo
+@ifinfo
+(il Bourne-Again SHell).
+@end ifinfo
+Si veda anche ``Bourne Shell''.
+
+@item Binario
+Notazione a base due, che usa le cifre @code{0}--@code{1}. Poich@'e
+i circuiti elettronici funzionano ``naturalmente'' in base 2
+(basta pensare a Off/On), ogni cosa all'interno di un computer @`e
+calcolata usando la base 2. Ciascuna cifra rappresenta la presenza
+(o l'assenza) di una potenza di 2 ed @`e chiamata un @dfn{bit}.
+Cos@`{@dotless{i}}, per esempio, il numero in base due @code{10101} rappresenta il
+numero in base decimale 21, ((1 x 16) + (1 x 4) + (1 x 1)).
+
+Poich@'e i numeri in base due diventano rapidamente molto lunghi
+sia da leggere che da scrivere, normalmente li si unisce a gruppi di tre
+(ossia, sono visti come numeri ottali) o a gruppi di quattro (ossia, sono
+visti come numeri esadecimali). Non c'@`e un modo diretto per inserire
+numeri a base due in un programma C. Se necessario, tali numeri vengono
+solitamente inseriti come numeri ottali o esadecimali.
+Il numero di cifre in base due contenuto nei registri usati per
+rappresentare i numeri interi all'interno dei computer @`e un'indicazione
+approssimativa della potenza di calcolo del computer stesso. La maggior
+parte dei computer oggi usa 64 bit per rappresentare i numeri interi nei
+registri di calcolo, ma registri a 32 bit, 16 bit e 8 bit sono stati
+largamente in uso in passato.
+@xref{Numeri non-decimali}.
+
+@cindex McIlroy, Doug
+@cindex biscotto della fortuna
+@item Biscotto della fortuna
+Una particolare perla di saggezza, segno, detto o ricordo
+prodotto da (o presentato a) un programma. (Con vivi ringraziamenti al Prof.
+Doug McIlroy).
+@ignore
+From: Doug McIlroy <doug@cs.dartmouth.edu>
+Date: Sat, 13 Oct 2012 19:55:25 -0400
+To: arnold@skeeve.com
+Subject: Re: origin of the term "cookie"?
+
+I believe the term "cookie", for a more or less inscrutable
+saying or crumb of information, was injected into Unix
+jargon by Bob Morris, who used the word quite frequently.
+It had no fixed meaning as it now does in browsers.
+
+The word had been around long before it was recognized in
+the 8th edition glossary (earlier editions had no glossary):
+
+cookie a peculiar goodie, token, saying or remembrance
+returned by or presented to a program. [I would say that
+"returned by" would better read "produced by", and assume
+responsibility for the inexactitude.]
+
+Doug McIlroy
+
+From: Doug McIlroy <doug@cs.dartmouth.edu>
+Date: Sun, 14 Oct 2012 10:08:43 -0400
+To: arnold@skeeve.com
+Subject: Re: origin of the term "cookie"?
+
+> Can I forward your email to Eric Raymond, for possible addition to the
+> Jargon File?
+
+Sure. I might add that I don't know how "cookie" entered Morris's
+vocabulary. Certainly "values of beta give rise to dom!" (see google)
+was an early, if not the earliest Unix cookie. The fact that it was
+found lying around on a model 37 teletype (which had Greek beta in
+its type box) suggests that maybe it was seen to be like milk and
+cookies laid out for Santa Claus. Morris was wont to make such
+connections.
+
+Doug
+@end ignore
+
+@item Bit
+Abbreviazione di ``Binary Digit'' [cifra binaria].
+Tutti i valori nella memoria di un computer sono rappresentati nella forma di
+cifre binarie: valori che sono zero o uno.
+Gruppi di bit possono essere interpretati differentemente---come numeri
+interi, numeri a virgola mobile, dati di tipo carattere, indirizzi di altri
+oggetti contenuti in memoria, o altri dati ancora.
+@command{awk} permette di lavorare con numeri a virgola mobile e stringhe.
+@command{gawk} permette di manipolare bit con le funzioni predefinite
+descritte
+@ifnottex
+in
+@end ifnottex
+@iftex
+nella
+@end iftex
+@ref{Funzioni a livello di bit}.
+
+I computer sono spesso definiti dal numero di bit che usano per rappresentare
+valori interi. Molti sistemi sono a 32-bit, ma i sistemi a 64-bit sono sempre
+pi@`u numerosi, mentre i sistemi a 16-bit [e quelli a 8-bit] sono praticamente
+scomparsi.
+
+@item Bourne Shell
+La shell standard (@file{/bin/sh}) in Unix e nei sistemi derivati da Unix,
+Originariamente scritto da Steven R.@: Bourne dei Bell Laboratories.
+Molte shell (Bash, @command{ksh}, @command{pdksh}, @command{zsh}) sono
+generalmente compatibili con la Bourne shell, anche quando offrono ulteriori
+funzionalit@`a.
+
+@item C
+Il linguaggio di programmazione di sistema con cui @`e scritta la maggior parte
+del software GNU. Il linguaggio di programmazione @command{awk} ha una
+sintassi simile a quella del C, e
+questo @value{DOCUMENT} puntualizza, quando serve, le somiglianze esistenti
+fra @command{awk} e C.
+
+In generale, @command{gawk} tenta di essere ragionevolmente simile alla
+versione 1990 del C ISO.
+
+@item C Shell
+La C Shell (@command{csh} o la sua versione migliorata @command{tcsh}) @`e una
+shell Unix creata da Bill Joy verso la fine degli anni '70. La C shell si
+differenzia dalla altre shell per le sue funzionalit@`a interattive, e per lo
+stile complessivo, che @`e abbastanza simile a quello del linguaggio C.
+La C shell non @`e compatibile all'indietro con la Bourne Shell, e per questo
+motivo un'attenzione speciale @`e necessaria se si convertono alla C shell
+degli script scritti per altre shell Unix, in particolare per ci@`o che
+concerne la gestione delle variaili di shell.
+Si veda anche ``Bourne Shell''.
+
+@item C++
+Un linguaggio di programmazione molto diffuso, orientato agli oggetti,
+derivato dal C.
+
+@item Campo
+Quando @command{awk} legge un record in input, suddivide il record in parti
+separate da spazi vuoti (o da una @dfn{regexp} che individua il separatore,
+modificabile reimpostando la variabile predefinita @code{FS}). Tali parti
+sono dette campi. Se le parti sono di lunghezza fissa, si pu@`o usare la
+variabile predefinita @code{FIELDWIDTHS} per descriverne le lunghezze.
+Se si desidera specificare i contenuti dei campi, piuttosto che il separatore
+fra i campi, si pu@`o usare la variabile predefinita @code{FPAT} per farlo.
+(@xref{Separatori di campo},
+@iftex
+la
+@end iftex
+@ref{Dimensione costante},
+e
+@iftex
+la
+@end iftex
+@ref{Separazione in base al contenuto}).
+
+@cindex ASCII
+@cindex ISO 8859-1
+@cindex ISO Latin-1
+@cindex caratteri (codifiche macchina di caratteri)
+@cindex insiemi di caratteri (codifiche macchina di caratteri)
+@cindex Unicode
+@item Caratteri
+L'insieme di codici numerici usati da un computer per rappresentare i
+caratteri (lettere, numeri, segni d'interpunzione, etc.) di un particolare
+paese o localit@`a. L'insieme di caratteri pi@`u comunemente in uso oggi @`e
+l'ASCII (American Standard Code for Information Interchange). Molti paesi
+europei usano un'estensione dell'ASCII
+nota come ISO-8859-1 (ISO Latin-1).
+L'insieme di caratteri @uref{http://www.unicode.org, Unicode} sta guadagnando
+popolarit@`a e affermandosi come standard, e il suo uso @`e particolarmente esteso
+nei sistemi GNU/Linux.
+
+@cindex Kernighan, Brian
+@cindex Bentley, Jon
+@cindex @command{chem}, programma di utilit@`a
+@cindex programma di utilit@`a @command{chem}
+@item CHEM
+Un preprocessore per @command{pic} che legge descrizioni di molecole
+e produce l'input a @command{pic} che serve a disegnarle.
+@`E stato scritto in @command{awk}
+da Brian Kernighan e Jon Bentley, ed @`e disponibile in
+@uref{http://netlib.org/typesetting/chem}.
+
+@item Classe di caratteri
+Si veda ``Espressione tra parentesi quadre''.
+
+@cindex programmi compilati
+@item Compilatore
+Un programma che traduce codici sorgente scritti in qualche linguaggio
+in codici eseguibili su un particolare computer. Il codice oggetto risultante
+pu@`o quindi essere eseguito direttamente dal computer.
+Si veda anche ``Interprete''.
+
+@item Concatenazione
+Concatenare due stringhe significa unirle, producendo una nuova stringa.
+Per esempio, la stringa @samp{pippo} concatenata con
+la stringa @samp{pluto} produce la stringa @samp{pippopluto}.
+(@xref{Concatenazione}).
+
+@item Contatore di riferimenti
+Un meccanismo interno di @command{gawk} per minimizzare la quantit@`a di
+memoria necessaria per contenere il valore delle variabili di tipo
+stringa. Se il valore assunto da una variabile @`e usato in pi@`u di un
+posto nel programma, solo una copia del valore stesso @`e tenuta in
+memoria, e il contatore di riferimenti ad esso associato @`e aumentato di
+uno quando lo stesso valore @`e usato da un'ulteriore variabile, e diminuito
+di uno quando la variabile relativa non @`e pi@`u utilizzata. Quando il
+contatore di riferimenti va a zero, la parte di memoria utilizzata per
+contenere il valore della variuabile @`e liberato.
+
+@item Coprocesso
+Un programma subordinato con il quale @`e possibile una comunicazione
+bidirezionale dal programma principale.
+
+@item Dati oggetto
+Sono costituiti da numeri e stringhe di caratteri. I numeri sono convertiti
+in stringhe e viceversa, a seconda delle necessit@`a.
+(@xref{Conversione}).
+
+@item Debugger
+Un programma che serve agli sviluppatori per rimuovere ``bug'' (de-bug) dai
+loro programmi.
+
+@item Dominio di testo
+Un nome unico che identifica un'applicazione.
+Usato per raggruppare messaggi che sono tradotti in fase di esecuzione
+nel linguaggio locale.
+
+@item Doppia precisione
+Una rappresentazione di numeri all'interno del computer che ha una parte
+espressa sotto forma di frazione. I numeri a doppia precisione hanno pi@`u
+cifre decimali che quelli a singola precisione, ma le operazioni che la
+usano consumano pi@`u risorse di quelle
+eseguite in singola precisione. La doppia precisione @`e il formato con cui
+@command{awk} memorizza i valori numerici. Nel linguaggio C @`e il tipo di
+dati detto @code{double}.
+
+@item Editore di flusso
+Un programma che legge record da un flusso in input e li elabora uno o
+pi@`u alla volta. Questo @`e diverso da quel che farebbe un programma batch
+il quale potrebbe leggere completamente i file in input, prima di
+iniziare a fare alcunch@'e, ed @`e diverso anche da un programma interattivo, che
+richiede input dall'utente [tipicamente, una riga alla volta].
+
+@item Effetto collaterale
+Un effetto collaterale ha luogo quando un'espressione ha un effetto ulteriore,
+invece di produrre solo un valore. Espressioni di assegnamento,
+incremento e decremento, e invocazioni di funzioni hanno effetti collaterali.
+(@xref{Operatori di assegnamento}).
+
+@cindex epoch, definizione di
+@item Epoca [Inizio del tempo in Unix]
+la data usata come ``inizio del tempo'' per i campi che contengono date.
+I valori del tempo nella maggior parte dei dei sistemi sono rappresentati
+in numero di secondi trascorsi dall'Epoca, con funzioni di libreria
+che consentono di convertire tali valori nei formati normali di data e ora.
+
+L'Epoca nei sistemi Unix e POSIX parte dal primo gennaio 1970 alle ore
+00:00:00 UTC.
+Si veda anche ``GMT'' e ``UTC''.
+
+@item Esadecimale
+Notazione per l'aritmetica in base 16, che usa le cifre @code{0}--@code{9} e
+le lettere @code{A}--@code{F}, con @samp{A}
+che rappresenta 10, @samp{B} che rappresenta 11, e cos@`{@dotless{i}} via, fino a
+@samp{F} per 15.
+I numeri esadecimali sono scritti in C prefissandoli con @samp{0x},
+per indicarne la base. Quindi, @code{0x12} @`e 18 ((1 x 16) + 2).
+@xref{Numeri non-decimali}.
+
+@item Espressione booleana
+Cos@`{@dotless{i}} detta dal nome del matematico inglese George Boole.
+Si veda anche ``Espressione logica''.
+
+@item Espressione condizionale
+Un'espressione che usa l'operatore ternario @samp{?:}, come p.es.
+@samp{@var{expr1} ? @var{expr2} : @var{expr3}}. Dell'espressione
+@var{expr1} viene calcolato il valore; se risulta verificata, il valore
+dell'intera espressione diviene quello di @var{expr2}; altrimenti il valore @`e
+quello di @var{expr3}. In ogni caso, solo una delle due espressioni
+@var{expr2} e @var{expr3}
+viene calcolata. (@xref{Espressioni condizionali}).
+
+@item Espressione di confronto
+Una relazione che @`e vera o falsa, del tipo di @samp{a < b}.
+Espressioni di confronto sono usate nelle istruzioni
+@code{if}, @code{while}, @code{do}, @code{for}
+e nelle espressioni di ricerca per scegliere quale record in input elaborare.
+(@xref{Tipi di variabile e confronti}).
+
+@item Espressione di intervallo
+Una parte di un'espressione regolare che permette di specificare
+corrispondenze multiple di qualche parte della @dfn{regexp}. Le espressioni di
+intervallo non erano originariamente ammesse nei programmi @command{awk}.
+
+@item Espressione di ricerca [@dfn{pattern}]
+@itemx (detta anche "criterio di ricerca" o "modello di ricerca")
+Le espressioni di ricerca individuano per @command{awk} a quali record in
+input sono applicabili determinate
+regole.
+
+Un'espressione di ricerca [pattern] @`e un'espressione condizionale specifica
+che viene confrontata con ogni record
+in input. Se la corrispondenza esiste, si dice che il modello @dfn{individua}
+il record in input. Una tipica espressione di ricerca potrebbe confrontare
+il record in input con un'espressione regolare.
+(@xref{Panoramica sui criteri di ricerca}).
+
+@item Espressione logica
+Un'espressione che usa gli operatori logici AND, OR e NOT,
+scritti come @samp{&&}, @samp{||}, e @samp{!} in @command{awk}.
+Spesso chiamate espressioni booleane, dal nome del matematico che per primo
+ha sistematizzato questo tipo di logica matematica.
+
+@item Espressione regolare
+un'espressione regolare (abbreviabile come ``@dfn{regexp}'') @`e un modello che
+descrive un assieme di stringhe, potenzialmente illimitato. Per esempio
+l'espressione regolare
+@samp{R.*xp} corrisponde a qualsiasi stringa che inizia con la lettera
+@samp{R} e termina con le lettere @samp{xp}. In @command{awk}, le espressioni
+regolari sono usate nei modelli [pattern] e nelle espressioni condizionali.
+Le espressioni regolari possono contenere sequenze di protezione.
+@iftex
+(@xrefil{Espressioni regolari}).
+@end iftex
+@ifnottex
+(@xref{Espressioni regolari}).
+@end ifnottex
+
+@item Espressione regolare calcolata
+Si veda ``Espressioni regolari dinamiche''.
+
+@item Espressione regolare costante
+Un'espressione regolare costante @`e un'espressione regolare scritta tra barre,
+come @code{/pippo/}. A una tale espressione viene assegnato un valore quando
+si scrive un programma @command{awk} e non pu@`o essere modificata in fase di
+esecuzione del programma. (@xref{Uso di @dfn{regexp}}.)
+
+@item Espressione regolare dinamica
+Un'espressione regolare dinamica @`e un'espressione regolare scritta come
+un'espressione normale. Potrebbe essere una costante stringa, come
+@code{"pippo"}, ma potrebbe anche essere un'espressione il cui valore @`e variabile
+(@xref{Espressioni regolari calcolate}).
+
+@item Espressione tra parentesi quadre
+All'interno di una @dfn{espressione regolare}, un'espressione racchiusa
+fra parentesi quadre sta a indicare che un singolo carattere appartiene
+a una specifica classe di caratteri. Un'espressione tra parentesi quadre
+pu@`o contenere una lista di uno o pi@`u caratteri, come @samp{[abc]}, un
+intervallo di caratteri, come @samp{[A-Z]}, o un nome, delimitato da
+@samp{:}, che designa un insieme di caratteri conosciuto, come
+@samp{[:digit:]}. La forma di espressione tra parentesi quadre
+racchiusa tra @samp{:} @`e indipendente dalla rappresentazione binaria dei
+caratteri stessi, che potrebbe utilizzare le codifiche ASCII, EBCDIC, o
+Unicode, a seconda dell'architettura del computer, e della localizzazione.
+Si veda anche ``Espressioni regolari''.
+
+@item Espressione tra parentesi quadre complementata
+La negazione di una @dfn{espressione tra parentesi quadre}. Tutto ci@`o che
+@emph{non} @`e descritto da una data espressione tra parentesi quadre.
+Il simbolo @samp{^} precede l'espressione tra parentesi quadre che viene
+negata. Per esempio: @samp{[[^:digit:]}
+designa qualsiasi carattere che non sia una cifra. @samp{[^bad]}
+designa qualsiasi carattere che non sia una delle lettere @samp{b}, @samp{a},
+o @samp{d}.
+Si veda ``Espressione tra parentesi quadre''.
+
+@item Estensione
+Una funzionalit@`a aggiunta o una modifica a un linguaggio di programmazione
+o a un programma di utilit@`a, non definita dallo standard di quel linguaggio
+o di quel programma di utilit@`a.
+@command{gawk} ha molte estensioni rispetto al POSIX @command{awk} (fin
+troppe).
+
+@item FDL
+Free Documentation License. Si veda ``Licenza Documentazione Libera''.
+
+@item File speciale
+Un @value{FN} interpretato internamente da @command{gawk}, invece che
+gestito direttamente dal sistema operativo in cui viene eseguito
+@command{gawk}---per esempio, @file{/dev/stderr}.
+(@xref{File speciali}).
+
+@item Flag [Indicatore]
+Una variabile [di tipo booleano] che, se verificata, indica la presenza o
+l'assenza di qualche condizione.
+
+@item Formato
+Le stringhe di formato controllano il modo in cui le funzioni
+@code{strftime()}, @code{sprintf()} e l'istruzione @code{printf} visualizzano
+l'output che producono. Inoltre, le conversioni da numeri a stringhe sono
+controllate dalle stringhe di formato contenute nelle variabili predefinite
+@code{CONVFMT} e @code{OFMT}. (@xref{Lettere di controllo}).
+
+@cindex formattatore incredibilmente duttile (@command{awf})
+@cindex programma @command{awf} (formattatore incredibilmente duttile)
+@item Formattatore incredibilmente duttile (@command{awf})
+Henry Spencer all'Universit@`a di Toronto ha scritto un formattatore che
+accetta un ampio sottoassieme dei comandi di formattazione @samp{nroff -ms}
+e @samp{nroff -man} usando
+@command{awk} e @command{sh}.
+Si pu@`o scaricare da @uref{http://awk.info/?tools/awf}.
+
+@item Fortran
+Abbreviazione di FORmula TRANslator (traduttore di formule), @`e uno dei primi
+linguaggi di programmazione, pensato per il calcolo scientifico.
+@`E stato ideato da John Backus ed @`e disponibile a partire dal 1957. @`E ancora
+in uso ai giorni nostri.
+
+@cindex FSF (Free Software Foundation)
+@cindex Free Software Foundation (FSF)
+@cindex Stallman, Richard
+@item Free Software Foundation
+Un'organizzazione senza fini di lucro dedicata alla
+produzione e distribuzione di software liberamente distribuibile.
+@`E stata fondata da Richard M.@: Stallman, l'autore dell'originale editor
+Emacs. GNU Emacs @`e la versione di Emacs maggiormente usata oggigiorno.
+
+@item FSF
+Si veda ``Free Software Foundation''.
+
+@item Funzione
+Una parte di un programma @command{awk} che si pu@`o chiamare da qualsiasi
+punto del programma, per eseguire un compito. @command{awk} ha parecchie
+funzioni predefinite.
+Gli utenti possono definire essi stessi delle funzioni in qualsiasi parte
+del programma. Le funzioni possono essere ricorsive, ossia possono
+chiamare se stesse.
+@iftex
+@xrefil{Funzioni}.
+@end iftex
+@ifnottex
+@xref{Funzioni}.
+@end ifnottex
+In @command{gawk} @`e anche possibile avere funzioni condivise tra diversi
+programmi, incluse secondo necessit@`a usando la direttiva
+@code{@@include}
+(@pxref{Includere file}).
+In @command{gawk} il nome della funzione da chiamare pu@`o essere generato
+in fase di esecuzione, ossia in maniera dinamica.
+L'estensione API di @command{gawk} fornisce funzioni di costruzione
+(@pxref{Funzioni di costruzione}).
+
+@item Funzioni predefinite
+Il linguaggio @command{awk} fornisce funzioni predefinite, che compiono
+calcoli vari, di tipo numerico, di input/output e di tipo carattere. Esempi
+sono @code{sqrt()} ([square root], la radice quadrata di un numero) e
+@code{substr()} (che estrae una sottostringa da una stringa).
+@command{gawk} fornisce funzioni per la gestione di data e ora,
+le operazioni a livello di bit, l'ordinamento di
+vettori, il controllo di tipo [di variabile] e la traduzione di stringhe
+in fase di esecuzione di progranna.
+(@xref{Funzioni predefinite}).
+
+@item @command{gawk}
+L'implementazione GNU di @command{awk}.
+
+@cindex GPL (General Public License)
+@cindex General Public License (GPL)
+@cindex GNU General Public License
+@item General Public License
+Un documento che descrive le condizioni alle quali @command{gawk} e i suoi
+file sorgenti possono essere distribuiti. (@xref{Copia}).
+
+@item GMT
+``Greenwich Mean Time''.
+Il termine tradizionalmente usato per UTC.
+@`E la datazione usata internamente dai sistemi Unix e POSIX.
+Si veda anche ``Epoca'' e ``UTC''.
+
+@cindex FSF (Free Software Foundation)
+@cindex Free Software Foundation (FSF)
+@cindex Progetto GNU
+@item GNU
+``GNU's not Unix'' (GNU non @`e Unix).
+Un progetto della Free Software Foundation, ancora in corso, che mira a creare
+un ambiente di calcolo completo, liberamente distribuibile, aderente allo
+standard POSIX.
+
+@item GNU/Linux
+Una variante del sistema GNU che usa il kernel Linux,
+invece del kernel proprio della Free Software Foundation, noto come Hurd.
+Il kernel Linux @`e un clone di Unix stabile, efficiente, completo di tutte le
+funzionalit@`a, ed @`e stato portato su varie architetture hardware.
+@`E molto diffuso su sistemi del tipo dei Personal Computer, ma funziona bene
+anche in parecchi altri computer.
+Il codice sorgente del kernel Linux @`e disponibile nei termini della GNU General
+Public License, la qual cosa @`e forse il suo aspetto pi@`u rilevante.
+
+@item GPL
+Si veda ``General Public License''.
+
+@item Graffe
+I caratteri @samp{@{} e @samp{@}}. Le parentesi graffe sono usate in
+@command{awk} per delimitare azioni, istruzioni composte, e il codice che
+costituisce le funzioni.
+
+@item Guidato dai dati
+Una descrizione dei programmi @command{awk}, nei quali si specifica quali sono
+i dati che si vogliono elaborare, e cosa fare quando si trovano tali dati.
+
+@item I/O
+Abbreviazione per ``Input/Output,'' ovvero il trasferimento di dati da e verso
+un programma in esecuzione.
+
+@item Individuazione
+L'azione che consiste nel confrontare una stringa con un'espressione regolare.
+Se la @dfn{regexp} descrive qualcosa che @`e contenuto nella stringa, si dice che
+la @dfn{individua}.
+
+@item Internazionalizzazione
+La procedura con cui si scrive o si modifica un programma
+in modo che possa inviare messaggi in lingue differenti, senza richiedere
+ulteriori modifiche al codice sorgente.
+
+@item Intero
+Un numero intero, cio@`e un numero che non ha una parte frazionaria.
+
+@cindex programmi interpretati
+@item Interprete
+Un programma che accetta come input del codice sorgente, e usa le
+istruzione contenute nello stesso per elaborare dati e fornire risultati.
+@command{awk} @`e tipicamente (ma non sempre) implementato come un interprete.
+Si veda anche ``Compilatore''.
+
+@item Intervallo (nelle righe di input)
+Una sequenza di righe consecutive nel/nei file in input. Un'espressione di
+ricerca pu@`o specificare intervalli di righe di input da far elaborare ad
+@command{awk} oppure pu@`o specificare singole righe.
+(@xref{Panoramica sui criteri di ricerca}).
+
+@cindex ISO
+@item ISO
+Acronimo di International Organization for Standardization.
+Questo ente elabora degli standard internazionali in vari settori, inclusi i
+linguaggi di programmazione, come il C e il C++.
+In ambito informatico, standard importanti come quelli per il C, C++, e POSIX
+sono allo stesso tempo standard nazionali americani e standard internazionali
+ISO.
+In questo @value{DOCUMENT} lo Standard C @`e chiamato ``ISO C''.
+Si veda @uref{http://www.iso.org/iso/home/about.htm, il sito web ISO} per
+ulteriori informazioni sul nome dell'ente e sul suo acronimo di tre lettere,
+che rimane lo stesso in tutte le lingue.
+
+@item Istruzione
+Un'espressione all'interno di un programma @command{awk} nella parte
+"azione" di una regola @dfn{criterio di ricerca--azione}, o all'interno
+di una funzione @command{awk}. Un'espressione pu@`o essere un assegnamento
+di variabile, un'operazione su un vettore, un ciclo, etc.
+
+@item Istruzione composta
+Una serie di istruzioni @command{awk}, racchiuse tra parentesi graffe.
+Le istruzioni composte possono essere nidificate [possono esserci pi@`u livelli
+di parentesi graffe].
+(@xref{Istruzioni}).
+
+@item Istruzione di controllo
+Un'istruzione di controllo @`e un'istruzione per eseguire una data operazione
+o un insieme di operazioni all'interno di un programma @command{awk},
+se una determinata condizione @`e verificata.
+Istruzioni di controllo sono: @code{if}, @code{for}, @code{while}, e @code{do}
+(@pxref{Istruzioni}).
+
+@cindex Java, linguaggio di programmazione
+@cindex linguaggio di programmazione, Java
+@item Java
+Un moderno linguaggio di programmazione originalmente sviluppato da Sun
+Microsystems (ora Oracle) che prevede la programmazione orientata agli
+oggetti. Sebbene normalmente sia implementato compilando le istruzioni
+per una macchina virtuale standard (la JVM---Java Virtual Machine) il
+linguaggio pu@`o essere compilato per essere eseguito in maniera nativa.
+
+@item Korn Shell
+La Korn Shell (@command{ksh}) @`e una shell Unix sviluppata da David Korn,
+presso i Bell Laboratories, nei primi anni '80. La Korn shell @`e
+compatibile all'indietro con la Bourne shell e comprende molte funzionalit@`a
+presenti nella C Shell.
+Si veda anche ``Bourne Shell''.
+
+@item LDL
+Si veda ``Licenza Documentazione Libera''.
+
+@cindex LGPL (Lesser General Public License)
+@cindex Lesser General Public License (LGPL)
+@cindex GNU Lesser General Public License
+@item Lesser General Public License
+Questo documento descrive i termini nei quali possono essere distribuiti
+degli archivi contenenti librerie in formato eseguibile o oggetti condivisi,
+e il relativo codice sorgente.
+
+@item LGPL
+Si veda ``Lesser General Public License''.
+
+@item Licenza Documentazione Libera
+Questo documento descrive i termini in base ai quali questo @value{DOCUMENT}
+@`e pubblicato e pu@`o essere copiato.
+(@xref{Licenza per Documentazione Libera GNU (FDL)}).
+
+@item Linguaggio @command{awk}
+Il linguaggio in cui i programmi @command{awk} sono scritti.
+
+@item Linux
+Si veda ``GNU/Linux''.
+
+@item Lista di caratteri
+Si veda ``Espressione tra parentesi quadre''.
+
+@item Localizzazioni
+La funzionalit@`a che fornisce i dati necessari perch@'e un programma
+internazionalizzato interagisca con l'utente in un particolare linguaggio.
+
+@item @dfn{Lvalue}
+[left-value, ossia valore a sinistra] Un'espressione che pu@`o stare alla
+sinistra di un operatore di assegnamento.
+Nella maggior parte dei linguaggi, gli @dfn{lvalue} possono essere variabili o
+elementi di un vettore. In @command{awk}, un designatore di campo pu@`o anche
+essere usato come un @dfn{lvalue}.
+
+@item Marcatura temporale
+Un valore nel formato ``secondi a partire dall'epoch'' usato dai sistemi Unix
+e POSIX. Usato per le funzioni @command{gawk}
+@code{mktime()}, @code{strftime()}, e @code{systime()}.
+Si veda anche ``Epoca,'' ``GMT,'' e ``UTC''.
+
+@item Metacaratteri
+Caratteri usati all'interno di una @dfn{regexp} e che non rappresentano se
+stessi.
+Servono invece per rappresentare operazioni con espressioni regolari, come
+per esempio delle ripetizioni, dei raggruppamenti, o delle alternanze.
+
+@item Nidificazione
+Una nidificazione si riscontra dove l'informazione @`e organizzata a strati,
+o dove degli oggetti contengono altri oggetti simili.
+In @command{gawk} la direttiva @code{@@include}
+pu@`o essere nidificata. La nidificazione ``naturale'' delle operazioni
+aritmetiche e logiche pu@`o essere modificato attraverso l'uso di parentesi.
+(@pxref{Precedenza}).
+
+@item No-op
+Un'operazione che non fa nulla.
+
+@item Numero
+Un dato oggetto il cui valore @`e numerico. Le implementazioni di @command{awk}
+usano numeri a virgola mobile in doppia precisione per rappresentare i numeri.
+Le primissime implementazioni di @command{awk} usavano numeri a virgola mobile
+in singola precisione.
+
+@item Numero a virgola mobile
+Spesso descritto, in termini matematici, come un numero ``razionale'' o reale,
+@`e soltanto un numero che pu@`o avere una parte frazionaria.
+Si veda anche ``Doppia precisione'' e ``Singola precisione''.
+
+@item Operatori di espressioni regolari
+Si veda ``Metacaratteri''.
+
+@item Ottale
+Notazione avente come base 8, nella quale le cifre sono @code{0}--@code{7}.
+I numeri ottali in C sono scritti premettendo uno @samp{0},
+per indicare la base. Quindi, @code{013} @`e 11 ((1 x 8) + 3).
+@xref{Numeri non-decimali}.
+
+@item Parentesi Graffe
+Si veda ``Graffe''.
+
+@item Parola chiave
+nel linguaggio @command{awk}, una parola chiave (keyword) @`e una parola
+che ha un significato speciale. Queste parole sono riservate e non possono
+essere usate come nomi di variabili.
+
+Le parole chiave di @command{gawk} sono:
+@code{BEGIN},
+@code{BEGINFILE},
+@code{END},
+@code{ENDFILE},
+@code{break},
+@code{case},
+@code{continue},
+@code{default}
+@code{delete},
+@code{do@dots{}while},
+@code{else},
+@code{exit},
+@code{for@dots{}in},
+@code{for},
+@code{function},
+@code{func},
+@code{if},
+@code{next},
+@code{nextfile},
+@code{switch},
+e
+@code{while}.
+
+@item PEBKAC
+Un acronimo inglese che descrive qual @`e probabilmente la causa pi@`u frequente
+di problemi nell'uso di un computer. (@dfn{Problem Exists Between Keyboard and
+Chair} [il problema si trova tra la tastiera e la sedia].)
+
+@item Percorso di ricerca
+In @command{gawk}, una lista di directory in cui cercare file contenenti del
+codice sorgente per @command{awk}.
+Nella shell, una lista di directory in cui ricercare un programma eseguibile.
+
+@item Plug-in
+Si veda ``Estensione''.
+
+@item POSIX
+Il nome di una serie di standard che specificano l'interfaccia di un Sistema
+Operativo Portabile (Portable Operating System). La ``IX'' specifica
+che questi standard sono stati originati dallo Unix.
+Lo standard pi@`u rilevante per gli utenti @command{awk} @`e lo
+@cite{IEEE Standard for Information Technology, Standard 1003.1-2008}.
+Lo standard POSIX 2008 pu@`o essere trovato in rete all'indirizzo:
+@url{http://www.opengroup.org/onlinepubs/9699919799/}.
+
+@item Precedenza
+L'ordine in cui le operazioni sono eseguite quando si usano degli operatori
+se non si stabiliscono precedenze per mezzo di parentesi.
+
+@item Private
+Variabili e/o funzioni che sono riservate all'uso esclusivo di funzioni di
+libreria, e non per il programma principale @command{awk}. Un'attenzione
+particolare va prestata quando si desigano tali variabili e funzioni.
+(@xref{Nomi di variabili di libreria}).
+
+@item Programma @command{awk}
+Un programma @command{awk} consiste in una serie di @dfn{espressioni di
+ricerca} e @dfn{azioni}, che formano delle @dfn{regole}. Per ogni record in
+input a un progranna, le regole del programma sono elaborate nell'ordine in
+cui sono scritte. I programmi
+@command{awk} possono anche contenere definizioni di funzioni.
+
+@item Record
+Si veda ``Record in input'' e ``Record in output''.
+
+@item Record in input
+Una singola parte di dati letta da @command{awk}. Solitamente, un
+record in input di @command{awk} consiste in una linea di testo.
+(@xref{Record}).
+
+@item Record in output
+Un singolo pezzo di dati scritto da @command{awk}. Solitamente, un
+record in output di @command{awk} consiste di una o pi@`u righe di testo.
+@xref{Record}.
+
+@item Ricorsione
+Quando una funzione chiama se stessa, direttamente o indirettamente.
+Se questo @`e chiaro, si pu@`o passare a leggere la definizione successiva.
+Altrimenti, si veda la voce ``Ricorsione''.
+
+@item @dfn{regexp}
+Si veda ``Espressione regolare''.
+
+@item Regola
+Un segmento di un programma @command{awk} che specifica come trattare singoli
+record in input. Una regola consiste in una @dfn{espressione di ricerca} e in
+una @dfn{azione}.
+@command{awk} legge un record in input; poi, per ogni regola, se il record in
+input soddisfa l'espressione di ricerca della regola, @command{awk} esegue
+l'azione specificata dalla regola.
+Altrimenti, la regola non ha alcun effetto su quel record in input.
+
+@item Ridirezione
+Ridirezione significa ricevere input da quaclosa che non sia il flusso dello
+standard input, o dirigere output a qualcosa di diverso dal flusso dello
+standard output.
+
+Si pu@`o ridirigere input all'istruzione @code{getline} usando gli operatori
+@samp{<}, @samp{|}, e @samp{|&}.
+Si pu@`o ridirigere l'output delle istruzioni @code{print} e @code{printf} verso
+un file o un comando di sistema, usando gli operatori @samp{>}, @samp{>>},
+@samp{|}, e @samp{|&}.
+(@xref{Getline},
+e @ref{Ridirezione}).
+
+@item @dfn{Rvalue}
+[right-value, ossia valore a destra] Un valore che pu@`o apparire alla destra
+di un operatore di assegnazione.
+In @command{awk}, essenzialmente ogni espressione ha un valore.
+Ognuno di questi valori @`e un @dfn{rvalue}.
+
+@item Scalare
+Un valore singolo, sia numerico che di tipo stringa.
+Le variabili normali sono scalari; i vettori e le funzioni non lo sono.
+
+@item Scorciatoia
+La natura degli operatori logici @command{awk} @samp{&&} e @samp{||}.
+Se il valore dell'intera espressione in cui sono contenuti @`e determinabile
+valutando solo una parte iniziale dell'espressione, la parte seguente non @`e
+presa in considerazione.
+(@xref{Operatori booleani}).
+
+@item @dfn{Script} @command{awk}
+Un altro nome per designare un programma @command{awk}.
+
+@item @command{sed}
+Si veda ``Editore di flusso''.
+
+@item Seme
+Il valore iniziale, o il punto di partenza, di una sequenza di numeri casuali.
+
+@item Sequenze di protezione
+Una speciale sequenza di caratteri usata per descrivere caratteri non
+stampabili, come @samp{\n} (ritorno a capo) o @samp{\033} per il carattere
+ASCII ESC (Escape). (@xref{Sequenze di protezione}).
+
+@item Shell
+Il programma che interpreta i comandi nei sistemi Unix e in quelli che
+rispettano lo standard POSIX.
+La shell funziona sia interattivamente che come un linguaggio di
+programmazione, che elabora file sequenziali, detti @dfn{script} di shell.
+
+@item Singola precisione
+Una rappresentazione di numeri all'interno del computer che ha una parte
+espressa sotto forma di frazione. I numeri a singola precisione hanno meno
+cifre significative di quelli a doppia precisione, ma le operazioni relative
+richiedono talora meno risorse elaborative da parte del computer.
+Questo tipo di numero @`e quello usato da alcune tra le prime versioni di
+@command{awk} per memorizzare valori numerici. Nel linguaggio C, sono numeri
+di tipo @code{float}.
+
+@item Spazio
+Il carattere generato premendo la barra spaziatrice sulla tastiera.
+
+@item Spazio vuoto
+Una sequenza di spazi, TAB, o caratteri di ritorno a capo presenti in un
+record in input o in una stringa.
+
+@item Stringa
+Un dato che consiste in una sequenza di caratteri, come @samp{Io sono una
+stringa}. Le costanti stringa sono scritte tra doppi apici nel linguaggio
+@command{awk} e possono contenere sequenze di protezione
+(@xref{Sequenze di protezione}).
+
+@item Stringa nulla
+Una stringa che non contiene alcun carattere. @`E rappresentabile
+esplicitamente nei programmi @command{awk} mettendo due caratteri di
+doppio apice uno dietro all'altro (@code{""}). La si pu@`o inserire nei dati
+in input mettendo due separatori di campo uno dietro all'altro.
+
+@item Stringa vuota
+Si veda ``Stringa nulla''.
+
+@item Tab
+Il carattere generato premendo il tasto @kbd{TAB} sulla tastiera.
+Normalmente pu@`o generare sino a otto spazi in output.
+
+@cindex Linux
+@cindex GNU/Linux
+@cindex Unix
+@cindex sistemi operativi basati su BSD
+@cindex NetBSD
+@cindex FreeBSD
+@cindex OpenBSD
+@item Unix
+Un sistema operativo per computer originalmente sviluppato nei primi anni '70
+presso gli AT&T Bell Laboratories. Inizialmente si diffuse nelle universit@`a
+di tutto il mondo e in seguito si estese agli ambienti del mondo del lavoro
+come un sistema per lo sviluppo del software e come server di rete.
+Ci sono parecchie versioni di Unix a pagamento, come pure parecchi sistemi
+operativi modellati su Unix e il cui codice sorgente @`e liberamente
+disponibile. (come GNU/Linux, @uref{http://www.netbsd.org, NetBSD},
+@uref{http://www.freebsd.org, FreeBSD}, e
+@uref{http://www.openbsd.org, OpenBSD}).
+
+@item UTC
+L'abbreviazione comune per ``Universal Coordinated Time'' (tempo coordinato
+universale). Questa @`e l'ora standard di Greenwich, (UK), usata come tempo
+di riferimento per i calcoli relativi a marcature temporali.
+Si veda anche ``Epoca'' e ``GMT''.
+
+@item Variabile
+Un nome per designare un valore. In @command{awk}, le variabili possono
+essere degli scalari o dei vettori.
+
+@item Variabili d'ambiente
+Una collezione di stringhe, in formato @samp{@var{nome}=@var{valore}}, che
+ogni programma ha a disposizione. Gli utenti in generale assegnano valori
+alle variabili d'ambiente per fornire informazioni a vari programmi.
+Esempi tipici sono le variabili d'ambiente @env{HOME} e @env{PATH}.
+
+@item Variabili predefinite
+@code{ARGC},
+@code{ARGV},
+@code{CONVFMT},
+@code{ENVIRON},
+@code{FILENAME},
+@code{FNR},
+@code{FS},
+@code{NF},
+@code{NR},
+@code{OFMT},
+@code{OFS},
+@code{ORS},
+@code{RLENGTH},
+@code{RSTART},
+@code{RS},
+e
+@code{SUBSEP}
+sono le variabili con un significato speciale in @command{awk}.
+In pi@`u,
+@code{ARGIND},
+@code{BINMODE},
+@code{ERRNO},
+@code{FIELDWIDTHS},
+@code{FPAT},
+@code{IGNORECASE},
+@code{LINT},
+@code{PROCINFO},
+@code{RT},
+e
+@code{TEXTDOMAIN}
+sono le variabili con un significato speciale in @command{gawk}.
+Se i loro valori sono modificati, il contesto di esecuzione di @command{awk}
+cambia.
+(@xref{Variabili predefinite}).
+
+@item Vettore
+Un raggruppamento di molti valori con uno stesso nome.
+La maggior parte dei linguaggi fornisce solo vettori sequenziali.
+@command{awk} fornisce vettori associativi.
+
+@item Vettore associativo
+Un vettore i cui indici possono essere numeri o stringhe, e non solamente
+interi sequenziali compresi in un intervallo prestabilito.
+
+@end table
+
+@end ifclear
+
+@c The GNU General Public License.
+
+@node Copia
+@unnumbered Licenza Pubblica Generale GNU (GPL)
+@ifnotdocbook
+@center Versione 3, 29 Giugno 2007
+@end ifnotdocbook
+@docbook
+<subtitle>Versione 3, 29 Giugno 2007</subtitle>
+@end docbook
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2007 Free Software Foundation, Inc. @url{http://fsf.org/}
+
+This is an unofficial translation of the GNU General Public License into
+Italian. It was not published by the Free Software Foundation, and does not
+legally state the distribution terms for software that uses the GNU GPL—only
+the original English text of the GNU GPL does that. However, we hope that this
+translation will help Italian speakers understand the GNU GPL better.
+
+Questa @`e una traduzione non ufficiale in italiano della GNU General Public
+License. Questa traduzione non @`e stata pubblicata dalla Free Software
+Foundation, e non stabilisce i termini legali di distribuzione del software
+che usa la GNU GPL. Soltanto la versione originale in inglese della GNU GPL
+fa ci@`o. Ciononostante, speriamo che questa traduzione possa aiutare gli utenti
+di lingua italiana a comprendere un po' meglio la GNU GPL.
+
+A chiunque @`e permesso copiare e ridistribuire copie esatte di questo documento
+di licenza, ma non @`e in alcun modo consentito apportarvi modifiche.
+@end display
+
+@c fakenode --- for prepinfo
+@heading Preambolo
+
+La GNU General Public License @`e una licenza libera e basata su copyleft per
+software e altri tipi di opere.
+
+Le licenze della maggior parte del software e di altre opere materiali sono
+pensate per togliere la libert@`a di condividere e modificare tali opere. Al
+contrario, la GNU General Public License ha l'obiettivo di garantire la
+libert@`a di condividere e modificare tutte le versioni di un programma e di
+fare in modo che esso rimanga software libero per tutti gli utenti. Noi, Free
+Software Foundation, usiamo la GNU General Public License per la maggior parte
+del nostro software; essa viene applicata anche a qualunque altro software
+rilasciato dall'autore sotto questa licenza. Chiunque pu@`o utilizzare questa
+licenza per i suoi programmi.
+
+Quando parliamo di software libero (free software), ci riferiamo al concetto
+di libert@`a, non al prezzo. Le nostre General Public License sono progettate
+per garantire che chiunque abbia la libert@`a di distribuire copie di software
+libero (anche dietro pagamento di un prezzo, se lo desidera), che chiunque
+riceva o possa ricevere il codice sorgente se lo vuole, che chiunque possa
+apportare modifiche al software o utilizzarne delle porzioni in altri software
+liberi, e che chiunque sappia che ha il diritto di fare tutte queste cose col
+software libero.
+
+Per proteggere i vostri diritti, abbiamo la necessit@`a di impedire che altri vi
+neghino questi diritti o vi obblighino a rinunciarvi. Pertanto, chiunque
+distribuisce o modifica software rilasciato con questa licenza assume dei
+precisi doveri: il dovere di rispettare la libert@`a degli altri.
+
+Per esempio, chi distribuisce copie di un programma rilasciato sotto questa
+licenza, sia gratis che dietro pagamento di un prezzo, e' obbligato a
+riconoscere a chi riceve il software esattamente gli stessi diritti che ha
+ricevuto. Deve garantire che chi riceva il software abbia o possa avere
+accesso al codice sorgente. E deve chiaramente far conoscere ai destinatari
+del software queste condizioni, cos@`{@dotless{i}} che essi conoscano quali sono i loro
+diritti.
+
+Gli sviluppatori che usano la GNU GPL proteggono i vostri diritti in due modi:
+(1) Rivendicando il copyright sul software, e (2) offrendovi questa licenza
+che vi garantisce il diritto legale di copiarlo e/o di modificarlo.
+
+Al fine di proteggere gli sviluppatori e gli autori, la GPL spiega chiaramente
+che non c'@`e nessuna garanzia per questo software libero. Nell'interesse degli
+utenti e degli autori, la GPL impone che le versioni modificate del software
+vengano esplicitamente marcate come ``modificate'', in maniera tale che
+eventuali problemi non vengano erroneamente attribuiti agli autori delle
+versioni precedenti.
+
+Alcuni dispositivi sono progettati per negare agli utenti l'installazione o
+l'esecuzione di versioni modificate del software che gira sugli stessi, anche
+se il costruttore si riserva la possibilit@`a di farlo. Ci@`o @`e fondamentalmente
+incompatibile con l'obiettivo di garantire la libert@`a degli utenti di
+modificare il software. Una ripetizione sistematica di tali abusi avviene nel
+campo dei dispositivi per usi individuali, e ci@`o rende questi abusi ancora pi@`u
+inaccettabili. Pertanto, abbiamo realizzato questa versione della GPL al fine
+di proibire queste pratiche. Se problemi simili dovessero sorgere in altri
+ambiti, saremo pronti ad estendere queste misure a questi nuovi ambiti in
+versioni future della GPL, nella maniera che si render@`a necessaria per
+difendere la libert@`a degli utenti.
+
+In conclusione, tutti i programmi sono costantemente minacciati dai brevetti
+sul software. Gli Stati non dovrebbero permettere ai brevetti sul software di
+limitare lo sviluppo e l'utilizzo di software per computer, ma nei Paesi in
+cui ci@`o avviene noi vogliamo evitare in particolare il pericolo che i brevetti
+sul software applicati ad un programma libero possano renderlo, a tutti gli
+effetti, proprietario. Per impedire ci@`o, la GPL assicura che non @`e possibile
+utilizzare i brevetti sul software per rendere un programma non libero.
+
+I termini e le condizioni esatte per la copia, la distribuzione e la modifica
+del software sono riportate di seguito.
+
+@c fakenode --- for prepinfo
+@heading TERMINI E CONDIZIONI
+
+@enumerate 0
+@item Definizioni
+
+``Questa Licenza'' si riferisce alla versione 3 della GNU General Public
+License.
+
+``Copyright'' indica anche leggi simili al copyright che riguardano altri tipi
+di opere, come le maschere per la produzione di semiconduttori.
+
+``Il Programma'' indica qualunque opera che sia soggetta a copyright e che sia
+rilasciata sotto questa Licenza. I detentori della licenza sono indicati come
+``tu'' o ``voi''. Licenziatari e destinatari possono essere individui o
+organizzazioni.
+
+``Modificare'' un'opera significa copiare o adattare tutta o parte dell'opera in
+una maniera che richieda un permesso di copyright, e non indica la semplice
+azione di fare una esatta copia dell'opera. L'opera risultante viene chiamata
+``versione modificata'' dell'opera precedente, oppure viene detta opera ``basata
+sulla'' opera precedente.
+
+Una ``opera coperta da questa licenza'' indica il Programma originale non
+modificato oppure un'opera basata sul Programma.
+
+``Propagare'' un'opera significa fare qualunque cosa con essa che, in mancanza
+di un esplicito permesso, ti renda direttamente o indirettamente perseguibile
+per violazione secondo le vigenti normative sul copyright, ad eccezione della
+semplice esecuzione del Programma su un computer o della modifica di una copia
+privata. La Propagazione include la copia, la distribuzione (con o senza
+modifiche), la messa a disposizione al pubblico e, in alcuni stati, altre
+attivit@`a simili e connesse.
+
+``Distribuire'' un'opera indica qualunque forma di propagazione che permetta a
+terze parti di effettuare o ricevere delle copie. La mera interazione con un
+utente attraverso una rete di computer, senza che ci sia alcun trasferimento
+di una copia, non @`e considerata ``Distribuzione''.
+
+Una interfaccia utente interattiva fornisce delle ``Adeguate Informazioni
+Legali'' soltanto nel caso in cui include una apposita funzionalit@`a, resa
+adeguatamente visibile, che (1) visualizzi un'adeguata informazione di
+copyright, e (2) informi l'utente che non c'@`e alcuna garanzia sull'opera
+(eccetto nel caso in cui delle garanzie sono espressamente fornite), dica che
+il licenziatario pu@`o distribuire l'opera utilizzando questa Licenza, indichi
+come @`e possibile prendere visione di una copia di questa Licenza. Se
+l'interfaccia presenta una lista di comandi o di opzioni, come per esempio un
+men@`u, una delle opzioni fornite nella lista deve rispettare questa condizione.
+
+@item Codice Sorgente
+
+Il ``codice sorgente'' di un'opera indica la forma pi@`u indicata dell'opera per
+effettuare modifiche su di essa. Il ``codice oggetto'' indica qualunque forma
+dell'opera che non sia codice sorgente.
+
+Una ``Interfaccia Standard'' @`e una interfaccia che risponde ad uno standard
+ufficiale definito da un ente di standardizzazione riconosciuto o, nel caso di
+interfacce specifiche per un particolare linguaggio di programmazione, una
+interfaccia che @`e largamente utilizzata dagli sviluppatori per sviluppare in
+tale linguaggio.
+
+Le ``Librerie di Sistema'' di un eseguibile includono qualsiasi cosa, eccetto
+l'opera nel suo insieme, che (a) sia inclusa nella normale forma di
+pacchettizzazione di un ``Componente Principale'', ma che non @`e parte di quel
+Componente Principale, e (b) che serva solo a consentire l'uso dell'opera con
+quel Componente Principale, o per implementare una Interfaccia Standard per la
+quale esista una implementazione disponibile al pubblico in forma sorgente. Un
+``Componente Principale'', in questo contesto, @`e un componente essenziale
+(kernel, gestore di finestre eccetera) dello specifico sistema operativo
+(ammesso che ce ne sia uno) sul quale l'eseguibile esegue, o un compilatore
+utilizzato per produrre il programma, o un interprete di codice oggetto
+utilizzato per eseguire il programma.
+
+Il ``Sorgente Corrispondente'' per un'opera in forma di codice oggetto @`e il
+codice sorgente necessario per generare, installare e (per un programma
+eseguibile) eseguire il codice oggetto e per modificare l'opera, inclusi gli
+script per controllare le suddette attivit@`a di generazione, installazione ed
+esecuzione. Non sono incluse le Librerie di Sistema usate dal programma, o gli
+strumenti di utilit@`a generica o i programmi liberamente accessibili che sono
+utilizzati, senza modifiche, per portare a termine le suddette attivit@`a ma che
+non fanno parte dell'opera. Per esempio, il sorgente corrispondente include i
+file con le definizioni delle interfacce associati ai file sorgente
+dell'opera, e il codice sorgente delle librerie condivise e sottoprogrammi
+collegati dinamicamente specificatamente necessari per il programma, ad
+esempio a causa di stretta comunicazione dati o di controllo di flusso tra
+questi sottoprogrammi e altre parti del programma.
+
+Il Sorgente Corrispondente non include qualunque cosa che l'utente possa
+rigenerare automaticamente da altre parti del Sorgente Corrispondente stesso.
+
+Il Sorgente Corrispondente di un'opera in forma di codice sorgente @`e l'opera
+stessa.
+
+@item Principali Diritti
+
+Tutti i diritti garantiti da questa Licenza sono garantiti per la durata del
+copyright sul Programma, e sono irrevocabili ammesso che le suddette
+condizioni siano rispettate. Questa Licenza afferma esplicitamente il tuo
+permesso illimitato di eseguire il Programma non modificato. Il risultato
+dell'esecuzione di un programma coperto da questa Licenza @`e a sua volta
+coperto da questa Licenza solo se il risultato stesso, a causa del suo
+contenuto, @`e un'opera coperta da questa Licenza. Questa Licenza riconosce il
+tuo diritto all'uso legittimo o altri diritti equivalenti, come stabilito
+dalla legislazione sul copyright.
+
+Puoi creare, eseguire e propagare programmi coperti da questa Licenza che tu
+non distribuisci, senza alcuna condizione fino a quando la tua Licenza rimane
+valida. Puoi distribuire opere coperte da questa Licenza ad altri al solo
+scopo di ottenere che essi facciano delle modifiche al programma
+esclusivamente per te, o che ti forniscano dei servizi per l'esecuzione di
+queste opere, ammesso che tu rispetti i termini di questa Licenza nel
+distribuire tutto il materiale per il quale non detieni il copyright. Coloro i
+quali creano o eseguono per conto tuo un programma coperto da questa Licenza
+lo fanno esclusivamente in tua vece, sotto la tua direzione e il tuo
+controllo, in maniera tale che sia proibito a costoro effettuare copie di
+materiale di cui detieni il copyright al di fuori della relazione che
+intrattengono nei tuoi confronti.
+
+Distribuire opere coperte da licenza in qualunque altra circostanza @`e
+consentito soltanto alle condizioni espresse in seguito. Non @`e consentito
+sottolicenziare le opere: la sezione 10 lo rende non necessario.
+
+@item Protezione dei diritti legali degli utenti dalle leggi anti-elusione
+
+Nessun programma protetto da questa Licenza pu@`o essere considerato parte di
+una misura tecnologica di restrizione che sottosta ad alcuna delle leggi che
+soddisfano l'articolo 11 del ``WIPO copyright treaty'' adottato il 20 Dicembre
+1996, o a simili leggi che proibiscono o limitano l'elusione di tali misure
+tecnologiche di restrizione.
+
+Quando distribuisci un programma coperto da questa Licenza, rifiuti tutti i
+poteri legali atti a proibire l'elusione di misure tecnologiche di restrizione
+ammesso che tale elusione sia effettuata nell'esercizio dei diritti garantiti
+da questa Licenza riguardo al programma coperto da questa Licenza, e rinunci
+all'intenzione di limitare l'operativit@`a o la modifica del programma per far
+valere, contro i diritti degli utenti del programma, diritti legali tuoi o di
+terze parti che impediscano l'elusione di misure tecnologiche di restrizione.
+
+@item Distribuzione di Copie Esatte
+
+Ti @`e permesso distribuire copie esatte del codice sorgente del Programma come
+lo hai ricevuto, con qualunque mezzo, ammesso che tu aggiunga in maniera
+appropriata su ciascuna copia una appropriata nota di copyright; che tu lasci
+intatti tutti gli avvisi che affermano che questa Licenza e tutte le clausole
+non-permissive aggiunte in accordo con la sezione 7 sono valide per il codice
+che distribuisci; che tu lasci intatti tutti gli avvisi circa l'assenza di
+garanzia; che tu fornisca a tutti i destinatari una copia di questa Licenza
+assieme al Programma.
+
+Puoi richiedere il pagamento di un prezzo o di nessun prezzo per ciascuna
+copia che distribuisci, e puoi offrire supporto o garanzia a pagamento.
+
+@item Distribuzione di Versioni modificate del sorgente
+
+Puoi distribuire un'opera basata sul Programma, o le modifiche per produrla a
+partire dal Programma, nella forma di codice sorgente secondo i termini della
+sezione 4, ammesso che tu rispetti anche tutte le seguenti condizioni:
+
+@enumerate a
+@item
+L'opera deve recare con s@`e delle informazioni adeguate che affermino che tu
+l'hai modificata, indicando la data di modifica.
+
+@item
+L'opera deve recare informazioni adeguate che affermino che essa @`e rilasciata
+sotto questa Licenza e sotto le condizioni aggiuntive secondo quanto indicato
+dalla Sezione 7. Questa condizione modifica la condizione espressa alla
+sezione 4 di ``lasciare intatti tutti gli avvisi''.
+
+@item
+Devi rilasciare l'intera opera, nel suo complesso, sotto questa Licenza a
+chiunque venga in possesso di una copia di essa. Questa Licenza sar@`a pertanto
+applicata, assieme ad eventuali clausole aggiunte in osservanza della Sezione
+7, all'opera nel suo complesso, a tutte le sue parti, indipendentemente da
+come esse siano pacchettizzate. Questa Licenza nega il permesso di licenziare
+l'opera in qualunque altro modo, ma non rende nullo un tale permesso ammesso
+che tu lo abbia ricevuto separatamente.
+
+@item
+Se l'opera ha delle interfacce utente interattive, ciascuna deve mostrare
+delle Adeguate Informazioni Legali; altrimenti, se il Programma ha delle
+interfacce interattive che non visualizzano delle Adeguate Informazioni
+Legali, il tuo programma non @`e obbligato a visualizzarle.
+@end enumerate
+
+La giustapposizione di un'opera coperta da questa Licenza assieme ad altre
+opere separate e indipendenti, che non sono per loro natura estensioni del
+Programma, e che non sono combinate con esso a formare un altro programma pi@`u
+grande, dentro o in uno stesso supporto di memorizzazione a lungo termine o di
+distribuzione, @`e semplicemente detto ``aggregato'' se la raccolta e il suo
+copyright non sono utilizzati per limitare l'accesso o i diritti legali degli
+utenti della raccolta stessa oltre ci@`o che ciascun singolo programma consente.
+L'inclusione di un programma coperto da questa Licenza in un aggregato non
+comporta l'applicazione di questa Licenza alle altre parti dell'aggregato.
+
+@item Distribuzione in formato non-sorgente
+
+Puoi distribuire un programma coperto da questa Licenza in formato di codice
+oggetto secondo i termini delle sezioni 4 e 5, ammesso che tu fornisca anche
+il Sorgente Corrispondente in formato comprensibile da un computer sotto i
+termini di questa stessa Licenza, in uno dei seguenti modi:
+
+@enumerate a
+@item
+Distribuendo il codice oggetto in, o contenuto in, un prodotto fisico (inclusi
+i mezzi fisici di distribuzione), accompagnato dal Sorgente Corrispondente su
+un supporto fisico duraturo comunemente utilizzato per lo scambio di software.
+
+@item
+Distribuendo il codice oggetto in, o contenuto in, un prodotto fisico (inclusi
+i mezzi fisici di distribuzione), accompagnato da un'offerta scritta, valida
+per almeno tre anni e valida per tutto il tempo durante il quale tu offri
+ricambi o supporto per quel modello di prodotto, di fornire a chiunque
+possieda il codice oggetto (1) una copia del Sorgente Corrispondente di tutto
+il software contenuto nel prodotto che @`e coperto da questa Licenza, su un
+supporto fisico duraturo comunemente utilizzato per lo scambio di software, ad
+un prezzo non superiore al costo ragionevole per effettuare fisicamente tale
+distribuzione del sorgente, oppure (2) accesso alla copia del Sorgente
+Corrispondente attraverso un server di rete senza alcun costo aggiuntivo.
+
+@item
+Distribuendo copie singole del codice oggetto assieme ad una copia
+dell'offerta scritta di fornire il Sorgente Corrispondente. Questa possibilit@`a
+@`e permessa soltanto occasionalmente e per fini non commerciali, e solo se tu
+hai ricevuto il codice oggetto assieme ad una tale offerta, in accordo alla
+sezione 6b.
+
+@item
+Distribuendo il codice oggetto mediante accesso da un luogo designato (gratis
+o dietro pagamento di un prezzo), e offrendo un accesso equivalente al
+Sorgente Corrispondente alla stessa maniera a partire dallo stesso luogo senza
+costi aggiuntivi. Non devi obbligare i destinatari a copiare il Sorgente
+Corrispondente assieme al codice oggetto. Se il luogo dal quale copiare il
+codice oggetto @`e un server di rete, il Sorgente Corrispondente pu@`o trovarsi su
+un server differente (gestito da te o da terze parti) che fornisca
+funzionalit@`a equivalenti per la copia, a patto che tu fornisca delle
+indicazioni chiare accanto al codice oggetto che indichino dove trovare il
+Sorgente Corrispondente. Indipendentemente da quale server ospiti il Sorgente
+Corrispondente, tu rimani obbligato ad assicurare che esso rimanga disponibile
+per tutto il tempo necessario a soddisfare queste condizioni.
+
+@item
+Distribuendo il codice oggetto mediante trasmissione peer-to-peer, a patto che
+tu informi gli altri peer circa il luogo in cui il codice oggetto e il
+Sorgente Corrispondente sono gratuitamente offerti al pubblico secondo i
+termini della sezione 6d.
+
+@end enumerate
+
+Una porzione separabile del codice oggetto, il cui sorgente @`e escluso dal
+Sorgente Corrispondente e trattato come Libreria di Sistema, non deve essere
+obbligatoriamente inclusa nella distribuzione del codice oggetto del
+programma.
+
+Un ``Prodotto Utente'' @`e un (1) ``prodotto consumer'', cio@`e qualunque propriet@`a
+personale tangibile che @`e normalmente utilizzata per scopi personali,
+familiari o domestici, oppure (2) qualunque cosa progettata o venduta per
+essere utilizzata in ambiente domestico. Nella classificazione di un prodotto
+come ``prodotto consumer'', i casi dubbi andranno risolti in favore dell'ambito
+di applicazione. Per un dato prodotto ricevuto da un dato utente, ``normalmente
+utilizzato'' si riferisce ad un uso tipico o comune di quella classe di
+prodotti, indipendentemente dallo stato dell'utente specifico o dal modo in
+cui l'utente specifico utilizza, o si aspetta o ci si aspetta che utilizzi, il
+prodotto. Un prodotto @`e un ``prodotto consumer'' indipendentemente dal fatto che
+abbia usi commerciali, industriali o diversi da quelli ``consumer'', a meno che
+questi usi non rappresentino il solo modo utile di utilizzare il prodotto in
+questione.
+
+Le ``Informazioni di Installazione'' per un Prodotto Utente sono i metodi, le
+procedure, le chiavi di autorizzazioni o altre informazioni necessarie per
+installare ed eseguire versioni modificate di un programma coperto da questa
+Licenza all'interno di un Prodotto Utente, a partire da versioni modificate
+dei suoi Sorgenti Corrispondenti. Tali informazioni devono essere sufficienti
+ad assicurare che il funzionamento del codice oggetto modificato non sia in
+nessun caso proibito o ostacolato per il solo fatto che sono state apportate
+delle modifiche.
+
+Se distribuisci un codice oggetto secondo le condizioni di questa sezione in,
+o assieme, o specificatamente per l'uso in o con un Prodotto Utente, e la
+distribuzione avviene come parte di una transazione nella quale il diritto di
+possesso e di uso del Prodotto Utente viene trasferito al destinatario per
+sempre o per un periodo prefissato (indipendentemente da come la transazione
+sia caratterizzata), il Sorgente Corrispondente distribuito secondo le
+condizioni di questa sezione deve essere accompagnato dalle Informazioni di
+Installazione. Questa condizione non @`e richiesta se n@`e tu n@`e una terza parte
+ha la possibilit@`a di installare versioni modificate del codice oggetto sul
+Prodotto Utente (per esempio, se il programma @`e installato su una ROM)
+
+La condizione che richiede di fornire delle Informazioni di Installazione non
+implica che venga fornito supporto, garanzia o aggiornamenti per un programma
+che @`e stato modificato o installato dal destinatario, o per il Prodotto Utente
+in cui esso @`e stato modificato o installato. L'accesso ad una rete pu@`o essere
+negato se le modifiche apportate impattano materialmente sull'operativit@`a
+della rete o se violano le regole e i protocolli di comunicazione attraverso
+la rete.
+
+Il Sorgente Corrispondente distribuito, e le Informazioni di Installazione
+fornite, in accordo con questa sezione, devono essere in un formato che sia
+pubblicamente documentato (e con una implementazione pubblicamente disponibile
+in formato di codice sorgente), e non devono richiedere speciali password o
+chiavi per essere spacchettate, lette o copiate.
+
+@item Condizioni Aggiuntive
+
+Le ``Condizioni Aggiuntive'' sono condizioni che completano le condizioni di
+questa Licenza permettendo delle eccezioni a una o pi@`u delle condizioni sopra
+elencate. Le condizioni aggiuntive che sono applicabili all'intero Programma
+devono essere considerate come se fossero incluse in questa Licenza, a patto
+che esse siano valide secondo le normative vigenti. Se alcune condizioni
+aggiuntive fanno riferimento soltanto ad alcune parti del Programma, quelle
+parti possono essere utilizzate separatamente sotto le stesse condizioni, ma
+l'intero Programma rimane sottoposto a questa Licenza senza riferimento ad
+alcuna condizione aggiuntiva.
+
+Quando distribuisci una copia di un programma coperto da questa Licenza, puoi,
+a tua discrezione, eliminare qualunque condizione aggiuntiva dalla copia, o da
+parte di essa. (Le Condizioni Aggiuntive possono essere scritte in maniera
+tale da richiedere la loro rimozione in certi casi di modifica del Programma).
+Puoi aggiungere Condizioni Aggiuntive su materiale, aggiunto da te ad un'opera
+coperta da questa Licenza, per il quale hai o puoi garantire un'adeguata
+licenza di copyright.
+
+Indipendentemente da qualunque altra condizione di questa Licenza, e per il
+materiale che aggiungi ad un'opera coperta da questa Licenza, puoi (se
+autorizzato dai legittimi detentori del copyright per il suddetto materiale)
+aggiungere alle condizioni di questa Licenza delle condizioni che:
+
+@enumerate a
+@item
+Negano la garanzia o limitano la responsabilit@`a del Programma in maniera
+differente da quanto riportato nelle sezioni 15 e 16 di questa Licenza; oppure
+
+@item
+Richiedono il mantenimento di specifiche e circostanziate informative legali o
+di note di attribuzione ad autori nel materiale o assieme alle Adeguate
+Informazioni Legali mostrate dal Programma che lo contiene; oppure
+
+@item
+Proibiscono di fornire informazioni errate o ingannevoli sull'origine e la
+provenienza del materiale in oggetto, o richiedono che versioni modificate di
+tale materiale siano appositamente marcate in maniera differente rispetto alla
+versione originale; oppure
+
+@item
+Limitano l'utilizzo per scopi pubblicitari del nome dei detentori del
+copyright o degli autori del materiale; oppure
+
+@item
+Rifiutano di garantire diritti secondo le leggi sulla propriet@`a intellettuale
+circa l'uso di nomi, marchi di fabbrica o similari; oppure
+
+@item
+Richiedono l'indennizzo dei detentori del copyright o degli autori del
+materiale in oggetto da parte di chi distribuisce il materiale (o versioni
+modificate dello stesso) con impegni contrattuali circa la responsabilit@`a nei
+confronti del destinatario, per qualunque responsabilit@`a che questi impegni
+contrattuali dovessero imporre direttamente ai suddetti detentori del
+copyright e autori.
+@end enumerate
+
+Tutte le altre condizioni addizionali non-permissive sono considerate
+``ulteriori restrizioni'', secondo il significato specificato alla sezione 10.
+Se il Programma o parti di esso contengono, all'atto della ricezione dello
+stesso, informative che specificano che esso @`e soggetto a questa Licenza
+assieme ad una condizione che @`e una ``ulteriore restrizione'', puoi rimuovere
+quest'ultima condizione. Se un documento di licenza contiene ulteriori
+restrizioni ma permette di rilicenziare o distribuire il Programma con questa
+Licenza, puoi aggiungere al Programma del materiale coperto dalle condizioni
+di quel documento di licenza, a patto che le ulteriori restrizioni non
+compaiano nelle versioni rilicenziate o ridistribuite.
+
+Se aggiungi ad un Programma coperto da questa Licenza delle condizioni
+aggiuntive in accordo con questa sezione, devi aggiungere anche, nei file
+sorgenti corrispondenti, un avviso che riassuma le condizioni aggiuntive
+applicate a quei file, ovvero un avviso che specifichi dove @`e possibile
+trovare copia delle condizioni aggiunte.
+
+Tutte le Condizioni aggiuntive, permissive o non-permissive, devono essere
+espresse nella forma di una licenza scritta e separata, o espresse
+esplicitamente come eccezioni; in entrambi i casi valgono le condizioni
+succitate.
+
+@item Cessazione di Licenza
+
+Non puoi propagare o modificare un programma coperto da questa Licenza in
+maniera diversa da quanto espressamente consentito da questa Licenza.
+Qualunque tentativo di propagare o modificare altrimenti il Programma @`e nullo,
+e provoca l'immediata cessazione dei diritti garantiti da questa Licenza
+(compresi tutte le eventuali licenze di brevetto garantite ai sensi del terzo
+paragrafo della sezione 11).
+
+In ogni caso, se cessano tutte le violazioni di questa Licenza, allora la tua
+licenza da parte di un dato detentore del copyright viene ripristinata (a) in
+via cautelativa, a meno che e fino a quando il detentore del copyright non
+cessa esplicitamente e definitivamente la tua licenza, e (b) in via permanente
+se il detentore del copyright non ti notifica in alcun modo la violazione
+entro 60 giorni dalla cessazione della licenza.
+
+Inoltre, la tua licenza da parte di un dato detentore del copyright viene
+ripristinata in maniera permanente se il detentore del copyright ti notifica
+la violazione in maniera adeguata, se questa @`e la prima volta che ricevi una
+notifica di violazione di questa Licenza (per qualunque Programma) dallo
+stesso detentore di copyright, e se rimedi alla violazione entro 30 giorni
+dalla data di ricezione della notifica di violazione.
+
+La cessazione dei tuoi diritti come specificato in questa sezione non provoca
+la cessazione delle licenze di terze parti che abbiano ricevuto copie o
+diritti da te secondo questa Licenza. Se i tuoi diritti cessano e non sono
+ristabiliti in via permanente, non hai diritto di ricevere nuove licenze per
+lo stesso materiale, secondo quanto stabilito nella sezione 10.
+
+@item L'ottenimento di copie non richiede l'accettazione della Licenza
+
+Non sei obbligato ad accettare i termini di questa Licenza al solo fine di
+ottenere o eseguire una copia del Programma. Similmente, propagazioni
+collaterali di un Programma coperto da questa Licenza che occorrono come
+semplice conseguenza dell'utilizzo di trasmissioni peer-to-peer per la
+ricezione di una copia non richiedono l'accettazione della Licenza. In ogni
+caso, solo e soltanto questa Licenza ti garantiscono il permesso di propagare
+e modificare qualunque programma coperto da questa Licenza. Queste azioni
+violano le leggi sul copyright nel caso in cui tu non accetti questa Licenza.
+Pertanto, modificando o propagando un programma coperto da questa Licenza,
+indichi implicitamente la tua accettazione della Licenza.
+
+@item Licenza Automatica per i successivi destinatari
+
+Ogni qual volta distribuisci un programma coperto da questa Licenza, il
+destinatario riceve automaticamente una licenza, dal detentore originario del
+copyright, di eseguire, modificare e propagare il programma, nel rispetto di
+questa Licenza. Non sei ritenuto responsabile del rispetto di questa Licenza
+da parte di terze parti.
+
+Una ``transazione d'entit@`a'' @`e una transazione che trasferisce il controllo di
+una organizzazione, o sostanzialmente di tutti i suoi beni, che suddivide una
+organizzazione o che fonde pi@`u organizzazioni. Se la propagazione di un
+programma coperto da questa Licenza @`e conseguente ad una transazione di
+entit@`a, ciascuna parte che ha ruolo nella transazione e che riceve una copia
+del programma riceve allo stesso tempo qualsiasi licenza sul programma che i
+predecessori della parte possedevano o potevano rilasciare nel rispetto del
+paragrafo precedente, e in pi@`u il diritto di possesso del Sorgente
+Corrispondente del programma dal predecessore in interesse, se il predecessore
+lo possiede o se pu@`o ottenerlo senza troppe difficolt@`a.
+
+Non puoi imporre nessuna ulteriore restrizione sull'esercizio dei diritti
+garantiti o affermati da questa Licenza. Per esempio, non puoi imporre un
+prezzo di licenza, una royalty, o altri costi per l'esercizio dei diritti
+garantiti da questa Licenza, a non puoi dar corso ad una controversia (ivi
+incluse le controversie incrociate o la difesa in cause legali) affermando che
+siano stati violati dei brevetti a causa della produzione, dell'uso, della
+vendita, della messa in vendita o dell'importazione del Programma o di sue
+parti.
+
+@item Brevetti
+
+Un ``contribuente'' @`e un detentore di copyright che autorizza l'uso secondo
+questa Licenza di un Programma o di un'opera basata sul Programma. L'opera
+cos@`{@dotless{i}} licenziata viene chiamata ``versione del contribuente''.
+
+I ``diritti essenziali di brevetto'' da parte di un contribuente sono tutti i
+diritti di brevetto che appartengono o che sono controllati dal contribuente,
+che siano gi@`a acquisiti o che saranno acquisiti in futuro, che possano essere
+violati in qualche maniera, consentita da questa Licenza, generando,
+modificando o vendendo la versione del contribuente, ma non includono i
+diritti che possano essere violati soltanto come conseguenza di ulteriori
+modifiche alla versione del contribuente. In relazione a questa definizione,
+il termine ``controllo'' include il diritto di garantire sottolicenze di
+brevetto in maniera consistente con le condizioni di questa Licenza.
+
+Ciascun contribuente ti garantisce la licenza di brevetto sui diritti
+essenziali di brevetto del contribuente stesso non-esclusiva, valida in tutto
+il mondo, esente da royalty, di creare, usare, vendere, offrire in vendita,
+importare e altrimenti eseguire, modificare e propagare i contenuti della
+versione del contribuente.
+
+Nei tre paragrafi successivi, con ``licenza di brevetto'' si intende qualunque
+accordo o contratto, comunque denominato, di non rivendicazione di un brevetto
+(come per esempio un permesso esplicito di utilizzare un brevetto o un accordo
+di rinuncia alla persecuzione per violazione di brevetto). ``Garantire'' una
+tale licenza di brevetto ad una parte significa portare a termine un tale
+accordo o contratto di non rivendicazione di brevetto contro la parte.
+
+Se distribuisci un programma coperto da questa Licenza, confidando
+consapevolmente su una licenza di brevetto, e il Sorgente Corrispondente per
+il programma non @`e reso disponibile per la copia, senza alcun onere aggiuntivo
+e comunque nel rispetto delle condizioni di questa Licenza, attraverso un
+server di rete pubblicamente accessibile o tramite altri mezzi facilmente
+accessibili, allora devi (1) fare in modo che il Sorgente Corrispondente sia
+reso disponibile come sopra, oppure (2) fare in modo di rinunciare ai benefici
+della licenza di brevetto per quel particolare programma, oppure (3)
+adoperarti, in maniera consistente con le condizioni di questa Licenza, per
+estendere la licenza di brevetto a tutti i destinatari successivi. ``Confidare
+consapevolmente'' significa che tu sei attualmente cosciente che, eccettuata la
+licenza di brevetto, la distribuzione da parte tua di un programma protetto da
+questa Licenza in un paese, o l'utilizzo in un paese del programma coperto da
+questa Licenza da parte di un destinatario, pu@`o violare uno o pi@`u brevetti in
+quel paese che tu hai ragione di ritenere validi.
+
+Se, come conseguenza o in connessione con una singola transazione o con un
+dato accordo, distribuisci, o fai in modo di distribuire, un programma coperto
+da questa Licenza, e garantisci una licenza di brevetto per alcune delle parti
+che ricevono il Programma autorizzandole ad utilizzare, propagare, modificare
+o distribuire una specifica copia del Programma, allora la licenza di brevetto
+che fornisci @`e automaticamente estesa a tutti i destinatari del Programma
+coperto da questa Licenza e delle opere basate sul Programma.
+
+Una licenza di brevetto @`e ``discriminatoria'' se non include nell'ambito della
+sua copertura, proibisce l'esercizio, o @`e vincolata al non-esercizio di uno o
+pi@`u dei diritti che sono specificatamente garantiti da questa Licenza. Non
+puoi distribuire un Programma coperto da questa Licenza se sei parte di un
+accordo con una terza parte la cui attivit@`a comprende la distribuzione di
+software, secondo il quale tu sei costretto ad un pagamento alla parte terza
+in funzione della tua attivit@`a di distribuzione del Programma, e in
+conseguenza del quale la parte terza garantisce, a qualunque delle parti che
+riceveranno il Programma da te, una licenza di brevetto discriminatoria (a)
+assieme a copie del Programma coperto da questa Licenza distribuite da te (o
+ad altre copie fatte da codeste copie), oppure (b) principalmente per e in
+connessione con specifici prodotti o raccolte di prodotti che contengono il
+Programma, a meno che l'accordo non sia stato stipulato, o le licenze di
+brevetto non siano state rilasciate, prima del 28 Marzo 2007.
+
+Nessuna parte di questa Licenza pu@`o essere interpretata come atta ad escludere
+o limitare gli effetti di qualunque altra licenza o altri meccanismi di difesa
+dalla violazione che possano altrimenti essere resi disponibili dalla
+normativa vigente in materia di brevetti.
+
+@item Nessuna resa di libert@`a altrui
+
+Se ti vengono imposte delle condizioni (da un ordine giudiziario, da un
+accordo o da qualunque altra eventualit@`a) che contraddicono le condizioni di
+questa Licenza, non sei in nessun modo esonerato dal rispetto delle condizioni
+di questa Licenza. Se non puoi distribuire un Programma coperto da questa
+Licenza per sottostare simultaneamente agli obblighi derivanti da questa
+Licenza e ad altri obblighi pertinenti, allora non puoi distribuire il
+Programma per nessun motivo. Per esempio, se accetti delle condizioni che ti
+obbligano a richiedere il pagamento di una royalty per le distribuzioni
+successivamente effettuate da coloro ai quali hai distribuito il Programma,
+l'unico modo per soddisfare sia queste condizioni che questa Licenza @`e evitare
+del tutto la distribuzione del Programma.
+
+@item Utilizzo con la GNU Affero General Public License
+
+Indipendentemente da qualunque altra condizione espressa da questa Licenza,
+hai il permesso di collegare o combinare qualunque Programma coperto da questa
+Licenza con un'opera rilasciata sotto la versione 3 della licenza GNU Affero
+General Public License, ottenendo un singolo Programma derivato, e di
+distribuire il Programma risultante. Le condizioni di questa Licenza
+continuano a valere per le parti riguardanti il Programma che sono coperte da
+questa Licenza, mentre le condizioni speciali della GNU Affero General Public
+License, sezione 13, riguardanti l'interazione mediante rete, saranno
+applicate al Programma cos@`{@dotless{i}} risultante.
+
+@item Versioni rivedute di questa Licenza
+
+La Free Software Foundation pu@`o pubblicare delle versioni rivedute e/o delle
+nuove versioni della GNU General Public License di tanto in tanto. Tali
+versioni saranno simili, nello spirito, alla presente versione, ma potranno
+differire nei dettagli al fine di affrontare nuovi problemi e nuove
+situazioni.
+
+A ciascuna versione viene assegnato un numero identificativo di versione. Se
+il Programma specifica che si applica a s@`e stesso una certa versione della GNU
+General Public License, ``o qualunque altra versione successiva'', hai la
+possibilit@`a di sottostare alle condizioni di quella specifica versione o di
+qualunque altra versione successiva pubblicata dalla Free Software Foundation.
+Se il Programma non specifica un numero di versione della GNU General Public
+License, puoi scegliere qualunque versione della GNU General Public License
+pubblicata dalla Free Software Foundation.
+
+Se il Programma specifica che un sostituto o un procuratore pu@`o decidere quali
+versioni future della GNU General Public License posso essere utilizzate,
+allora tale scelta di accettazione di una data versione ti autorizza, in
+maniera permanente, ad utilizzare quella versione della Licenza per il
+Programma.
+
+Versioni successive della Licenza possono garantire diritti aggiuntivi o
+leggermente differenti. Ad ogni modo, nessun obbligo aggiuntivo viene imposto
+agli autori o ai detentori di copyright come conseguenza della tua scelta di
+adottare una versione successiva della Licenza.
+
+@item Rinuncia alla Garanzia
+
+NON C'@`E NESSUNA GARANZIA PER IL PROGRAMMA, PER QUANTO CONSENTITO DALLE
+VIGENTI NORMATIVE. ECCETTO QUANDO ALTRIMENTI STABILITO PER ISCRITTO, I
+DETENTORI DEL COPYRIGHT E/O LE ALTRE PARTI FORNISCONO IL PROGRAMMA ``COS@`I COME
+@`E'' SENZA GARANZIA DI ALCUN TIPO, N@'E ESPRESSA N@'E IMPLICITA, INCLUSE, MA NON
+LIMITATE A, LE GARANZIE DI COMMERCIABILIT@`A O DI UTILIZZABILIT@`A PER UN
+PARTICOLARE SCOPO. L'INTERO RISCHIO CONCERNENTE LA QUALIT@`A E LE PRESTAZIONI
+DEL PROGRAMMA @`E DEL LICENZIATARIO. SE IL PROGRAMMA DOVESSE RISULTARE
+DIFETTOSO, IL LICENZIATARIO SI ASSUME I COSTI DI MANUTENZIONE, RIPARAZIONE O
+CORREZIONE.
+
+@item Limitazione di Responsabilit@`a
+
+IN NESSUN CASO, A MENO CHE NON SIA RICHIESTO DALLA NORMATIVA VIGENTE O
+CONCORDATO PER ISCRITTO, I DETENTORI DEL COPYRIGHT, O QUALUNQUE ALTRA PARTE
+CHE MODIICA E/O DISTRIBUISCE IL PROGRAMMA SECONDO LE CONDIZIONI PRECEDENTI,
+POSSONO ESSERE RITENUTI RESPONSABILI NEI CONFRONTI DEL LICENZIATARIO PER
+DANNI, INCLUSO QUALUNQUE DANNEGGIAMENTO GENERICO, SPECIALE, INCIDENTALE O
+CONSEQUENZIALE DOVUTO ALL'USO O ALL'IMPOSSIBILIT@`A D'USO DEL PROGRAMMA
+(INCLUSI, MA NON LIMITATI A, LE PERDITE DI DATI, LA CORRUZIONE DI DATI, LE
+PERDITE SOSTENUTE DAL LICENZIATARIO O DA TERZE PARTI O L'IMPOSSIBILIT@`A DEL
+PROGRAMMA A FUNZIONARE ASSIEME AD ALTRI PROGRAMMI), ANCHE NEL CASO IN CUI IL
+DETENTORE O LE ALTRE PARTI SIANO STATI AVVISATI CIRCA LA POSSIBILIT@`A DI TALI
+DANNEGGIAMENTI.
+
+@item Interpretazione delle Sezioni 15 e 16
+
+Se la dichiarazione di garanzia e la limitazione di responsabilit@`a fornite
+precedentemente non hanno effetto legale in un paese a causa delle loro
+condizioni, le corti di giustizia devono applicare la norma locale che pi@`u si
+avvicini al rifiuto assoluto di qualsivoglia responsabilit@`a civile relativa al
+Programma, a meno che una garanzia o una assunzione di responsabilit@`a scritta
+non accompagni una copia del programma ottenuta dietro pagamento.
+@end enumerate
+
+@c fakenode --- for prepinfo
+@heading FINE DEI TERMINI E DELLE CONDIZIONI
+
+@c fakenode --- for prepinfo
+@heading Come applicare queste condizioni di Licenza ai vostri programmi
+
+Se sviluppi un nuovo programma, e vuoi che esso sia della massima utilit@`a, il
+modo migliore @`e renderlo software libero in modo che chiunque possa
+ridistribuirlo e modificarlo secondo i termini di questa Licenza.
+
+Per fare ci@`o, allega le seguenti note informative al programma. Il modo
+migliore @`e inserirle all'inizio di ciascun file sorgente, al fine di rimarcare
+adeguatamente la mancanza di garanzia; ciascun file dovrebbe inoltre contenere
+la dichiarazione di copyright e un riferimento al posto in cui @`e possibile
+ottenere la versione completa delle note informative.
+
+@smallexample
+@var{<una riga con nome del programma e breve descrizione di ci@`o che fa.>}
+Copyright (C) @var{<anno>} @var{<nome dell'autore>}
+
+Questo software @`e libero; lo puoi distribuire e/o modificare alle condizioni
+stabilite nella 'GNU General Public License' pubblicata dalla Free Software
+Foundation; fai riferimento alla versione 3 della Licenza, o (a tua scelta)
+a una qualsiasi versione successiva.
+
+Questo programma @`e distribuito con la speranza che sia utile, ma SENZA
+ALCUNA GARANZIA; senza neppure la garanzia implicita di COMMERCIABILIT@`A o
+IDONEIT@`A AD UN PARTICOLARE SCOPO. Si veda la 'GNU General Public License' per
+ulteriori dettagli.
+
+Dovresti aver ricevuto una copia della GNU General Public License assieme a
+questo programma; se non @`e cos@`{@dotless{i}}, si veda
+@url{http://www.gnu.org/licenses/}.
+@end smallexample
+
+Inoltre, aggiungi le informazioni necessarie a contattarti via posta ordinaria
+o via posta elettronica.
+
+Se il programma interagisce mediante terminale, fai in modo che visualizzi,
+quando viene avviato in modalit@`a interattiva, un breve messaggio come quello
+che segue:
+
+@smallexample
+@var{<programma>} Copyright (C) @var{<anno>} @var{<nome dell'autore>}
+Questo programma non ha ALCUNA GARANZIA; per dettagli usare il comando
+@samp{show w}.
+Questo @`e software libero, e ognuno @`e libero di ridistribuirlo
+sotto certe condizioni; usare il comando @samp{show c} per i dettagli.
+@end smallexample
+
+Gli ipotetici comandi @samp{show w} e @samp{show c} devono visualizzare le parti
+corrispondenti della GNU General Public License. Naturalmente i comandi del
+tuo programma potrebbero essere differenti; per una interfaccia di tipo GUI,
+dovresti usare un bottone ``About'' o ``Info''.
+
+Devi inoltre fare in modo che il tuo datore di lavoro (se lavori come
+programmatore presso terzi) o la tua scuola, eventualmente, firmino una
+``rinuncia al copyright'' sul programma, se necessario. Per maggiori
+informazioni su questo punto, e su come applicare e rispettare la GNU GPL,
+consultare la pagina @url{http://www.gnu.org/licenses/}.
+
+La GNU General Public License non consente di incorporare il programma
+all'interno di software proprietario. Se il tuo programma @`e una libreria di
+funzioni, potresti ritenere pi@`u opportuno consentire il collegamento tra
+software proprietario e la tua libreria. Se @`e questo ci@`o che vuoi, allora
+utilizza la GNU Lesser General Public License anzich@'e questa Licenza, ma prima
+leggi @url{http://www.gnu.org/philosophy/why-not-lgpl.html}.
+
+@ifclear FOR_PRINT
+@c The GNU Free Documentation License.
+@node Licenza per Documentazione Libera GNU (FDL)
+@unnumbered Licenza per Documentazione Libera GNU (FDL)
+@ifnotdocbook
+@center Versione 1.3, 3 Novembre 2008
+@end ifnotdocbook
+
+@docbook
+<subtitle>Versione 1.3, 3 Novembre 2008 </subtitle>
+@end docbook
+
+@cindex FDL (Free Documentation License)
+@cindex Free Documentation License (FDL)
+@cindex GNU Free Documentation License
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+@uref{http://fsf.org}
+
+This is an unofficial translation of the GNU Free Documentation License into
+Italian. It was not published by the Free Software Foundation, and does not
+legally state the distribution terms for software that uses the GNU FDL—only
+the original English text of the GNU FDL does that. However, we hope that this
+translation will help Italian speakers understand the GNU FDL better.
+
+Questa @`e una traduzione non ufficiale della GNU Free Documentation License
+in italiano. Non @`e una pubblicazione della Free Software Foundation, e non
+ha validit@`a legale per i termini di distribuzione della documentazione che
+usa la GNU FDL; solo il testo originale inglese della GNU FDL ha tale
+validit@`a. Comunque, speriamo che questa traduzione aiuti chi parla
+italiano a comprendere meglio la GNU FDL.
+
+A chiunque @`e permesso copiare e ridistribuire copie esatte di questo documento
+di licenza, ma non @`e in alcun modo consentito apportarvi modifiche.
+
+@end display
+
+@enumerate 0
+@item
+PREAMBOLO
+
+Lo scopo di questa licenza @`e di rendere @dfn{liberi} un manuale, un testo o
+altri documenti funzionali e utili, nel senso di assicurare a tutti la
+libert@`a effettiva di copiarli e ridistribuirli, con o senza modifiche, con
+o senza fini di lucro. In secondo luogo questa licenza prevede per autori
+ed editori il modo per ottenere il giusto riconoscimento del proprio
+lavoro, preservandoli dall'essere considerati responsabili per modifiche
+apportate da altri.
+
+Questa licenza garantisce il ``copyleft'': questo significa che i lavori che
+derivano dal documento originale devono essere ugualmente liberi. @`E il
+complemento alla Licenza Pubblica Generale GNU, che @`e una licenza di tipo
+``copyleft'' pensata per il software libero.
+
+Questa licenza @`e stata progettata appositamente per l'uso con manuali di
+software libero, perch@'e il software libero ha bisogno di documentazione
+libera: un programma libero dovrebbe accompagnarsi a manuali che
+forniscano le stesse libert@`a del software. Questa licenza non @`e limitata
+alla manualistica del software; pu@`o essere utilizzata per ogni testo che
+tratti un qualsiasi argomento e al di l@`a dell'avvenuta pubblicazione
+cartacea. Si raccomanda l'uso di questa licenza principalmente per opere
+che abbiano fini didattici o per manuali.
+
+@item
+APPLICABILIT@`A E DEFINIZIONI
+
+Questa licenza si applica a qualsiasi manuale o altra opera, su ogni tipo
+di supporto, che contenga la nota, posta dal detentore del copyright, che
+attesti la possibilit@`a di distribuzione secondo i termini di questa
+licenza. Tale nota permette universalmente, senza pagamento di diritti e
+senza limiti di durata di utilizzare il lavoro secondo le condizioni qui
+specificate. Con ``documento'', nel seguito ci si riferisce a qualsiasi
+manuale o opera. Ogni fruitore @`e un destinatario della licenza ed @`e ad
+esso che si fa riferimento. Si conviene che la licenza viene accettata se
+si copia, modifica o distribuisce il lavoro in una maniera tale da
+richiedere il permesso secondo le leggi sul copyright.
+
+Una ``versione modificata'' del documento @`e ogni opera contenente il
+documento stesso o parte di esso, sia riprodotto alla lettera che con
+modifiche, oppure traduzioni in un'altra lingua.
+
+Una ``sezione secondaria'' @`e un'appendice cui si fa riferimento o una
+premessa del documento e riguarda esclusivamente il rapporto dell'editore
+o dell'autore del documento con l'argomento generale del documento stesso
+(o argomenti affini) e non contiene nulla che possa essere compreso
+nell'argomento principale. (Perci@`o, se il documento @`e in parte un manuale
+di matematica, una sezione secondaria non pu@`o contenere spiegazioni di
+matematica). Il rapporto con l'argomento pu@`o essere un tema collegato
+storicamente con il soggetto principale o con soggetti affini, o essere
+costituito da argomentazioni legali, commerciali, filosofiche, etiche o
+politiche pertinenti.
+
+Le ``sezioni non modificabili'' sono alcune sezioni secondarie i cui titoli
+sono esplicitamente elencati come titoli delle sezioni non modificabili
+nella nota che indica che il documento @`e realizzato sotto questa licenza.
+Se una sezione non rientra nella precedente definizione di sezione
+secondaria, allora non @`e permesso che venga definita come non
+modificabile. Il documento pu@`o anche non contenere sezioni non
+modificabili. Se nel documento non vengono indicate sezioni non
+modificabili, allora significa che non ve ne sono.
+
+I ``testi di copertina'' sono dei brevi brani di testo che sono elencati,
+nella prima o quarta pagina di copertina, nella nota che indica che il
+documento @`e rilasciato sotto questa licenza. Il testo sulla prima di
+copertina pu@`o essere composto al massimo di 5 parole mentre quello sulla
+quarta di copertina pu@`o essere al massimo di 25 parole.
+
+Una copia ``trasparente'' indica una copia leggibile da un calcolatore,
+codificata in un formato le cui specifiche sono disponibili pubblicamente,
+tale che il suo contenuto possa essere modificato in modo semplice con
+generici editor di testi o (per immagini composte da pixel) con generici
+editor di immagini o (per i disegni) con qualche editor di disegni
+ampiamente diffuso; la copia deve essere adatta al trattamento per la
+formattazione o per la conversione in una variet@`a di formati atti alla
+successiva formattazione. Una copia fatta in un formato di file, per il
+resto trasparente, i cui marcatori o assenza di tali sono stati progettati
+per intralciare o scoraggiare modifiche future da parte dei lettori non @`e
+trasparente. Un formato immagine non @`e trasparente se viene usato per
+rappresentare una notevole quantit@`a di testo. Una copia non ``trasparente''
+viene detta ``opaca''.
+
+Esempi di formati adatti per copie trasparenti sono l'@sc{ASCII} puro senza
+marcatori, il formato di ingresso per Texinfo, il formato di ingresso per
+La@TeX{}, @acronym{SGML} o @acronym{XML} accoppiati ad una @acronym{DTD}
+pubblica e disponibile, e i formati conformi agli standard @acronym{HTML}
+semplice, Postscript e @acronym{PDF} progettati per essere modificati
+manualmente. Esempio di formati immagine trasparenti includono il
+@acronym{PNG}, @acronym{XCF} e @acronym{JPG}. I formati opachi includono i
+formati proprietari che possono essere letti e modificati solo con word
+processor proprietari, @acronym{SGML} o @acronym{XML} per cui non @`e in
+genere disponibile la @acronym{DTD} o gli strumenti per il trattamento, e i
+formati @acronym{HTML}, Postscript e @acronym{PDF} generati automaticamente
+da qualche word processor esclusivamente come output.
+
+La ``pagina del titolo'' di un libro stampato indica la pagina del titolo
+stessa, pi@`u qualche pagina seguente per quanto necessario a contenere in
+modo leggibile, il materiale che la licenza prevede che compaia nella
+pagina del titolo. Per opere in formati in cui non sia contemplata
+esplicitamente la pagina del titolo, con ``pagina del titolo'' si intende il
+testo prossimo al titolo dell'opera, precedente l'inizio del corpo del
+testo.
+
+Il termine ``editore'' indica qualunque persona o entit@`a che distribuisce al
+pubblico copie del documento.
+
+Una sezione ``Intitolata XYZ'' significa una sottosezione con nome del
+documento il cui titolo sia precisamente XYZ o che contenga XYZ in
+parentesi dopo il testo che traduce XYZ in un'altra lingua (in questo caso
+XYZ sta per uno specifico nome di sezione menzionato sotto, come per i
+``Riconoscimenti'', ``Dediche'', ``Approvazioni'', o ``Storia''). Secondo questa
+definizione, ``preservare il titolo'' di tale sezione quando si modifica il
+documento, significa che essa rimane una sezione ``Intitolata XYZ''.
+
+Il Documento pu@`o includere dei limiti alla garanzia accanto alla nota
+affermante l'applicazione di questa licenza al documento. Questi limiti
+alla garanzia sono da considerare da includere come riferimento a questa
+licenza, ma solo per quanto riguarda le limitazioni alla garanzia: ogni
+altra implicazione che questi limiti alla garanzia possono avere @`e da
+considerarsi nulla e non ha effetto sul significato di questa licenza.
+
+@item
+COPIE LETTERALI
+
+Si pu@`o copiare e distribuire il documento con qualsiasi mezzo, con o senza
+fini di lucro, purch@'e tutte le copie contengano questa licenza, le note di
+copyright e l'avviso che questa licenza si applica al documento, e che non
+si aggiungano altre condizioni al di fuori di quelle della licenza stessa.
+Non si possono usare misure tecniche per impedire o controllare la lettura
+o la produzione di copie successive alle copie che si producono o
+distribuiscono. Si possono comunque accettare compensi per la copiatura.
+Se si distribuiscono un numero sufficiente di copie si devono seguire
+anche le condizioni della sezione 3.
+
+Alle stesse condizioni sopra menzionate si possono prestare copie e
+mostrarle pubblicamente.
+
+@item
+COPIARE IN NOTEVOLI QUANTIT@`A
+
+Se si pubblicano a mezzo stampa (o in formati che tipicamente posseggono
+copertine) pi@`u di 100 copie del documento, e la nota della licenza
+richiede uno o pi@`u testi di copertina, si devono includere nelle copie, in
+modo chiaro e leggibile, tutti i testi di copertina indicati: il testo
+della prima di copertina in prima di copertina e il testo di quarta di
+copertina in quarta di copertina. Ambedue devono identificare l'editore
+che pubblica il documento. La prima di copertina deve presentare il titolo
+completo con tutte le parole che lo compongono egualmente visibili ed
+evidenti. Si pu@`o aggiungere altro materiale alle copertine. Il copiare con
+modifiche limitate alle sole copertine, purch@'e si preservino il titolo e
+le altre condizioni viste in precedenza, @`e considerato alla stregua di
+copiare alla lettera.
+
+Se il testo richiesto per le copertine @`e troppo voluminoso per essere
+riprodotto in modo leggibile, se ne pu@`o mettere una prima parte (per
+quanto ragionevolmente pu@`o stare) in copertina, e continuare il resto
+nelle pagine immediatamente seguenti.
+
+Se si pubblicano o distribuiscono copie opache del documento in numero
+superiore a 100, si deve anche includere una copia trasparente leggibile
+da un calcolatore in ogni copia oppure menzionare in ogni copia opaca un
+indirizzo di rete di calcolatori pubblicamente accessibile che utilizzi un
+protocollo di rete standard pubblico, da cui si possa scaricare
+liberamente una copia trasparente completa del documento, senza materiale
+aggiuntivo. Se si adotta quest'ultima opzione, si deve prestare la giusta
+attenzione, nel momento in cui si inizia la distribuzione in quantit@`a
+elevata di copie opache, ad assicurarsi che la copia trasparente rimanga
+accessibile all'indirizzo stabilito fino ad almeno un anno dopo l'ultima
+distribuzione (direttamente o attraverso distributori o rivenditori) di
+quell'edizione al pubblico.
+
+@`E caldamente consigliato, bench@'e non obbligatorio, contattare l'autore del
+documento prima di distribuirne un numero considerevole di copie, per
+metterlo in grado di fornire una versione aggiornata del documento.
+
+@item
+MODIFICHE
+
+Si possono copiare e distribuire versioni modificate del documento
+rispettando le condizioni delle precedenti sezioni 2 e 3, purch@'e la
+versione modificata sia realizzata seguendo questa stessa licenza, con la
+versione modificata che svolga il ruolo del ``documento'', cos@`{@dotless{i}} da estendere
+la licenza sulla distribuzione e la modifica a chiunque ne possieda una
+copia. Inoltre nelle versioni modificate si deve:
+
+@enumerate A
+@item
+Usare nella pagina del titolo (e nelle copertine se ce ne sono) un titolo
+diverso da quello del documento, e da quelli di versioni precedenti (che
+devono essere elencati nella sezione storia del documento ove presenti).
+Si pu@`o usare lo stesso titolo di una versione precedente se l'editore di
+quella versione originale ne ha dato il permesso.
+
+@item
+Elencare nella pagina del titolo, come autori, una o pi@`u persone o gruppi
+responsabili in qualit@`a di autori delle modifiche nella versione
+modificata, insieme ad almeno cinque tra i principali autori del documento
+(tutti gli autori principali se sono meno di cinque), a meno che questi
+non abbiano acconsentito a liberarvi da quest'obbligo.
+
+@item
+Dichiarare nella pagina del titolo il nome dell'editore della versione
+modificata in qualit@`a di editore.
+
+@item
+Conservare tutte le note di copyright
+del documento originale.
+
+@item
+Aggiungere un'appropriata nota di copyright per
+le modifiche di seguito alle altre note di copyright.
+
+@item
+Includere, immediatamente dopo la nota di copyright, una nota di licenza
+che dia pubblicamente il permesso di usare la versione modificata nei
+termini di questa licenza, nella forma mostrata nell'Addendum alla fine di
+questo testo.
+
+@item
+Preservare in tale nota di licenza l'elenco completo di sezioni non
+modificabili e testi di copertina richiesti come previsto dalla licenza
+del documento.
+
+@item
+Includere una copia non modificata di questa licenza.
+
+@item
+Conservare la sezione intitolata ``Storia'', e il suo titolo, e aggiungere
+a questa un elemento che riporti almeno il titolo, l'anno, i nuovi autori,
+e gli editori della versione modificata come figurano nella pagina del
+titolo. Se non ci sono sezioni intitolate ``Storia'' nel documento,
+crearne una che riporti il titolo, gli autori, gli editori del documento
+come figurano nella pagina del titolo, quindi aggiungere un elemento che
+descriva la versione modificata come detto in precedenza.
+
+@item
+Conservare l'indirizzo in rete riportato nel documento, se c'@`e, al fine
+del pubblico accesso ad una copia trasparente, e possibilmente l'indirizzo
+in rete per le precedenti versioni su cui ci si @`e basati. Questi possono
+essere collocati nella sezione ``Storia''. Si pu@`o omettere un indirizzo di
+rete per un'opera pubblicata almeno quattro anni prima del documento
+stesso, o se l'originario editore della versione cui ci si riferisce ne d@`a
+il permesso.
+
+@item
+In ogni sezione di ``Ringraziamenti'' o ``Dediche'', si conservi il titolo
+della sezione, e all'interno della sezione tutta la sostanza e il tono di
+ognuno dei ringraziamenti ai contributori e/o le dediche ivi contenute.
+
+@item
+Si conservino inalterate le sezioni non modificabili del documento, nei
+propri testi e nei propri titoli. I numeri della sezione o equivalenti non
+sono considerati parte del titolo della sezione.
+
+@item
+Si cancelli ogni sezione intitolata ``Approvazioni''. Tale sezione non pu@`o
+essere inclusa nella versione modificata.
+
+@item
+Non si cambi il titolo di sezioni esistenti in ``Approvazioni'' o in modo
+tale che si possa creare confusione con i titoli di sezioni non
+modificabili.
+
+@item
+Si conservino tutti i limiti alla garanzia.
+@end enumerate
+
+
+
+Se la versione modificata comprende nuove sezioni di primaria
+importanza o appendici che ricadono in ``sezioni secondarie'', e non
+contengono materiale copiato dal documento, si ha facolt@`a di rendere non
+modificabili quante sezioni si voglia. Per fare ci@`o si aggiunga il loro
+titolo alla lista delle sezioni non modificabili nella nota di licenza
+della versione modificata. Questi titoli devono essere distinti dai titoli
+di ogni altra sezione.
+
+Si pu@`o aggiungere una sezione intitolata ``Approvazioni'', a patto che non
+contenga altro che le approvazioni alla versione modificata prodotte da
+vari soggetti--per esempio, affermazioni di revisione o che il testo @`e
+stato approvato da una organizzazione come la definizione normativa di uno
+standard.
+
+Si pu@`o aggiungere un brano fino a cinque parole come testo di prima di
+copertina e un brano fino a 25 parole come testo di quarta di copertina,
+alla fine dell'elenco dei testi di copertina nella versione modificata.
+Solamente un brano del testo di prima di copertina e uno del testo di
+quarta di copertina possono essere aggiunti (anche con adattamenti) da
+ciascuna persona o organizzazione. Se il documento include gi@`a un testo di
+copertina per la stessa copertina, precedentemente aggiunto o adattato da
+qualunque fruitore o dalla stessa organizzazione nel nome della quale si
+agisce, non se ne pu@`o aggiungere un altro, ma si pu@`o rimpiazzare il
+vecchio ottenendo l'esplicita autorizzazione dall'editore precedente che
+aveva aggiunto il testo di copertina.
+
+L'autore/i e l'editore/i del documento non danno, tramite questa licenza,
+il permesso di usare i loro nomi per pubblicizzare o asserire, anche
+implicitamente, la loro approvazione di ogni versione modificata.
+
+@item
+COMBINAZIONE DI DOCUMENTI
+
+Si pu@`o combinare il documento con altri pubblicati con questa licenza,
+seguendo i termini definiti nella precedente sezione 4 per le versioni
+modificate, a patto che si includa l'insieme di tutte le sezioni non
+modificabili di tutti i documenti originali, senza modifiche, e si
+elenchino tutte come sezioni non modificabili della combinazione di
+documenti nella licenza della stessa, mantenendo tutti i limiti alla
+garanzia.
+
+Nella combinazione @`e necessaria una sola copia di questa licenza, e pi@`u
+sezioni non modificabili possono essere rimpiazzate da una singola copia
+se identiche. Se ci sono pi@`u sezioni non modificabili con lo stesso nome
+ma contenuti differenti, si renda unico il titolo di ciascuna sezione
+aggiungendovi, alla fine e tra parentesi, il nome dell'autore o editore
+della sezione, se noti, o altrimenti un numero distintivo. Si facciano gli
+stessi aggiustamenti ai titoli delle sezioni nell'elenco delle sezioni non
+modificabili nella nota di copyright della combinazione.
+
+Nella combinazione si devono unire le varie sezioni intitolate ``Storia''
+nei vari documenti originali di partenza per formare una unica sezione
+intitolata ``Storia''; allo stesso modo si unisca ogni sezione intitolata
+``Ringraziamenti'', e ogni sezione intitolata ``Dediche''. Si devono eliminare
+tutte le sezioni intitolate ``Approvazioni''.
+
+@item
+RACCOLTE DI DOCUMENTI
+
+Si pu@`o produrre una raccolta che consista del documento e di altri
+documenti rilasciati sotto questa licenza, e rimpiazzare le singole copie
+di questa licenza nei vari documenti con una sola inclusa nella raccolta,
+solamente se si seguono le regole fissate da questa licenza per le copie
+alla lettera come se si applicassero a ciascun documento.
+
+Si pu@`o estrarre un singolo documento da tale raccolta e distribuirlo
+separatamente sotto questa licenza, solo se si inserisce una copia di
+questa licenza nel documento estratto e se si seguono tutte le altre
+regole fissate da questa licenza per le copie alla lettera del documento.
+
+@item
+AGGREGAZIONE A LAVORI INDIPENDENTI
+
+Un'unione del documento o sue derivazioni con altri documenti o lavori
+separati o indipendenti, all'interno di, o a formare un, archivio o un
+supporto, per la memorizzazione o la distribuzione, viene chiamato un
+``aggregato'' se il copyright risultante dall'unione non viene usato per
+limitare i diritti legali degli utilizzatori oltre a ci@`o che viene
+permesso dai singoli lavori. Quando il documento viene incluso in un
+aggregato, questa licenza non si applica ad altri lavori nell'aggregato
+che non siano essi stessi dei lavori derivati dal documento.
+
+Se le esigenze del testo di copertina della sezione 3 sono applicabili a
+queste copie del documento allora, se il documento @`e inferiore alla met@`a
+dell'intero aggregato i testi di copertina del documento possono essere
+piazzati in copertine che delimitano il documento all'interno
+dell'aggregato, o dell'equivalente elettronico delle copertine se il
+documento @`e in un formato elettronico. Altrimenti devono apparire nella
+copertina dell'intero aggregato.
+
+@item
+TRADUZIONE
+
+La traduzione @`e considerata un tipo di modifica, di conseguenza si possono
+distribuire traduzioni del documento nei termini della sezione 4.
+Rimpiazzare sezioni non modificabili con traduzioni richiede un
+particolare permesso da parte dei detentori del copyright, ma @`e possibile
+includere la traduzione di parti o di tutte le sezioni non modificabili in
+aggiunta alle versioni originali di queste sezioni. @`E possibile includere
+una traduzione di questa licenza, di tutte le avvertenze del documento e
+di tutti i limiti di garanzia, a condizione che si includa anche la
+versione originale in inglese della licenza completa, comprese le
+avvertenze e limitazioni di garanzia. In caso di discordanza tra la
+traduzione e la versione originale inglese di questa licenza o avvertenza
+o limitazione di garanzia, prevale sempre la versione originale inglese.
+
+Se una sezione del documento viene titolata ``Riconoscimenti'', ``Dediche'', o
+``Storia'', il requisito (sezione 4) di preservare il titolo (sezione 1)
+richieder@`a tipicamente il cambiamento del titolo.
+
+@item
+CESSAZIONE DELLA LICENZA
+
+Non si pu@`o sublicenziare il documento, copiarlo, modificarlo, o
+distribuirlo al di fuori dei termini espressamente previsti da questa
+licenza. Ogni altro tentativo di applicare una licenza al documento,
+copiarlo, modificarlo, o distribuirlo @`e nullo e pone fine automaticamente
+ai diritti previsti da questa licenza.
+
+In ogni caso, se cessano tutte le violazioni di questa Licenza, allora la
+specifica licenza di un particolare detentore del copyright viene
+ripristinata (a) in via provvisoria, a meno che e fino a quando il
+detentore del copyright non faccia estinguere esplicitamente e
+definitivamente la licenza, e (b) in via permanente se il detentore del
+copyright non notifica in alcun modo la violazione entro 60 giorni dalla
+cessazione della licenza.
+
+Inoltre, la licenza di un dato detentore del copyright viene ripristinata
+in maniera permanente se quest'ultimo notifica la violazione in maniera
+adeguata, se si tratta della prima volta che si riceve una notifica di
+violazione della licenza (per qualsiasi opera) dallo stesso detentore di
+copyright, e se la violazione viene corretta entro 30 giorni dalla data di
+ricezione della notifica di violazione.
+
+La cessazione dei diritti come specificato in questa sezione non provoca
+la cessazione delle licenze di terze parti che abbiano ricevuto copie o
+diritti secondo questa licenza. Se i diritti sono cessati e non sono stati
+ristabiliti in via permanente, la ricezione di una copia dello stesso
+materiale, in tutto o in parte, non d@`a alcun diritto ad utilizzarlo.
+
+@item
+REVISIONI FUTURE DI QUESTA LICENZA
+
+La Free Software Foundation pu@`o occasionalmente pubblicare versioni nuove
+o rivedute della Licenza per Documentazione Libera GNU. Le nuove versioni
+saranno simili nello spirito alla versione attuale ma potrebbero
+differirne in qualche dettaglio per affrontare nuovi problemi e concetti.
+Si veda @uref{http://www.gnu.org/copyleft/}.
+
+Ad ogni versione della licenza viene dato un numero che la distingue. Se
+il documento specifica che si riferisce ad una versione particolare della
+licenza ``o ogni versione successiva'', si ha la possibilit@`a di seguire
+termini e condizioni sia della versione specificata che di ogni versione
+successiva pubblicata (non come bozza) dalla Free Software Foundation. Se
+il documento non specifica un numero di versione particolare di questa
+licenza, si pu@`o scegliere ogni versione pubblicata (non come bozza) dalla
+Free Software Foundation. Se il documento specifica che un delegato pu@`o
+decidere quale futura versione di questa licenza pu@`o essere utilizzata,
+allora la dichiarazione pubblica di accettazione della versione, da parte
+del delegato, autorizza in maniera permanente a scegliere tale versione
+per il documento.
+
+@item
+CAMBIO DI LICENZA
+
+Il termine ``sito per la collaborazione massiva multiautore'' (o ``sito
+MMC'')
+indica qualsiasi server web che pubblica opere sottoponibili a copyright e
+fornisce a chiunque appositi strumenti per modificare tali opere. Un wiki
+pubblico modificabile da chiunque @`e un esempio di server in questione. Una
+``collaborazione massiva multiautore'' (o ``MMC'') contenuta nel sito indica
+un qualunque insieme di opere sottoponibili a copyright pubblicate sul
+sito MMC.
+
+Il termine ``CC-BY-SA'' indica la licenza Creative Commons Attribution-Share
+Alike 3.0 pubblicata dalla Creative Commons Corporation, un'organizzazione
+senza fini di lucro con sede principale a San Francisco, California, come
+anche le future versioni di tale licenza pubblicate dalla stessa
+organizzazione.
+
+``Incorporare'' significa pubblicare o ripubblicare un documento in tutto o
+in parte, come parte di un altro documento.
+
+Una MMC @`e ``qualificata a cambiare questa licenza'' se ha adottato questa
+licenza e se tutte le opere precedentemente pubblicate con questa licenza
+altrove rispetto alla MMC e successivamente incorporate del tutto o in
+parte nella MMC (1) non hanno testo di copertina o sezioni invarianti e
+(2) sono state incorporate prima del 1° Novembre 2008.
+
+L'operatore di un sito MMC pu@`o ripubblicare un MMC contenuto nel sito con
+una CC-BY-SA nello stesso sito in qualsiasi momento prima del 1° Agosto
+2009, da parte di una MMC qualificata a cambiare questa licenza.
+
+@end enumerate
+
+@c fakenode --- for prepinfo
+@unnumberedsec ADDENDUM: Come usare questa licenza per i vostri documenti
+
+Per applicare questa licenza ad un documento che si @`e scritto, si includa
+una copia della licenza nel documento e si inserisca la seguente nota di
+copyright appena dopo la pagina del titolo:
+
+@smallexample
+@group
+ Copyright (C) @var{<anno>} @var{<il vostro nome>}
+ @`E permesso copiare, distribuire e/o modificare questo documento
+ seguendo i termini della ``Licenza per documentazione libera GNU'', versione 1.3
+ o ogni versione successiva pubblicata dalla Free Software Foundation;
+ senza sezioni non modificabili, senza testi di prima di copertina e di quarta di copertina.
+ Una copia della licenza @`e inclusa nella sezione intitolata
+ ``Licenza per la documentazione libera GNU''.
+@end group
+@end smallexample
+
+Se ci sono sezioni non modificabili, testi di prima di copertina e di
+quarta di copertina, scrivere nella parte ``with@dots{} di copertina'' il testo seguente:
+
+@smallexample
+@group
+ con le seguenti sezioni non modificabili @var{lista dei loro titoli},
+ con i seguenti testi di prima di copertina @var{elenco},
+ e con i seguenti testi di quarta di copertina @var{elenco},
+@end group
+@end smallexample
+
+Se esistono delle sezioni non modificabili ma non i testi di copertina, o
+qualche altra combinazione dei tre elementi sopra riportati, fondere
+assieme le due alternative in modo da conformarsi alla situazione descritta.
+
+Se il vostro documento contiene esempi non banali di programma in codice
+sorgente si raccomanda di rilasciare gli esempi contemporaneamente
+applicandovi anche una licenza di software libero di vostra scelta, come
+per esempio la Licenza Pubblica Generica GNU, al fine di permetterne l'uso
+come software libero.
+
+@end ifclear
+
+@ifnotdocbook
+@node Indice analitico
+@unnumbered Indice analitico
+@end ifnotdocbook
+@printindex cp
+
+@bye
+
+Unresolved Issues:
+------------------
+1. From ADR.
+
+ Robert J. Chassell points out that awk programs should have some indication
+ of how to use them. It would be useful to perhaps have a "programming
+ style" section of the manual that would include this and other tips.
+
+Consistency issues:
+ /.../ regexps are in @code, not @samp
+ ".." strings are in @code, not @samp
+ no @print before @dots
+ values of expressions in the text (@code{x} has the value 15),
+ should be in roman, not @code
+ Use TAB and not tab
+ Use ESC and not ESCAPE
+ Use space and not blank to describe the space bar's character
+ The term "blank" is thus basically reserved for "blank lines" etc.
+ To make dark corners work, the @value{DARKCORNER} has to be outside
+ closing `.' of a sentence and after (pxref{...}).
+ " " should have an @w{} around it
+ Use "non-" only with language names or acronyms, or the words bug and option and null
+ Use @command{ftp} when talking about anonymous ftp
+ Use uppercase and lowercase, not "upper-case" and "lower-case"
+ or "upper case" and "lower case"
+ Use "single precision" and "double precision", not "single-precision" or "double-precision"
+ Use alphanumeric, not alpha-numeric
+ Use POSIX-compliant, not POSIX compliant
+ Use --foo, not -Wfoo when describing long options
+ Use "Bell Laboratories", but not "Bell Labs".
+ Use "behavior" instead of "behaviour".
+ Use "coprocess" instead of "co-process".
+ Use "zeros" instead of "zeroes".
+ Use "nonzero" not "non-zero".
+ Use "runtime" not "run time" or "run-time".
+ 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
+ Use @code{"C"} for the C locale, not ``C'' or @samp{C}.
+ The words "a", "and", "as", "between", "for", "from", "in", "of",
+ "on", "that", "the", "to", "with", and "without",
+ should not be capitalized in @chapter, @section etc.
+ "Into" and "How" should.
+ Search for @dfn; make sure important items are also indexed.
+ "e.g." should always be followed by a comma.
+ "i.e." should always be followed by a comma.
+ 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.
+ 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
+ just the program. I.e.
+
+ {
+ ....
+ }
+
+ not
+ awk '{
+ ...
+ }'
+
+ Do show it when showing command-line arguments, data files, etc, even
+ if there is no output shown.
+
+ Use numbered lists only to show a sequential series of steps.
+
+ Use @code{xxx} for the xxx operator in indexing statements, not @samp.
+ Use MS-Windows not MS Windows
+ Use MS-DOS not MS DOS
+ Use an empty set of parentheses after built-in and awk function names.
+ Use "multiFOO" without a hyphen.
+ Use "time zone" as two words, not "timezone".
+
+Date: Wed, 13 Apr 94 15:20:52 -0400
+From: rms@gnu.org (Richard Stallman)
+To: gnu-prog@gnu.org
+Subject: A reminder: no pathnames in GNU
+
+It's a GNU convention to use the term "file name" for the name of a
+file, never "pathname". We use the term "path" for search paths,
+which are lists of file names. Using it for a single file name as
+well is potentially confusing to users.
+
+So please check any documentation you maintain, if you think you might
+have used "pathname".
+
+Note that "file name" should be two words when it appears as ordinary
+text. It's ok as one word when it's a metasyntactic variable, though.
+
+------------------------
+ORA uses filename, thus the macro.
+
+Suggestions:
+------------
+
+Better sidebars can almost sort of be done with:
+
+ @ifdocbook
+ @macro @sidebar{title, content}
+ @inlinefmt{docbook, <sidebar><title>}
+ \title\
+ @inlinefmt{docbook, </title>}
+ \content\
+ @inlinefmt{docbook, </sidebar>}
+ @end macro
+ @end ifdocbook
+
+
+ @ifnotdocbook
+ @macro @sidebar{title, content}
+ @cartouche
+ @center @b{\title\}
+
+ \content\
+ @end cartouche
+ @end macro
+ @end ifnotdocbook
+
+But to use it you have to say
+
+ @sidebar{Title Here,
+ @include file-with-content
+ }
+
+which sorta sucks.
+
+TODO:
+Check that all dark corners are indexed properly.
+
diff --git a/doc/it/lflashlight-small.xpic b/doc/it/lflashlight-small.xpic
new file mode 100644
index 00000000..94ae7746
--- /dev/null
+++ b/doc/it/lflashlight-small.xpic
@@ -0,0 +1,20 @@
+#! /usr/X11R6/bin/xpic
+80 48 160 80 8
+1 75 144 48 160 56 0 0
+2
+ 160 48 144 56
+1 76 112 48 136 56 0 0
+2
+ 112 56 136 48
+1 77 112 72 136 80 0 0
+2
+ 112 72 136 80
+5 78 128 48 144 80 0 0
+136 64 8 16
+3 79 80 56 112 72 0 0
+1 80 144 64 160 64 0 0
+2
+ 144 64 160 64
+1 81 144 72 160 80 0 0
+2
+ 144 72 160 80
diff --git a/doc/it/lflashlight.eps b/doc/it/lflashlight.eps
new file mode 100644
index 00000000..fdb8cf31
--- /dev/null
+++ b/doc/it/lflashlight.eps
@@ -0,0 +1,135 @@
+%!
+%%Creator: arnold@skeeve (Aharon Robbins)
+%%Title: rflashlight.small.xpic (xpic)
+%%CreationDate: Tue Dec 12 09:51:27 2000
+%%Pages: 1
+%%BoundingBox: 0 0 72 28.8
+% (in inches) at 0 0, width 1, height 0.4
+%%EndComments
+% Prolog for xpic to PostScript converter
+% Author: Mark Moraes
+% $Header: x2ps.pro,v 1.2 88/03/19 16:50:09 moraes Exp
+% %d D - change style SOLID, DOTTED, SHORT-DASH, LONG-DASH, DOT-DASH
+% %s F - change font to fontname
+% %d S - change size (font size in points)
+% (%s) rj %d t - text right just. (%d is TOPLINE, MIDLINE, BOTLINE)
+% (%s) lj %d t - text left just. (%d is TOPLINE, MIDLINE, BOTLINE)
+% (%s) ce %d t - text centered (%d is TOPLINE, MIDLINE, BOTLINE)
+% %d %d l - lineto
+% %d %d m - moveto
+% %d %d s - spline segment
+% x - flush line, spline
+% <wid> <ht> <x> <y> b - box
+% <wid> <ht> <x> <y> e - ellipse
+% %d ss - setscale
+% %d W - change linewidth
+% getpagesize - gets the values of PAGEHEIGHT and PAGEWIDTH
+% %d %d flip - translate by %d, PAGEHEIGHT - %d (this
+% transforms to X windows coordinates)
+save 50 dict begin /xpic exch def
+/StartXpic {newpath 0 0 moveto [] 0 setdash 0 setgray 1 setlinecap} def
+% Set defaults
+/fontname /Times-Roman def
+/ptsize 12 def
+% halign has the values for MIDLINE, TOPLINE, BOTLINE
+/halign 3 array def
+/s {rcurveto} def
+/x {stroke} def
+/l {lineto} def
+/m {moveto} def
+/b {
+ /ury exch def /urx exch def /lly exch def /llx exch def
+ llx lly moveto urx lly lineto urx ury lineto
+ llx ury lineto llx lly lineto stroke
+} def
+/mtrx matrix def
+/e {
+ /yc exch def /xc exch def /yrad exch def /xrad exch def
+ xc xrad add yc moveto
+ /savematrix mtrx currentmatrix def
+ xc yc translate
+ xrad yrad scale
+ 0 0 1 0 360 arc
+ savematrix setmatrix stroke
+} def
+% The next three take the text string, and moveto the right horiz. position
+% leaving the string on the stack.
+/lj {} def
+/rj {dup stringwidth pop neg 0 rmoveto} def
+/ce {dup stringwidth pop 2 div neg 0 rmoveto} def
+% And this is invoked after one of the three above, and
+% computes the vert. pos, and then displays the string.
+/t {halign exch get 0 exch rmoveto show newpath} def
+% Store an array of patterns in /styles - a pattern is an array consisting
+% of an array and an offset. Corresp to xpic patterns
+% solid, dotted, short-dashed, long-dashed, dot-dashed
+/styles [ [] 0 ] [ [1 3] 0 ] [ [4 4] 0 ] [ [8 4] 0 ] [ [1 4 4 4] 0 ]
+ 5 array astore def
+% change style to arg.
+/D {stroke styles exch get aload pop setdash newpath} def
+/W {stroke 0.5 mul setlinewidth newpath} def
+% fontbox takes a fontname off the stack, and returns an array
+% containing the values of the bottom line of the bounding box, the
+% mid line of the bounding box, and the top line of the bounding box
+% of that font, taken from the baseline, scaled to a font of size 1
+/fontbox {
+ findfont dup /FontMatrix get /fm exch def /FontBBox get aload pop
+ /ytop exch def pop /ybot exch def pop
+ /ymid ytop ybot sub 2 div def
+ 0 ybot fm dtransform exch pop % botline
+ dup neg exch % midline - this works better than (ytop-ybot)/2!
+ 0 ytop fm dtransform exch pop exch %topline
+ % now in the order midline, topline, botline.
+ 3 array astore
+} def
+% select font
+/F {
+ dup /fontname exch def fontbox
+ /thisfontbox exch def SF
+} def
+% set point size
+/S {/ptsize exch def SF} def
+% actually set font
+/SF {
+ fontname findfont ptsize curscale div scalefont setfont
+ thisfontbox aload pop
+ 1 1 3 {
+ pop ptsize mul curscale div neg 3 1 roll
+ } for
+ halign astore pop
+} def
+% sets the scale to 72 / n, where n is on the stack, and stores the value
+% in curscale for font scaling
+/curscale 1 def
+/getpagesize{newpath clippath pathbbox /pageheight exch def
+ /pagewidth exch def pop pop newpath} def
+/flip{pageheight exch sub translate} def
+/ss {/curscale exch 72 exch div dup dup scale def} def
+/land {90 rotate} def
+StartXpic
+%%EndProlog
+80 ss
+0.5 W
+0 D
+80 32 m
+64 24 l
+x
+32 24 m
+56 32 l
+x
+32 8 m
+56 0 l
+x
+8 16 56 16 e
+0 24 32 8 b
+64 16 m
+80 16 l
+x
+64 8 m
+80 0 l
+x
+%%Trailer
+showpage
+% Trailer for xpic to PostScript converter
+% $Header: x2ps.tra,v 1.2 89/07/02 15:59:53 moraes Exp $
+xpic end restore
diff --git a/doc/it/lflashlight.pdf b/doc/it/lflashlight.pdf
new file mode 100644
index 00000000..4432fdd0
--- /dev/null
+++ b/doc/it/lflashlight.pdf
@@ -0,0 +1,56 @@
+%PDF-1.3
+%Çì¢
+6 0 obj
+<</Length 7 0 R/Filter /FlateDecode>>
+stream
+xœUA! E÷=EO€¥¯ànôÄ“™ÅèÂëÛ51„P¿Ÿß)D$[ól;pº
+>ÞÀ3~ âE÷*ò²à¹äXpƒ±Z)IwZyBêÈš¢Èl·jFœBæ3fI¡–aáV ¤HàTúMÿÔV›‡*´R‘ÔÈèjÂñowU¢¹Î4ÍEÔì ¼îImä‘tÐ>’Á1Òªë ŸO>endstream
+endobj
+7 0 obj
+168
+endobj
+5 0 obj
+<</Type/Page/MediaBox [0 0 72 28.8]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF]
+/ExtGState 8 0 R
+>>
+/Contents 6 0 R
+>>
+endobj
+3 0 obj
+<< /Type /Pages /Kids [
+5 0 R
+] /Count 1
+>>
+endobj
+1 0 obj
+<</Type /Catalog /Pages 3 0 R
+>>
+endobj
+4 0 obj
+<</Type/ExtGState/Name/R4/TR/Identity/OPM 1/SM 0.02>>
+endobj
+8 0 obj
+<</R4
+4 0 R>>
+endobj
+2 0 obj
+<</Producer(GNU Ghostscript 7.07)>>endobj
+xref
+0 9
+0000000000 65535 f
+0000000471 00000 n
+0000000617 00000 n
+0000000412 00000 n
+0000000519 00000 n
+0000000272 00000 n
+0000000015 00000 n
+0000000253 00000 n
+0000000588 00000 n
+trailer
+<< /Size 9 /Root 1 0 R /Info 2 0 R
+>>
+startxref
+667
+%%EOF
diff --git a/doc/it/margini.texi b/doc/it/margini.texi
new file mode 100644
index 00000000..67b25192
--- /dev/null
+++ b/doc/it/margini.texi
@@ -0,0 +1,7 @@
+@tex
+\global\bindingoffset = 4.6mm
+@end tex
+
+@c \global\topskip = 0mm
+@c \global\baselineskip = 0mm
+@c \global\parskip = 0mm
diff --git a/doc/it/programma-generico.eps b/doc/it/programma-generico.eps
new file mode 100644
index 00000000..db87944d
--- /dev/null
+++ b/doc/it/programma-generico.eps
@@ -0,0 +1,228 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.12.8 (http://cairographics.org)
+%%CreationDate: Wed Dec 17 19:11:08 2014
+%%Pages: 1
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%BoundingBox: 0 -1 265 57
+%%EndComments
+%%BeginProlog
+save
+50 dict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+ 0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+ { globaldict begin /?pdfmark /pop load def /pdfmark
+ /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+ {
+ dup
+ type /stringtype eq
+ { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+ } forall
+ currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+ cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+ { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+ /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+ /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+ cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+11 dict begin
+/FontType 42 def
+/FontName /DroidSansFallback def
+/PaintType 0 def
+/FontMatrix [ 1 0 0 1 0 0 ] def
+/FontBBox [ 0 0 0 0 ] def
+/Encoding 256 array def
+0 1 255 { Encoding exch /.notdef put } for
+Encoding 68 /D put
+Encoding 80 /P put
+Encoding 82 /R put
+Encoding 97 /a put
+Encoding 103 /g put
+Encoding 105 /i put
+Encoding 108 /l put
+Encoding 109 /m put
+Encoding 111 /o put
+Encoding 114 /r put
+Encoding 115 /s put
+Encoding 116 /t put
+Encoding 117 /u put
+/CharStrings 14 dict dup begin
+/.notdef 0 def
+/D 1 def
+/a 2 def
+/t 3 def
+/i 4 def
+/P 5 def
+/r 6 def
+/o 7 def
+/g 8 def
+/m 9 def
+/R 10 def
+/s 11 def
+/u 12 def
+/l 13 def
+end readonly def
+/sfnts [
+<000100000009008000030010637674200000000000000498000000026670676db02159b00000
+049c00000007676c7966cf60e9770000009c000003fc68656164eb09793d000004a400000036
+68686561021600ec000004dc00000024686d747807ac012f00000500000000386c6f63610000
+1d50000005380000003c6d617870006802310000057400000020707265708014882900000594
+000000120002004b000000b500b700030007000037331523373335234b6a6a0d4f4fb7b70d9d
+000000020019000000a000b70008001100003335333216151406232715333236353426231933
+272d2f2a171422211f1fb72f2b2d30a38f242424230000000002000cfffe0074008c00170022
+0000332723062322263534373735342623220727363332161515270706061514163332363563
+04010f1b13153a170d0e11130816161a18171217110b0b1113131515132a0201080f0f0a110c
+16185e4301010e0d0b0b1413000000010004fffe005200a90015000037150623222635352335
+37373315331523151416333252090d12121414090d232309080a13110415164f0a0a1d20114f
+0d0c000200140000002f00bd000b000f0000371406232226353436333216072335332f070706
+0707060707021717ae07070707080707b6890000000200190000008600b7000a001300003715
+23353332161514062327333236353426232330172d20202221131019151515144747b71b1b1b
+1f141213111200000001001600000061008c000f000037072623220615152335331733363332
+610308060f14171203011015098b150118154a89191c0002000efffe0086008c000b00170000
+3734363332161514062322263734262322061514163332360e211b1a22211b1b216012121212
+121212124522252621232425221a1a1a1a1a1b1b000000030005ffc30080008c00250031003e
+0000371507161514062322270615141633333216151406232226353437263534372635343633
+321717342623220615141633323607232206151416333236353426801908191608020b090a16
+151522221b1a1e0c10181a170b07070d0d0d0c0d0d0c0d0e160d0e101017170b890e030b1014
+1801070a05051312181713131a08050e0e0a0a1c1719032b0e0f0f0f0e0e0e4d0c0c0b0b0e0e
+0a08000000010016000000d1008c002100003335342623220615152335342623220615152335
+3317333633321733363332161515ba0d0c1111170d0d1011171204010c1a1e09010d1d161658
+111017164c581110161c47891215171719195a00000200190000009400b7000c001500003715
+233533321615140717232727333236353426232330172c212024321b2c1d1515141317144c4c
+b71a1a240d524c13121111100001000bfffe0068008c001f000037351633323635342e023534
+36333217072623220615141e0215140623220b16130f0f0b2d0d1917151408140e0c0d0a2e0d
+1a1a1a06150b0a0a080915110c11140a12090808080914120c13150000010015fffe00810089
+0013000033272306232226353533151416333236353533156f04010c1b1717160e0d12121712
+14191959581011171b478900000100160000002d00c300030000332335332d1717c300000000
+0000b0002cb000212d000001000000024f5c133ce3d25f0f3cf5000b010000000000c3477867
+00000000c79972b4ffe9ffbc011f010b00000009000200010000000000010000010bffbc0000
+012bffe9fff6011f00010000000000000000000000000000000e0100004b00af00190088000c
+005700040042001400940019006600160094000e0085000500e50016009700190074000b0097
+001500420016000000000000002400000060000000c8000001080000014000000180000001b4
+00000200000002ac000003080000034c000003a8000003e4000003fc00010000000e00e80027
+0105001800020010002f0001000000040012000500014bb0c8514bb007535a58b9000101ff85
+8d59000000>
+] def
+/f-0-0 currentdict end definefont pop
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 -1 265 57
+%%EndPageSetup
+q 0 -1 265 58 rectclip q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 114.254 56.309 m 98.195 28.215 l 114.508 0.246 l 146.82 0.434 l 162.883
+ 28.527 l 146.57 56.496 l 114.254 56.309 l S
+Q q
+26 56.719 170 -57 re W n
+26.316 83.094 m 26.316 -25.965 l 195.043 -25.965 l 195.043 83.094 l 26.316
+ 83.094 l 83.664 24.711 m 89.629 24.711 l 89.629 31.816 l 83.664 31.816
+l 88.406 28.266 l 83.664 24.711 l W n
+q
+26 56.719 170 -57 re W n
+[ 1 0 0 1 0 -0.28125 ] concat
+ q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 65.922 28.547 m 89.035 28.547 l S
+ Q
+Q
+Q q
+0 g
+87.988 26.449 m 95.547 28.34 l 87.988 30.23 l 87.988 26.449 l f*
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 88.047 26.359 m 93.973 28.25 l 88.047 30.141 l 88.047 26.359 l S
+Q q
+0 56.719 265 -57 re W n
+-3.438 57.5 m -3.438 -0.5 l 265.562 -0.5 l 265.562 57.5 l -3.438 57.5 l
+ 190.031 26.449 m 199.543 26.449 l 199.543 30.23 l 190.031 30.23 l 197.59
+ 28.34 l 190.031 26.449 l W n
+q
+0 56.719 265 -57 re W n
+[ 1 0 0 1 0 -0.28125 ] concat
+ q
+0 g
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 167.418 28.621 m 198.598 28.621 l S
+ Q
+Q
+Q q
+0 g
+190.031 26.449 m 197.59 28.34 l 190.031 30.23 l 190.031 26.449 l f*
+0.4724 w
+0 J
+0 j
+[] 0.0 d
+10 M 190.031 26.449 m 197.59 28.34 l 190.031 30.23 l 190.031 26.449 l S
+205.215 48.18 m 202.605 48.18 200.488 46.066 200.488 43.457 c 200.488 13.285
+ l 200.488 10.676 202.605 8.562 205.215 8.562 c 259.953 8.562 l 262.559
+8.562 264.676 10.676 264.676 13.285 c 264.676 43.457 l 264.676 46.066 262.559
+ 48.18 259.953 48.18 c 205.215 48.18 l S
+BT
+10 0 0 10 21.9375 24.9167 Tm
+/f-0-0 1 Tf
+[(D)-4(a)31(t)28(i)]TJ
+8.1875 -0.05 Td
+[(P)16(r)23(o)16(g)19(r)24(a)31(m)19(m)20(a)]TJ
+11.2375 0.1 Td
+[(R)27(i)8(s)16(u)27(l)8(t)27(a)32(t)27(i)]TJ
+ET
+205.215 48.18 m 202.605 48.18 200.488 46.066 200.488 43.457 c 200.488 13.285
+ l 200.488 10.676 202.605 8.562 205.215 8.562 c 259.953 8.562 l 262.559
+8.562 264.676 10.676 264.676 13.285 c 264.676 43.457 l 264.676 46.066 262.559
+ 48.18 259.953 48.18 c 205.215 48.18 l S
+4.965 47.805 m 2.355 47.805 0.238 45.691 0.238 43.082 c 0.238 12.91 l 0.238
+ 10.301 2.355 8.188 4.965 8.188 c 59.703 8.188 l 62.309 8.188 64.426 10.301
+ 64.426 12.91 c 64.426 43.082 l 64.426 45.691 62.309 47.805 59.703 47.805
+ c 4.965 47.805 l S
+Q Q
+showpage
+%%Trailer
+end restore
+%%EOF
diff --git a/doc/it/programma-generico.fig b/doc/it/programma-generico.fig
new file mode 100644
index 00000000..e87f6e3b
--- /dev/null
+++ b/doc/it/programma-generico.fig
@@ -0,0 +1,25 @@
+#FIG 3.2 Produced by xfig version 3.2.5c
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 5805 3465 6300 3465
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 4 0 0 5
+ 4052 3779 4052 3195 3105 3195 3105 3779 4052 3779
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7695 3825 7695 3195 6300 3195 6300 3825 7695 3825
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 4095 3465 4680 3465
+2 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
+ 5490 3915 5745 3456 5475 3006 4950 3015 4695 3474 4965 3924
+ 5490 3915
+4 0 0 50 -1 0 12 0.0000 4 135 360 3375 3510 Dati\001
+4 0 0 50 -1 0 12 0.0000 4 165 810 4860 3510 Programma\001
+4 0 0 50 -1 0 12 0.0000 4 135 810 6525 3510 Risultati\001
diff --git a/doc/it/programma-generico.pdf b/doc/it/programma-generico.pdf
new file mode 100644
index 00000000..d5c751af
--- /dev/null
+++ b/doc/it/programma-generico.pdf
Binary files differ
diff --git a/doc/it/programma-generico.png b/doc/it/programma-generico.png
new file mode 100644
index 00000000..1a877907
--- /dev/null
+++ b/doc/it/programma-generico.png
Binary files differ
diff --git a/doc/it/programma-generico.txt b/doc/it/programma-generico.txt
new file mode 100644
index 00000000..1f6e5124
--- /dev/null
+++ b/doc/it/programma-generico.txt
@@ -0,0 +1,4 @@
+ _________
++------+ / \ +-----------+
+| Dati | -----> < Programma > -----> | Risultati |
++------+ \_________/ +-----------+
diff --git a/doc/it/rflashlight-small.xpic b/doc/it/rflashlight-small.xpic
new file mode 100644
index 00000000..9e78a3f5
--- /dev/null
+++ b/doc/it/rflashlight-small.xpic
@@ -0,0 +1,26 @@
+#! /usr/X11R6/bin/xpic
+80 48 160 80 8
+5 36 96 48 112 80 0 0
+104 64 8 16
+1 37 104 48 128 56 0 0
+2
+ 104 48 128 56
+1 38 104 72 128 80 0 0
+2
+ 104 80 128 72
+2 39 128 56 128 72 0 0
+2
+ 128 56 128 72
+3 40 128 56 160 72 0 0
+1 41 80 72 80 72 0 0
+2
+ 80 72 80 72
+1 42 80 72 96 80 0 0
+2
+ 80 80 96 72
+1 43 80 64 96 64 0 0
+2
+ 80 64 96 64
+1 45 80 48 96 56 0 0
+2
+ 96 56 80 48
diff --git a/doc/it/rflashlight.eps b/doc/it/rflashlight.eps
new file mode 100644
index 00000000..28cb7e25
--- /dev/null
+++ b/doc/it/rflashlight.eps
@@ -0,0 +1,141 @@
+%!
+%%Creator: arnold@skeeve (Aharon Robbins)
+%%Title: flashlight.small.xpic (xpic)
+%%CreationDate: Tue Oct 24 14:41:28 2000
+%%Pages: 1
+%%BoundingBox: 0 0 72 28.8
+% (in inches) at 0 0, width 1, height 0.4
+%%EndComments
+% Prolog for xpic to PostScript converter
+% Author: Mark Moraes
+% $Header: x2ps.pro,v 1.2 88/03/19 16:50:09 moraes Exp
+% %d D - change style SOLID, DOTTED, SHORT-DASH, LONG-DASH, DOT-DASH
+% %s F - change font to fontname
+% %d S - change size (font size in points)
+% (%s) rj %d t - text right just. (%d is TOPLINE, MIDLINE, BOTLINE)
+% (%s) lj %d t - text left just. (%d is TOPLINE, MIDLINE, BOTLINE)
+% (%s) ce %d t - text centered (%d is TOPLINE, MIDLINE, BOTLINE)
+% %d %d l - lineto
+% %d %d m - moveto
+% %d %d s - spline segment
+% x - flush line, spline
+% <wid> <ht> <x> <y> b - box
+% <wid> <ht> <x> <y> e - ellipse
+% %d ss - setscale
+% %d W - change linewidth
+% getpagesize - gets the values of PAGEHEIGHT and PAGEWIDTH
+% %d %d flip - translate by %d, PAGEHEIGHT - %d (this
+% transforms to X windows coordinates)
+save 50 dict begin /xpic exch def
+/StartXpic {newpath 0 0 moveto [] 0 setdash 0 setgray 1 setlinecap} def
+% Set defaults
+/fontname /Times-Roman def
+/ptsize 12 def
+% halign has the values for MIDLINE, TOPLINE, BOTLINE
+/halign 3 array def
+/s {rcurveto} def
+/x {stroke} def
+/l {lineto} def
+/m {moveto} def
+/b {
+ /ury exch def /urx exch def /lly exch def /llx exch def
+ llx lly moveto urx lly lineto urx ury lineto
+ llx ury lineto llx lly lineto stroke
+} def
+/mtrx matrix def
+/e {
+ /yc exch def /xc exch def /yrad exch def /xrad exch def
+ xc xrad add yc moveto
+ /savematrix mtrx currentmatrix def
+ xc yc translate
+ xrad yrad scale
+ 0 0 1 0 360 arc
+ savematrix setmatrix stroke
+} def
+% The next three take the text string, and moveto the right horiz. position
+% leaving the string on the stack.
+/lj {} def
+/rj {dup stringwidth pop neg 0 rmoveto} def
+/ce {dup stringwidth pop 2 div neg 0 rmoveto} def
+% And this is invoked after one of the three above, and
+% computes the vert. pos, and then displays the string.
+/t {halign exch get 0 exch rmoveto show newpath} def
+% Store an array of patterns in /styles - a pattern is an array consisting
+% of an array and an offset. Corresp to xpic patterns
+% solid, dotted, short-dashed, long-dashed, dot-dashed
+/styles [ [] 0 ] [ [1 3] 0 ] [ [4 4] 0 ] [ [8 4] 0 ] [ [1 4 4 4] 0 ]
+ 5 array astore def
+% change style to arg.
+/D {stroke styles exch get aload pop setdash newpath} def
+/W {stroke 0.5 mul setlinewidth newpath} def
+% fontbox takes a fontname off the stack, and returns an array
+% containing the values of the bottom line of the bounding box, the
+% mid line of the bounding box, and the top line of the bounding box
+% of that font, taken from the baseline, scaled to a font of size 1
+/fontbox {
+ findfont dup /FontMatrix get /fm exch def /FontBBox get aload pop
+ /ytop exch def pop /ybot exch def pop
+ /ymid ytop ybot sub 2 div def
+ 0 ybot fm dtransform exch pop % botline
+ dup neg exch % midline - this works better than (ytop-ybot)/2!
+ 0 ytop fm dtransform exch pop exch %topline
+ % now in the order midline, topline, botline.
+ 3 array astore
+} def
+% select font
+/F {
+ dup /fontname exch def fontbox
+ /thisfontbox exch def SF
+} def
+% set point size
+/S {/ptsize exch def SF} def
+% actually set font
+/SF {
+ fontname findfont ptsize curscale div scalefont setfont
+ thisfontbox aload pop
+ 1 1 3 {
+ pop ptsize mul curscale div neg 3 1 roll
+ } for
+ halign astore pop
+} def
+% sets the scale to 72 / n, where n is on the stack, and stores the value
+% in curscale for font scaling
+/curscale 1 def
+/getpagesize{newpath clippath pathbbox /pageheight exch def
+ /pagewidth exch def pop pop newpath} def
+/flip{pageheight exch sub translate} def
+/ss {/curscale exch 72 exch div dup dup scale def} def
+/land {90 rotate} def
+StartXpic
+%%EndProlog
+80 ss
+0.5 W
+0 D
+8 16 24 16 e
+24 32 m
+48 24 l
+x
+24 0 m
+48 8 l
+x
+48 24 m
+0 0 0 -5.33333 0 -16 s
+x
+48 24 80 8 b
+0 8 m
+0 8 l
+x
+0 0 m
+16 8 l
+x
+0 16 m
+16 16 l
+x
+16 24 m
+0 32 l
+x
+%%Trailer
+showpage
+% Trailer for xpic to PostScript converter
+% $Header: x2ps.tra,v 1.2 89/07/02 15:59:53 moraes Exp $
+xpic end restore
diff --git a/doc/it/rflashlight.pdf b/doc/it/rflashlight.pdf
new file mode 100644
index 00000000..72c8561e
--- /dev/null
+++ b/doc/it/rflashlight.pdf
@@ -0,0 +1,57 @@
+%PDF-1.3
+%Çì¢
+6 0 obj
+<</Length 7 0 R/Filter /FlateDecode>>
+stream
+xœEQà †ß9'pBQ»+ì­ÛšeYRº%Ûõ'(] ‚ð£îaÔ5üZa‡ÓUðñœð „—fOàyFÁzD›EÌSH|FN)”,hŒ²ù¨äÀS?iWk¬Ö*Úž%H!F¯Ž¦Ð®®MÁë\m…ø¬
+2±õmƒÆÁ
+òt‡”gÉÏH–¿ðëÞXTR»Û쬊š>@ÿŒ2{¤MéWV¶´õó'E€endstream
+endobj
+7 0 obj
+175
+endobj
+5 0 obj
+<</Type/Page/MediaBox [0 0 72 28.8]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF]
+/ExtGState 8 0 R
+>>
+/Contents 6 0 R
+>>
+endobj
+3 0 obj
+<< /Type /Pages /Kids [
+5 0 R
+] /Count 1
+>>
+endobj
+1 0 obj
+<</Type /Catalog /Pages 3 0 R
+>>
+endobj
+4 0 obj
+<</Type/ExtGState/Name/R4/TR/Identity/OPM 1/SM 0.02>>
+endobj
+8 0 obj
+<</R4
+4 0 R>>
+endobj
+2 0 obj
+<</Producer(GNU Ghostscript 7.07)>>endobj
+xref
+0 9
+0000000000 65535 f
+0000000478 00000 n
+0000000624 00000 n
+0000000419 00000 n
+0000000526 00000 n
+0000000279 00000 n
+0000000015 00000 n
+0000000260 00000 n
+0000000595 00000 n
+trailer
+<< /Size 9 /Root 1 0 R /Info 2 0 R
+>>
+startxref
+674
+%%EOF
diff --git a/doc/it/sidebar.awk b/doc/it/sidebar.awk
new file mode 100644
index 00000000..d1f3efc3
--- /dev/null
+++ b/doc/it/sidebar.awk
@@ -0,0 +1,67 @@
+# sidebar.awk --- add support for sidebars, other stuff to gawk.texi
+
+# Copyright (C) 2013, 2016 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+BEGIN {
+ print "% ****************************************************"
+ print "% * DO NOT MODIFY THIS FILE!!!! *"
+ print "% * It was generated from gawktexi.in by sidebar.awk *"
+ print "% * Edit gawktexi.in instead. *"
+ print "% ****************************************************"
+}
+
+/^@sidebar/ {
+ sub(/^@sidebar[ \t]+/, "", $0)
+ title = $0
+ body = ""
+ collecting = 1
+ next
+}
+
+/^@end[ \t]+sidebar[ \t]*$/ {
+ collecting = 0
+ printf "@cindex sidebar, %s\n", title
+ printf "@ifdocbook\n"
+ printf "@docbook\n"
+ printf "<sidebar><title>%s</title>\n", title
+ printf "@end docbook\n"
+ print body
+ print ""
+ printf "@docbook\n"
+ printf "</sidebar>\n"
+ printf "@end docbook\n"
+ printf "@end ifdocbook\n\n"
+
+ printf "@ifnotdocbook\n"
+ printf "@cartouche\n"
+ printf "@center @b{%s}\n\n", title
+ print body
+ printf "@end cartouche\n"
+ printf "@end ifnotdocbook\n"
+ body = ""
+ next
+}
+
+collecting == 1 {
+ body = body RS $0
+ next
+}
+
+{ print }
diff --git a/doc/it/texinfo.tex b/doc/it/texinfo.tex
new file mode 100644
index 00000000..2a4cdd6c
--- /dev/null
+++ b/doc/it/texinfo.tex
@@ -0,0 +1,11231 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{2016-02-05.07}
+%
+% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
+% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+% 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
+% Free Software Foundation, Inc.
+%
+% This texinfo.tex file is free software: you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation, either version 3 of the
+% License, or (at your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program. If not, see <http://www.gnu.org/licenses/>.
+%
+% As a special exception, when this file is read by TeX when processing
+% a Texinfo source document, you may use the result without
+% restriction. This Exception is an additional permission under section 7
+% of the GNU General Public License, version 3 ("GPLv3").
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+% http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or
+% http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or
+% http://www.gnu.org/software/texinfo/ (the Texinfo home page)
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org. Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem. Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution. For a simple
+% manual foo.texi, however, you can get away with this:
+% tex foo.texi
+% texindex foo.??
+% tex foo.texi
+% tex foo.texi
+% dvips foo.dvi -o # or whatever; this makes foo.ps.
+% The extra TeX runs get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages, to some
+% extent. You can get the existing language-specific files from the
+% full Texinfo distribution.
+%
+% The GNU Texinfo home page is http://www.gnu.org/software/texinfo.
+
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+ \catcode`+=\active \catcode`\_=\active}
+
+\chardef\other=12
+
+% We never want plain's \outer definition of \+ in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Save some plain tex macros whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexfootnote=\footnote
+\let\ptexgtr=>
+\let\ptexhat=^
+\let\ptexi=\i
+\let\ptexindent=\indent
+\let\ptexinsert=\insert
+\let\ptexlbrace=\{
+\let\ptexless=<
+\let\ptexnewwrite\newwrite
+\let\ptexnoindent=\noindent
+\let\ptexplus=+
+\let\ptexraggedright=\raggedright
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexsp=\sp
+\let\ptexstar=\*
+\let\ptexsup=\sup
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Pre-3.0.
+\else
+ \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi
+\ifx\putworderror\undefined \gdef\putworderror{error}\fi
+\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi
+%
+% Aggiunto per l'italiano
+\gdef\putwordla{la}
+\gdef\putwordLa{La}
+\gdef\putwordsivedail{si veda il}
+\gdef\putwordSivedail{Si veda il}
+% Produces article before Section names
+\def\refla#1{\putwordla{} \xrefX[#1,,,,,,,]}
+\def\refLa#1{\putwordLa{} \xrefX[#1,,,,,,,]}
+% Produces article before Chapter names
+\def\pxrefil#1{\putwordsivedail{} \xrefX[#1,,,,,,,]}
+\def\pxrefIl#1{\putwordSivedail{} \xrefX[#1,,,,,,,]}
+\def\xrefil#1{\putwordsivedail{} \xrefX[#1,,,,,,,]}
+\def\xrefIl#1{\putwordSivedail{} \xrefX[#1,,,,,,,]}
+
+% Give the space character the catcode for a space.
+\def\spaceisspace{\catcode`\ =10\relax}
+
+\chardef\dashChar = `\-
+\chardef\slashChar = `\/
+\chardef\underChar = `\_
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+ ap-pen-dix bit-map bit-maps
+ data-base data-bases eshell fall-ing half-way long-est man-u-script
+ man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+ par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+ spell-ing spell-ings
+ stand-alone strong-est time-stamp time-stamps which-ever white-space
+ wide-spread wrap-around
+}
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal. We don't just call \tracingall here,
+% since that produces some useless output on the terminal. We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+ \tracingstats2
+ \tracingpages1
+ \tracinglostchars2 % 2 gives us more in etex
+ \tracingparagraphs1
+ \tracingoutput1
+ \tracingmacros2
+ \tracingrestores1
+ \showboxbreadth\maxdimen \showboxdepth\maxdimen
+ \ifx\eTeXversion\thisisundefined\else % etex gives us more logging
+ \tracingscantokens1
+ \tracingifs1
+ \tracinggroups1
+ \tracingnesting2
+ \tracingassigns1
+ \fi
+ \tracingcommands3 % 3 gives us more in etex
+ \errorcontextlines16
+}%
+
+% @errormsg{MSG}. Do the index-like expansions on MSG, but if things
+% aren't perfect, it's not the end of the world, being an error message,
+% after all.
+%
+\def\errormsg{\begingroup \indexnofonts \doerrormsg}
+\def\doerrormsg#1{\errmessage{#1}}
+
+% add check for \lastpenalty to plain's definitions. If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+ \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+ \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+ \removelastskip\penalty-200\bigskip\fi\fi}
+
+% Output routine
+%
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt }
+
+% Do @cropmarks to get crop marks.
+%
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Output a mark which sets \thischapter, \thissection and \thiscolor.
+% We dump everything together because we only have one kind of mark.
+% This works because we only use \botmark / \topmark, not \firstmark.
+%
+% A mark contains a subexpression of the \ifcase ... \fi construct.
+% \get*marks macros below extract the needed part using \ifcase.
+%
+% Another complication is to let the user choose whether \thischapter
+% (\thissection) refers to the chapter (section) in effect at the top
+% of a page, or that at the bottom of a page.
+
+% \domark is called twice inside \chapmacro, to add one
+% mark before the section break, and one after.
+% In the second call \prevchapterdefs is the same as \lastchapterdefs,
+% and \prevsectiondefs is the same as \lastsectiondefs.
+% Then if the page is not broken at the mark, some of the previous
+% section appears on the page, and we can get the name of this section
+% from \firstmark for @everyheadingmarks top.
+% @everyheadingmarks bottom uses \botmark.
+%
+% See page 260 of The TeXbook.
+\def\domark{%
+ \toks0=\expandafter{\lastchapterdefs}%
+ \toks2=\expandafter{\lastsectiondefs}%
+ \toks4=\expandafter{\prevchapterdefs}%
+ \toks6=\expandafter{\prevsectiondefs}%
+ \toks8=\expandafter{\lastcolordefs}%
+ \mark{%
+ \the\toks0 \the\toks2 % 0: marks for @everyheadingmarks top
+ \noexpand\or \the\toks4 \the\toks6 % 1: for @everyheadingmarks bottom
+ \noexpand\else \the\toks8 % 2: color marks
+ }%
+}
+
+% \gettopheadingmarks, \getbottomheadingmarks,
+% \getcolormarks - extract needed part of mark.
+%
+% \topmark doesn't work for the very first chapter (after the title
+% page or the contents), so we use \firstmark there -- this gets us
+% the mark with the chapter defs, unless the user sneaks in, e.g.,
+% @setcolor (or @url, or @link, etc.) between @contents and the very
+% first @chapter.
+\def\gettopheadingmarks{%
+ \ifcase0\topmark\fi
+ \ifx\thischapter\empty \ifcase0\firstmark\fi \fi
+}
+\def\getbottomheadingmarks{\ifcase1\botmark\fi}
+\def\getcolormarks{\ifcase2\topmark\fi}
+
+% Avoid "undefined control sequence" errors.
+\def\lastchapterdefs{}
+\def\lastsectiondefs{}
+\def\lastsection{}
+\def\prevchapterdefs{}
+\def\prevsectiondefs{}
+\def\lastcolordefs{}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% Main output routine.
+%
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument.
+% \shipout a vbox for a single page, adding an optional header, footer,
+% cropmarks, and footnote. This also causes index entries for this page
+% to be written to the auxiliary files.
+%
+\def\onepageout#1{%
+ \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+ %
+ \ifodd\pageno \advance\hoffset by \bindingoffset
+ \else \advance\hoffset by -\bindingoffset\fi
+ %
+ % Common context changes for both heading and footing.
+ % Do this outside of the \shipout so @code etc. will be expanded in
+ % the headline as they should be, not taken literally (outputting ''code).
+ \def\commmonheadfootline{\let\hsize=\pagewidth \texinfochars}
+ %
+ % Retrieve the information for the headings from the marks in the page,
+ % and call Plain TeX's \makeheadline and \makefootline, which use the
+ % values in \headline and \footline.
+ %
+ % This is used to check if we are on the first page of a chapter.
+ \ifcase1\topmark\fi
+ \let\prevchaptername\thischaptername
+ \ifcase0\firstmark\fi
+ \let\curchaptername\thischaptername
+ %
+ \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+ \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi
+ %
+ \ifx\curchaptername\prevchaptername
+ \let\thischapterheading\thischapter
+ \else
+ % \thischapterheading is the same as \thischapter except it is blank
+ % for the first page of a chapter. This is to prevent the chapter name
+ % being shown twice.
+ \def\thischapterheading{}%
+ \fi
+ %
+ \global\setbox\headlinebox = \vbox{\commmonheadfootline \makeheadline}%
+ \global\setbox\footlinebox = \vbox{\commmonheadfootline \makefootline}%
+ %
+ {%
+ % Set context for writing to auxiliary files like index files.
+ % Have to do this stuff outside the \shipout because we want it to
+ % take effect in \write's, yet the group defined by the \vbox ends
+ % before the \shipout runs.
+ %
+ \indexdummies % don't expand commands in the output.
+ \normalturnoffactive % \ in index entries must not stay \, e.g., if
+ % the page break happens to be in the middle of an example.
+ % We don't want .vr (or whatever) entries like this:
+ % \entry{{\indexbackslash }acronym}{32}{\code {\acronym}}
+ % "\acronym" won't work when it's read back in;
+ % it needs to be
+ % {\code {{\backslashcurfont }acronym}
+ \shipout\vbox{%
+ % Do this early so pdf references go to the beginning of the page.
+ \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi
+ %
+ \ifcropmarks \vbox to \outervsize\bgroup
+ \hsize = \outerhsize
+ \vskip-\topandbottommargin
+ \vtop to0pt{%
+ \line{\ewtop\hfil\ewtop}%
+ \nointerlineskip
+ \line{%
+ \vbox{\moveleft\cornerthick\nstop}%
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}%
+ }%
+ \vss}%
+ \vskip\topandbottommargin
+ \line\bgroup
+ \hfil % center the page within the outer (page) hsize.
+ \ifodd\pageno\hskip\bindingoffset\fi
+ \vbox\bgroup
+ \fi
+ %
+ \unvbox\headlinebox
+ \pagebody{#1}%
+ \ifdim\ht\footlinebox > 0pt
+ % Only leave this space if the footline is nonempty.
+ % (We lessened \vsize for it in \oddfootingyyy.)
+ % The \baselineskip=24pt in plain's \makefootline has no effect.
+ \vskip 24pt
+ \unvbox\footlinebox
+ \fi
+ %
+ \ifcropmarks
+ \egroup % end of \vbox\bgroup
+ \hfil\egroup % end of (centering) \line\bgroup
+ \vskip\topandbottommargin plus1fill minus1fill
+ \boxmaxdepth = \cornerthick
+ \vbox to0pt{\vss
+ \line{%
+ \vbox{\moveleft\cornerthick\nsbot}%
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}%
+ }%
+ \nointerlineskip
+ \line{\ewbot\hfil\ewbot}%
+ }%
+ \egroup % \vbox from first cropmarks clause
+ \fi
+ }% end of \shipout\vbox
+ }% end of group with \indexdummies
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+% Main part of page, including any footnotes
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+ \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1\relax \unvbox#1\relax
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks. Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+ {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+ {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+
+% Argument parsing
+
+% Parse an argument, then pass it to #1. The argument is the rest of
+% the input line (except we remove a trailing comment). #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+% For example, \def\foo{\parsearg\fooxxx}.
+%
+\def\parsearg{\parseargusing{}}
+\def\parseargusing#1#2{%
+ \def\argtorun{#2}%
+ \begingroup
+ \obeylines
+ \spaceisspace
+ #1%
+ \parseargline\empty% Insert the \empty token, see \finishparsearg below.
+}
+
+{\obeylines %
+ \gdef\parseargline#1^^M{%
+ \endgroup % End of the group started in \parsearg.
+ \argremovecomment #1\comment\ArgTerm%
+ }%
+}
+
+% First remove any @comment, then any @c comment. Also remove a @texinfoc
+% comment (see \scanmacro for details). Pass the result on to \argcheckspaces.
+\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm}
+\def\argremovec#1\c#2\ArgTerm{\argremovetexinfoc #1\texinfoc\ArgTerm}
+\def\argremovetexinfoc#1\texinfoc#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm}
+
+% Each occurrence of `\^^M' or `<space>\^^M' is replaced by a single space.
+%
+% \argremovec might leave us with trailing space, e.g.,
+% @end itemize @c foo
+% This space token undergoes the same procedure and is eventually removed
+% by \finishparsearg.
+%
+\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M}
+\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M}
+\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{%
+ \def\temp{#3}%
+ \ifx\temp\empty
+ % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp:
+ \let\temp\finishparsearg
+ \else
+ \let\temp\argcheckspaces
+ \fi
+ % Put the space token in:
+ \temp#1 #3\ArgTerm
+}
+
+% If a _delimited_ argument is enclosed in braces, they get stripped; so
+% to get _exactly_ the rest of the line, we had to prevent such situation.
+% We prepended an \empty token at the very beginning and we expand it now,
+% just before passing the control to \argtorun.
+% (Similarly, we have to think about #3 of \argcheckspacesY above: it is
+% either the null string, or it ends with \^^M---thus there is no danger
+% that a pair of braces would be stripped.
+%
+% But first, we have to remove the trailing space token.
+%
+\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}}
+
+
+% \parseargdef - define a command taking an argument on the line
+%
+% \parseargdef\foo{...}
+% is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+\def\parseargdef#1{%
+ \expandafter \doparseargdef \csname\string#1\endcsname #1%
+}
+\def\doparseargdef#1#2{%
+ \def#2{\parsearg#1}%
+ \def#1##1%
+}
+
+% Several utility definitions with active space:
+{
+ \obeyspaces
+ \gdef\obeyedspace{ }
+
+ % Make each space character in the input produce a normal interword
+ % space in the output. Don't allow a line break at this space, as this
+ % is used only in environments like @example, where each line of input
+ % should produce a line of output anyway.
+ %
+ \gdef\sepspaces{\obeyspaces\let =\tie}
+
+ % If an index command is used in an @example environment, any spaces
+ % therein should become regular spaces in the raw index file, not the
+ % expansion of \tie (\leavevmode \penalty \@M \ ).
+ \gdef\unsepspaces{\let =\space}
+}
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+% Define the framework for environments in texinfo.tex. It's used like this:
+%
+% \envdef\foo{...}
+% \def\Efoo{...}
+%
+% It's the responsibility of \envdef to insert \begingroup before the
+% actual body; @end closes the group after calling \Efoo. \envdef also
+% defines \thisenv, so the current environment is known; @end checks
+% whether the environment name matches. The \checkenv macro can also be
+% used to check whether the current environment is the one expected.
+%
+% Non-false conditionals (@iftex, @ifset) don't fit into this, so they
+% are not treated as environments; they don't open a group. (The
+% implementation of @end takes care not to call \endgroup in this
+% special case.)
+
+
+% At run-time, environments start with this:
+\def\startenvironment#1{\begingroup\def\thisenv{#1}}
+% initialize
+\let\thisenv\empty
+
+% ... but they get defined via ``\envdef\foo{...}'':
+\long\def\envdef#1#2{\def#1{\startenvironment#1#2}}
+\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}}
+
+% Check whether we're in the right environment:
+\def\checkenv#1{%
+ \def\temp{#1}%
+ \ifx\thisenv\temp
+ \else
+ \badenverr
+ \fi
+}
+
+% Environment mismatch, #1 expected:
+\def\badenverr{%
+ \errhelp = \EMsimple
+ \errmessage{This command can appear only \inenvironment\temp,
+ not \inenvironment\thisenv}%
+}
+\def\inenvironment#1{%
+ \ifx#1\empty
+ outside of any environment%
+ \else
+ in environment \expandafter\string#1%
+ \fi
+}
+
+% @end foo executes the definition of \Efoo.
+% But first, it executes a specialized version of \checkenv
+%
+\parseargdef\end{%
+ \if 1\csname iscond.#1\endcsname
+ \else
+ % The general wording of \badenverr may not be ideal.
+ \expandafter\checkenv\csname#1\endcsname
+ \csname E#1\endcsname
+ \endgroup
+ \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\unskip\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=\endofsentencespacefactor\space}
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=\endofsentencespacefactor\space}
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=\endofsentencespacefactor\space}
+
+% @frenchspacing on|off says whether to put extra space after punctuation.
+%
+\def\onword{on}
+\def\offword{off}
+%
+\parseargdef\frenchspacing{%
+ \def\temp{#1}%
+ \ifx\temp\onword \plainfrenchspacing
+ \else\ifx\temp\offword \plainnonfrenchspacing
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @frenchspacing option `\temp', must be on|off}%
+ \fi\fi
+}
+
+% @w prevents a word break. Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox. We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line. According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0). If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large. This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material. In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom. The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+ \ifnum\catcode`\^^M=\active \else
+ \errhelp = \groupinvalidhelp
+ \errmessage{@group invalid in context where filling is enabled}%
+ \fi
+ \startsavinginserts
+ %
+ \setbox\groupbox = \vtop\bgroup
+ % Do @comment since we are called inside an environment such as
+ % @example, where each end-of-line in the input causes an
+ % end-of-line in the output. We don't want the end-of-line after
+ % the `@group' to put extra space in the output. Since @group
+ % should appear on a line by itself (according to the Texinfo
+ % manual), we don't worry about eating any user text.
+ \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it. Thus, space below is not quite equal to space
+% above. But it's pretty close.
+\def\Egroup{%
+ % To get correct interline space between the last line of the group
+ % and the first line afterwards, we have to propagate \prevdepth.
+ \endgraf % Not \par, as it may have been set to \lisppar.
+ \global\dimen1 = \prevdepth
+ \egroup % End the \vtop.
+ \addgroupbox
+ \prevdepth = \dimen1
+ \checkinserts
+}
+
+\def\addgroupbox{
+ % \dimen0 is the vertical size of the group's box.
+ \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox
+ % \dimen2 is how much space is left on the page (more or less).
+ \dimen2 = \pageheight \advance\dimen2 by -\pagetotal
+ % if the group doesn't fit on the current page, and it's a big big
+ % group, force a page break.
+ \ifdim \dimen0 > \dimen2
+ \ifdim \pagetotal < \vfilllimit\pageheight
+ \page
+ \fi
+ \fi
+ \box\groupbox
+}
+
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil \mil=0.001in
+
+\parseargdef\need{%
+ % Ensure vertical mode, so we don't make a big box in the middle of a
+ % paragraph.
+ \par
+ %
+ % If the @need value is less than one line space, it's useless.
+ \dimen0 = #1\mil
+ \dimen2 = \ht\strutbox
+ \advance\dimen2 by \dp\strutbox
+ \ifdim\dimen0 > \dimen2
+ %
+ % Do a \strut just to make the height of this box be normal, so the
+ % normal leading is inserted relative to the preceding line.
+ % And a page break here is fine.
+ \vtop to #1\mil{\strut\vfil}%
+ %
+ % TeX does not even consider page breaks if a penalty added to the
+ % main vertical list is 10000 or more. But in order to see if the
+ % empty box we just added fits on the page, we must make it consider
+ % page breaks. On the other hand, we don't want to actually break the
+ % page after the empty box. So we use a penalty of 9999.
+ %
+ % There is an extremely small chance that TeX will actually break the
+ % page at this \penalty, if there are no other feasible breakpoints in
+ % sight. (If the user is using lots of big @group commands, which
+ % almost-but-not-quite fill up a page, TeX will have a hard time doing
+ % good page breaking, for example.) However, I could not construct an
+ % example where a page broke at this \penalty; if it happens in a real
+ % document, then we can reconsider our strategy.
+ \penalty9999
+ %
+ % Back up by the size of the box, whether we did a page break or not.
+ \kern -#1\mil
+ %
+ % Do not allow a page break right after this kern.
+ \nobreak
+ \fi
+}
+
+% @br forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+ \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph. For more general purposes, use the \margin insertion
+% class. WHICH is `l' or `r'. Not documented, written for gawk manual.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+ \nobreak
+ \kern-\strutdepth
+ \vtop to \strutdepth{%
+ \baselineskip=\strutdepth
+ \vss
+ % if you have multiple lines of stuff to put here, you'll need to
+ % make the vbox yourself of the appropriate size.
+ \ifx#1l%
+ \llap{\ignorespaces #2\hskip\inmarginspacing}%
+ \else
+ \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+ \fi
+ \null
+ }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt
+ \def\lefttext{#1}% have both texts
+ \def\righttext{#2}%
+ \else
+ \def\lefttext{#1}% have only one text
+ \def\righttext{#1}%
+ \fi
+ %
+ \ifodd\pageno
+ \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+ \else
+ \def\temp{\inleftmargin\lefttext}%
+ \fi
+ \temp
+}
+
+% @| inserts a changebar to the left of the current line. It should
+% surround any changed text. This approach does *not* work if the
+% change spans more than two lines of output. To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change). This command
+% is not documented, not supported, and doesn't work.
+%
+\def\|{%
+ % \vadjust can only be used in horizontal mode.
+ \leavevmode
+ %
+ % Append this vertical mode material after the current line in the output.
+ \vadjust{%
+ % We want to insert a rule with the height and depth of the current
+ % leading; that is exactly what \strutbox is supposed to record.
+ \vskip-\baselineskip
+ %
+ % \vadjust-items are inserted at the left edge of the type. So
+ % the \llap here moves out into the left-hand margin.
+ \llap{%
+ %
+ % For a thicker or thinner bar, change the `1pt'.
+ \vrule height\baselineskip width1pt
+ %
+ % This is the space between the bar and the text.
+ \hskip 12pt
+ }%
+ }%
+}
+
+% @include FILE -- \input text of FILE.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+ \pushthisfilestack
+ \def\thisfile{#1}%
+ {%
+ \makevalueexpandable % we want to expand any @value in FILE.
+ \turnoffactive % and allow special characters in the expansion
+ \indexnofonts % Allow `@@' and other weird things in file names.
+ \wlog{texinfo.tex: doing @include of #1^^J}%
+ \edef\temp{\noexpand\input #1 }%
+ %
+ % This trickery is to read FILE outside of a group, in case it makes
+ % definitions, etc.
+ \expandafter
+ }\temp
+ \popthisfilestack
+}
+\def\filenamecatcodes{%
+ \catcode`\\=\other
+ \catcode`~=\other
+ \catcode`^=\other
+ \catcode`_=\other
+ \catcode`|=\other
+ \catcode`<=\other
+ \catcode`>=\other
+ \catcode`+=\other
+ \catcode`-=\other
+ \catcode`\`=\other
+ \catcode`\'=\other
+}
+
+\def\pushthisfilestack{%
+ \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+ \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+ \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+ the stack of filenames is empty.}}
+%
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+ \ifhmode
+ \let\centersub\centerH
+ \else
+ \let\centersub\centerV
+ \fi
+ \centersub{\hfil \ignorespaces#1\unskip \hfil}%
+ \let\centersub\relax % don't let the definition persist, just in case
+}
+\def\centerH#1{{%
+ \hfil\break
+ \advance\hsize by -\leftskip
+ \advance\hsize by -\rightskip
+ \line{#1}%
+ \break
+}}
+%
+\newcount\centerpenalty
+\def\centerV#1{%
+ % The idea here is the same as in \startdefun, \cartouche, etc.: if
+ % @center is the first thing after a section heading, we need to wipe
+ % out the negative parskip inserted by \sectionheading, but still
+ % prevent a page break here.
+ \centerpenalty = \lastpenalty
+ \ifnum\centerpenalty>10000 \vskip\parskip \fi
+ \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi
+ \line{\kern\leftskip #1\kern\rightskip}%
+}
+
+% @sp n outputs n lines of vertical space
+%
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+%
+\def\comment{\begingroup \catcode`\^^M=\active%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other\commentxxx}%
+
+{\catcode`\^^M=\active%
+\gdef\commentxxx#1^^M{\endgroup%
+\futurelet\nexttoken\commentxxxx}%
+\gdef\commentxxxx{\ifx\nexttoken\aftermacro\expandafter\comment\fi}%
+}
+
+\def\c{\begingroup \catcode`\^^M=\active%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\cxxx}
+{\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}}
+% See comment in \scanmacro about why the definitions of @c and @comment differ
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% NCHARS can also be the word `asis' or `none'.
+% We cannot feasibly implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\parseargdef\paragraphindent{%
+ \def\temp{#1}%
+ \ifx\temp\asisword
+ \else
+ \ifx\temp\noneword
+ \defaultparindent = 0pt
+ \else
+ \defaultparindent = #1em
+ \fi
+ \fi
+ \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\parseargdef\exampleindent{%
+ \def\temp{#1}%
+ \ifx\temp\asisword
+ \else
+ \ifx\temp\noneword
+ \lispnarrowing = 0pt
+ \else
+ \lispnarrowing = #1em
+ \fi
+ \fi
+}
+
+% @firstparagraphindent WORD
+% If WORD is `none', then suppress indentation of the first paragraph
+% after a section heading. If WORD is `insert', then do indent at such
+% paragraphs.
+%
+% The paragraph indentation is suppressed or not by calling
+% \suppressfirstparagraphindent, which the sectioning commands do.
+% We switch the definition of this back and forth according to WORD.
+% By default, we suppress indentation.
+%
+\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent}
+\def\insertword{insert}
+%
+\parseargdef\firstparagraphindent{%
+ \def\temp{#1}%
+ \ifx\temp\noneword
+ \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent
+ \else\ifx\temp\insertword
+ \let\suppressfirstparagraphindent = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @firstparagraphindent option `\temp'}%
+ \fi\fi
+}
+
+% Here is how we actually suppress indentation. Redefine \everypar to
+% \kern backwards by \parindent, and then reset itself to empty.
+%
+% We also make \indent itself not actually do anything until the next
+% paragraph.
+%
+\gdef\dosuppressfirstparagraphindent{%
+ \gdef\indent {\restorefirstparagraphindent \indent}%
+ \gdef\noindent{\restorefirstparagraphindent \noindent}%
+ \global\everypar = {\kern -\parindent \restorefirstparagraphindent}%
+}
+%
+\gdef\restorefirstparagraphindent{%
+ \global\let\indent = \ptexindent
+ \global\let\noindent = \ptexnoindent
+ \global\everypar = {}%
+}
+
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% @setfilename INFO-FILENAME - ignored
+\let\setfilename=\comment
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+\newtoks\toksA
+\newtoks\toksB
+\newtoks\toksC
+\newtoks\toksD
+\newbox\boxA
+\newbox\boxB
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set). So we test for \relax and 0 as well as being undefined.
+\ifx\pdfoutput\thisisundefined
+\else
+ \ifx\pdfoutput\relax
+ \else
+ \ifcase\pdfoutput
+ \else
+ \pdftrue
+ \fi
+ \fi
+\fi
+
+% PDF uses PostScript string constants for the names of xref targets,
+% for display in the outlines, and in other places. Thus, we have to
+% double any backslashes. Otherwise, a name like "\node" will be
+% interpreted as a newline (\n), followed by o, d, e. Not good.
+%
+% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
+% related messages. The final outcome is that it is up to the TeX user
+% to double the backslashes and otherwise make the string valid, so
+% that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to
+% do this reliably, so we use it.
+
+% #1 is a control sequence in which to do the replacements,
+% which we \xdef.
+\def\txiescapepdf#1{%
+ \ifx\pdfescapestring\thisisundefined
+ % No primitive available; should we give a warning or log?
+ % Many times it won't matter.
+ \else
+ % The expandable \pdfescapestring primitive escapes parentheses,
+ % backslashes, and other special chars.
+ \xdef#1{\pdfescapestring{#1}}%
+ \fi
+}
+
+\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
+with PDF output, and none of those formats could be found. (.eps cannot
+be supported due to the design of the PDF format; use regular TeX (DVI
+output) for that.)}
+
+\ifpdf
+ %
+ % Color manipulation macros using ideas from pdfcolor.tex,
+ % except using rgb instead of cmyk; the latter is said to render as a
+ % very dark gray on-screen and a very dark halftone in print, instead
+ % of actual black. The dark red here is dark enough to print on paper as
+ % nearly black, but still distinguishable for online viewing. We use
+ % black by default, though.
+ \def\rgbDarkRed{0.50 0.09 0.12}
+ \def\rgbBlack{0 0 0}
+ %
+ % rg sets the color for filling (usual text, etc.);
+ % RG sets the color for stroking (thin rules, e.g., normal _'s).
+ \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}}
+ %
+ % Set color, and create a mark which defines \thiscolor accordingly,
+ % so that \makeheadline knows which color to restore.
+ \def\setcolor#1{%
+ \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}%
+ \domark
+ \pdfsetcolor{#1}%
+ }
+ %
+ \def\maincolor{\rgbBlack}
+ \pdfsetcolor{\maincolor}
+ \edef\thiscolor{\maincolor}
+ \def\lastcolordefs{}
+ %
+ \def\makefootline{%
+ \baselineskip24pt
+ \line{\pdfsetcolor{\maincolor}\the\footline}%
+ }
+ %
+ \def\makeheadline{%
+ \vbox to 0pt{%
+ \vskip-22.5pt
+ \line{%
+ \vbox to8.5pt{}%
+ % Extract \thiscolor definition from the marks.
+ \getcolormarks
+ % Typeset the headline with \maincolor, then restore the color.
+ \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+ }%
+ \vss
+ }%
+ \nointerlineskip
+ }
+ %
+ %
+ \pdfcatalog{/PageMode /UseOutlines}
+ %
+ % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+ \def\dopdfimage#1#2#3{%
+ \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+ \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+ %
+ % pdftex (and the PDF format) support .pdf, .png, .jpg (among
+ % others). Let's try in that order, PDF first since if
+ % someone has a scalable image, presumably better to use that than a
+ % bitmap.
+ \let\pdfimgext=\empty
+ \begingroup
+ \openin 1 #1.pdf \ifeof 1
+ \openin 1 #1.PDF \ifeof 1
+ \openin 1 #1.png \ifeof 1
+ \openin 1 #1.jpg \ifeof 1
+ \openin 1 #1.jpeg \ifeof 1
+ \openin 1 #1.JPG \ifeof 1
+ \errhelp = \nopdfimagehelp
+ \errmessage{Could not find image file #1 for pdf}%
+ \else \gdef\pdfimgext{JPG}%
+ \fi
+ \else \gdef\pdfimgext{jpeg}%
+ \fi
+ \else \gdef\pdfimgext{jpg}%
+ \fi
+ \else \gdef\pdfimgext{png}%
+ \fi
+ \else \gdef\pdfimgext{PDF}%
+ \fi
+ \else \gdef\pdfimgext{pdf}%
+ \fi
+ \closein 1
+ \endgroup
+ %
+ % without \immediate, ancient pdftex seg faults when the same image is
+ % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.)
+ \ifnum\pdftexversion < 14
+ \immediate\pdfimage
+ \else
+ \immediate\pdfximage
+ \fi
+ \ifdim \wd0 >0pt width \pdfimagewidth \fi
+ \ifdim \wd2 >0pt height \pdfimageheight \fi
+ \ifnum\pdftexversion<13
+ #1.\pdfimgext
+ \else
+ {#1.\pdfimgext}%
+ \fi
+ \ifnum\pdftexversion < 14 \else
+ \pdfrefximage \pdflastximage
+ \fi}
+ %
+ \def\pdfmkdest#1{{%
+ % We have to set dummies so commands such as @code, and characters
+ % such as \, aren't expanded when present in a section title.
+ \indexnofonts
+ \turnoffactive
+ \makevalueexpandable
+ \def\pdfdestname{#1}%
+ \txiescapepdf\pdfdestname
+ \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+ }}
+ %
+ % used to mark target names; must be expandable.
+ \def\pdfmkpgn#1{#1}
+ %
+ % by default, use black for everything.
+ \def\urlcolor{\rgbBlack}
+ \def\linkcolor{\rgbBlack}
+ \def\endlink{\setcolor{\maincolor}\pdfendlink}
+ %
+ % Adding outlines to PDF; macros for calculating structure of outlines
+ % come from Petr Olsak
+ \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+ \else \csname#1\endcsname \fi}
+ \def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+ \advance\tempnum by 1
+ \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+ %
+ % #1 is the section text, which is what will be displayed in the
+ % outline by the pdf viewer. #2 is the pdf expression for the number
+ % of subentries (or empty, for subsubsections). #3 is the node text,
+ % which might be empty if this toc entry had no corresponding node.
+ % #4 is the page number
+ %
+ \def\dopdfoutline#1#2#3#4{%
+ % Generate a link to the node text if that exists; else, use the
+ % page number. We could generate a destination for the section
+ % text in the case where a section has no node, but it doesn't
+ % seem worth the trouble, since most documents are normally structured.
+ \edef\pdfoutlinedest{#3}%
+ \ifx\pdfoutlinedest\empty
+ \def\pdfoutlinedest{#4}%
+ \else
+ \txiescapepdf\pdfoutlinedest
+ \fi
+ %
+ % Also escape PDF chars in the display string.
+ \edef\pdfoutlinetext{#1}%
+ \txiescapepdf\pdfoutlinetext
+ %
+ \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+ }
+ %
+ \def\pdfmakeoutlines{%
+ \begingroup
+ % Read toc silently, to get counts of subentries for \pdfoutline.
+ \def\partentry##1##2##3##4{}% ignore parts in the outlines
+ \def\numchapentry##1##2##3##4{%
+ \def\thischapnum{##2}%
+ \def\thissecnum{0}%
+ \def\thissubsecnum{0}%
+ }%
+ \def\numsecentry##1##2##3##4{%
+ \advancenumber{chap\thischapnum}%
+ \def\thissecnum{##2}%
+ \def\thissubsecnum{0}%
+ }%
+ \def\numsubsecentry##1##2##3##4{%
+ \advancenumber{sec\thissecnum}%
+ \def\thissubsecnum{##2}%
+ }%
+ \def\numsubsubsecentry##1##2##3##4{%
+ \advancenumber{subsec\thissubsecnum}%
+ }%
+ \def\thischapnum{0}%
+ \def\thissecnum{0}%
+ \def\thissubsecnum{0}%
+ %
+ % use \def rather than \let here because we redefine \chapentry et
+ % al. a second time, below.
+ \def\appentry{\numchapentry}%
+ \def\appsecentry{\numsecentry}%
+ \def\appsubsecentry{\numsubsecentry}%
+ \def\appsubsubsecentry{\numsubsubsecentry}%
+ \def\unnchapentry{\numchapentry}%
+ \def\unnsecentry{\numsecentry}%
+ \def\unnsubsecentry{\numsubsecentry}%
+ \def\unnsubsubsecentry{\numsubsubsecentry}%
+ \readdatafile{toc}%
+ %
+ % Read toc second time, this time actually producing the outlines.
+ % The `-' means take the \expnumber as the absolute number of
+ % subentries, which we calculated on our first read of the .toc above.
+ %
+ % We use the node names as the destinations.
+ \def\numchapentry##1##2##3##4{%
+ \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+ \def\numsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}%
+ \def\numsubsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}%
+ \def\numsubsubsecentry##1##2##3##4{% count is always zero
+ \dopdfoutline{##1}{}{##3}{##4}}%
+ %
+ % PDF outlines are displayed using system fonts, instead of
+ % document fonts. Therefore we cannot use special characters,
+ % since the encoding is unknown. For example, the eogonek from
+ % Latin 2 (0xea) gets translated to a | character. Info from
+ % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
+ %
+ % TODO this right, we have to translate 8-bit characters to
+ % their "best" equivalent, based on the @documentencoding. Too
+ % much work for too little return. Just use the ASCII equivalents
+ % we use for the index sort strings.
+ %
+ \indexnofonts
+ \setupdatafile
+ % We can have normal brace characters in the PDF outlines, unlike
+ % Texinfo index files. So set that up.
+ \def\{{\lbracecharliteral}%
+ \def\}{\rbracecharliteral}%
+ \catcode`\\=\active \otherbackslash
+ \input \tocreadfilename
+ \endgroup
+ }
+ {\catcode`[=1 \catcode`]=2
+ \catcode`{=\other \catcode`}=\other
+ \gdef\lbracecharliteral[{]%
+ \gdef\rbracecharliteral[}]%
+ ]
+ %
+ \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+ \ifx\PP\D\let\nextsp\relax
+ \else\let\nextsp\skipspaces
+ \addtokens{\filename}{\PP}%
+ \advance\filenamelength by 1
+ \fi
+ \nextsp}
+ \def\getfilename#1{%
+ \filenamelength=0
+ % If we don't expand the argument now, \skipspaces will get
+ % snagged on things like "@value{foo}".
+ \edef\temp{#1}%
+ \expandafter\skipspaces\temp|\relax
+ }
+ \ifnum\pdftexversion < 14
+ \let \startlink \pdfannotlink
+ \else
+ \let \startlink \pdfstartlink
+ \fi
+ % make a live url in pdf output.
+ \def\pdfurl#1{%
+ \begingroup
+ % it seems we really need yet another set of dummies; have not
+ % tried to figure out what each command should do in the context
+ % of @url. for now, just make @/ a no-op, that's the only one
+ % people have actually reported a problem with.
+ %
+ \normalturnoffactive
+ \def\@{@}%
+ \let\/=\empty
+ \makevalueexpandable
+ % do we want to go so far as to use \indexnofonts instead of just
+ % special-casing \var here?
+ \def\var##1{##1}%
+ %
+ \leavevmode\setcolor{\urlcolor}%
+ \startlink attr{/Border [0 0 0]}%
+ user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+ \endgroup}
+ \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+ \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+ \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+ \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+ \def\maketoks{%
+ \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+ \ifx\first0\adn0
+ \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+ \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+ \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+ \else
+ \ifnum0=\countA\else\makelink\fi
+ \ifx\first.\let\next=\done\else
+ \let\next=\maketoks
+ \addtokens{\toksB}{\the\toksD}
+ \ifx\first,\addtokens{\toksB}{\space}\fi
+ \fi
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \next}
+ \def\makelink{\addtokens{\toksB}%
+ {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+ \def\pdflink#1{%
+ \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+ \setcolor{\linkcolor}#1\endlink}
+ \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\else
+ % non-pdf mode
+ \let\pdfmkdest = \gobble
+ \let\pdfurl = \gobble
+ \let\endlink = \relax
+ \let\setcolor = \gobble
+ \let\pdfsetcolor = \gobble
+ \let\pdfmakeoutlines = \relax
+\fi % \ifx\pdfoutput
+
+%
+% @image support for XeTeX
+%
+\newif\ifxeteximgpdf
+\ifx\XeTeXrevision\thisisundefined
+\else
+ %
+ % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+ \def\doxeteximage#1#2#3{%
+ \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+ \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+ %
+ % XeTeX (and the PDF format) support .pdf, .png, .jpg (among
+ % others). Let's try in that order, PDF first since if
+ % someone has a scalable image, presumably better to use that than a
+ % bitmap.
+ \let\xeteximgext=\empty
+ \xeteximgpdffalse
+ \begingroup
+ \openin 1 #1.pdf \ifeof 1
+ \openin 1 #1.PDF \ifeof 1
+ \openin 1 #1.png \ifeof 1
+ \openin 1 #1.jpg \ifeof 1
+ \openin 1 #1.jpeg \ifeof 1
+ \openin 1 #1.JPG \ifeof 1
+ \errmessage{Could not find image file #1 for XeTeX}%
+ \else \gdef\xeteximgext{JPG}%
+ \fi
+ \else \gdef\xeteximgext{jpeg}%
+ \fi
+ \else \gdef\xeteximgext{jpg}%
+ \fi
+ \else \gdef\xeteximgext{png}%
+ \fi
+ \else \gdef\xeteximgext{PDF} \global\xeteximgpdftrue%
+ \fi
+ \else \gdef\xeteximgext{pdf} \global\xeteximgpdftrue%
+ \fi
+ \closein 1
+ \endgroup
+ %
+ \ifxeteximgpdf
+ \XeTeXpdffile "#1".\xeteximgext ""
+ \else
+ \XeTeXpicfile "#1".\xeteximgext ""
+ \fi
+ \ifdim \wd0 >0pt width \xeteximagewidth \fi
+ \ifdim \wd2 >0pt height \xeteximageheight \fi \relax
+ }
+\fi
+
+\message{fonts,}
+
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+ \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+ \csname ten#1\endcsname % change the current font
+}
+
+% Select #1 fonts with the current style.
+%
+\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
+
+% Unfortunately, we have to override this for titles and the like, since
+% in those cases "rm" is bold. Sigh.
+\def\rmisbold{\rm\def\curfontstyle{bf}}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly. There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+% can get a sort of poor man's double spacing by redefining this.
+\def\baselinefactor{1}
+%
+\newdimen\textleading
+\def\setleading#1{%
+ \dimen0 = #1\relax
+ \normalbaselineskip = \baselinefactor\dimen0
+ \normallineskip = \lineskipfactor\normalbaselineskip
+ \normalbaselines
+ \setbox\strutbox =\hbox{%
+ \vrule width0pt height\strutheightpercent\baselineskip
+ depth \strutdepthpercent \baselineskip
+ }%
+}
+
+% PDF CMaps. See also LaTeX's t1.cmap.
+%
+% do nothing with this by default.
+\expandafter\let\csname cmapOT1\endcsname\gobble
+\expandafter\let\csname cmapOT1IT\endcsname\gobble
+\expandafter\let\csname cmapOT1TT\endcsname\gobble
+
+% if we are producing pdf, and we have \pdffontattr, then define cmaps.
+% (\pdffontattr was introduced many years ago, but people still run
+% older pdftex's; it's easy to conditionalize, so we do.)
+\ifpdf \ifx\pdffontattr\thisisundefined \else
+ \begingroup
+ \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+ \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1-0)
+%%Title: (TeX-OT1-0 TeX OT1 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<23> <26> <0023>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+40 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+ }\endgroup
+ \expandafter\edef\csname cmapOT1\endcsname#1{%
+ \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+ }%
+%
+% \cmapOT1IT
+ \begingroup
+ \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+ \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1IT-0)
+%%Title: (TeX-OT1IT-0 TeX OT1IT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1IT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1IT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<25> <26> <0025>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+42 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<23> <0023>
+<24> <00A3>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+ }\endgroup
+ \expandafter\edef\csname cmapOT1IT\endcsname#1{%
+ \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+ }%
+%
+% \cmapOT1TT
+ \begingroup
+ \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+ \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1TT-0)
+%%Title: (TeX-OT1TT-0 TeX OT1TT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1TT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1TT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+5 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<21> <26> <0021>
+<28> <5F> <0028>
+<61> <7E> <0061>
+endbfrange
+32 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <2191>
+<0C> <2193>
+<0D> <0027>
+<0E> <00A1>
+<0F> <00BF>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<20> <2423>
+<27> <2019>
+<60> <2018>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+ }\endgroup
+ \expandafter\edef\csname cmapOT1TT\endcsname#1{%
+ \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+ }%
+\fi\fi
+
+
+% Set the font macro #1 to the font named \fontprefix#2.
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit).
+% Example:
+% #1 = \textrm
+% #2 = \rmshape
+% #3 = 10
+% #4 = \mainmagstep
+% #5 = OT1
+%
+\def\setfont#1#2#3#4#5{%
+ \font#1=\fontprefix#2#3 scaled #4
+ \csname cmap#5\endcsname#1%
+}
+% This is what gets called when #5 of \setfont is empty.
+\let\cmap\gobble
+%
+% (end of cmaps)
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\thisisundefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx} % where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Definitions for a main text size of 11pt. (The default in Texinfo.)
+%
+\def\definetextfontsizexi{%
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1095}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}{OT1}
+\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
+\setfont\defsl\slshape{10}{\magstep1}{OT1TT}
+\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf
+\let\tenttsl=\defttsl \let\tensl=\defsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\def\chapnominalsize{17pt}
+\setfont\chaprm\rmbshape{12}{\magstep2}{OT1}
+\setfont\chapit\itbshape{10}{\magstep3}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep3}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT}
+\setfont\chapsf\sfbshape{17}{1000}{OT1}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}{OT1}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+\def\chapecsize{1728}
+
+% Section fonts (14.4pt).
+\def\secnominalsize{14pt}
+\setfont\secrm\rmbshape{12}{\magstep1}{OT1}
+\setfont\secrmnotbold\rmshape{12}{\magstep1}{OT1}
+\setfont\secit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep2}{OT1}
+\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\secsf\sfbshape{12}{\magstep1}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}{OT1}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+\def\sececsize{1440}
+
+% Subsection fonts (13.15pt).
+\def\ssecnominalsize{13pt}
+\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1}
+\setfont\ssecit\itbshape{10}{1315}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1315}{OT1}
+\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1315}{OT1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+\def\ssececsize{1200}
+
+% Reduced fonts for @acro in text (10pt).
+\def\reducednominalsize{10pt}
+\setfont\reducedrm\rmshape{10}{1000}{OT1}
+\setfont\reducedtt\ttshape{10}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{1000}{OT1}
+\setfont\reducedit\itshape{10}{1000}{OT1IT}
+\setfont\reducedsl\slshape{10}{1000}{OT1}
+\setfont\reducedsf\sfshape{10}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{1000}{OT1}
+\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT}
+\font\reducedi=cmmi10
+\font\reducedsy=cmsy10
+\def\reducedecsize{1000}
+
+\textleading = 13.2pt % line spacing for 11pt CM
+\textfonts % reset the current fonts
+\rm
+} % end of 11pt text font size definitions, \definetextfontsizexi
+
+
+% Definitions to make the main text be 10pt Computer Modern, with
+% section, chapter, etc., sizes following suit. This is for the GNU
+% Press printing of the Emacs 22 manual. Maybe other manuals in the
+% future. Used with @smallbook, which sets the leading to 12pt.
+%
+\def\definetextfontsizex{%
+% Text fonts (10pt).
+\def\textnominalsize{10pt}
+\edef\mainmagstep{1000}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1000}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstephalf}{OT1}
+\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
+\setfont\defsl\slshape{10}{\magstephalf}{OT1TT}
+\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf
+\let\tensl=\defsl \let\tenttsl=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter fonts (14.4pt).
+\def\chapnominalsize{14pt}
+\setfont\chaprm\rmbshape{12}{\magstep1}{OT1}
+\setfont\chapit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep2}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\chapsf\sfbshape{12}{\magstep1}{OT1}
+\let\chapbf\chaprm
+\setfont\chapsc\scbshape{10}{\magstep2}{OT1}
+\font\chapi=cmmi12 scaled \magstep1
+\font\chapsy=cmsy10 scaled \magstep2
+\def\chapecsize{1440}
+
+% Section fonts (12pt).
+\def\secnominalsize{12pt}
+\setfont\secrm\rmbshape{12}{1000}{OT1}
+\setfont\secit\itbshape{10}{\magstep1}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep1}{OT1}
+\setfont\sectt\ttbshape{12}{1000}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT}
+\setfont\secsf\sfbshape{12}{1000}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep1}{OT1}
+\font\seci=cmmi12
+\font\secsy=cmsy10 scaled \magstep1
+\def\sececsize{1200}
+
+% Subsection fonts (10pt).
+\def\ssecnominalsize{10pt}
+\setfont\ssecrm\rmbshape{10}{1000}{OT1}
+\setfont\ssecit\itbshape{10}{1000}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1000}{OT1}
+\setfont\ssectt\ttbshape{10}{1000}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT}
+\setfont\ssecsf\sfbshape{10}{1000}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1000}{OT1}
+\font\sseci=cmmi10
+\font\ssecsy=cmsy10
+\def\ssececsize{1000}
+
+% Reduced fonts for @acro in text (9pt).
+\def\reducednominalsize{9pt}
+\setfont\reducedrm\rmshape{9}{1000}{OT1}
+\setfont\reducedtt\ttshape{9}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{900}{OT1}
+\setfont\reducedit\itshape{9}{1000}{OT1IT}
+\setfont\reducedsl\slshape{9}{1000}{OT1}
+\setfont\reducedsf\sfshape{9}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{900}{OT1}
+\setfont\reducedttsl\ttslshape{10}{900}{OT1TT}
+\font\reducedi=cmmi9
+\font\reducedsy=cmsy9
+\def\reducedecsize{0900}
+
+\divide\parskip by 2 % reduce space between paragraphs
+\textleading = 12pt % line spacing for 10pt CM
+\textfonts % reset the current fonts
+\rm
+} % end of 10pt text font size definitions, \definetextfontsizex
+
+
+% We provide the user-level command
+% @fonttextsize 10
+% (or 11) to redefine the text font size. pt is assumed.
+%
+\def\xiword{11}
+\def\xword{10}
+\def\xwordpt{10pt}
+%
+\parseargdef\fonttextsize{%
+ \def\textsizearg{#1}%
+ %\wlog{doing @fonttextsize \textsizearg}%
+ %
+ % Set \globaldefs so that documents can use this inside @tex, since
+ % makeinfo 4.8 does not support it, but we need it nonetheless.
+ %
+ \begingroup \globaldefs=1
+ \ifx\textsizearg\xword \definetextfontsizex
+ \else \ifx\textsizearg\xiword \definetextfontsizexi
+ \else
+ \errhelp=\EMsimple
+ \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'}
+ \fi\fi
+ \endgroup
+}
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families. We don't
+% bother to reset \scriptfont and \scriptscriptfont; awaiting user need.
+%
+\def\resetmathfonts{%
+ \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy
+ \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf
+ \textfont\ttfam=\tentt \textfont\sffam=\tensf
+}
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE. We do this because \STYLE needs to also set the
+% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire
+% \tenSTYLE to set the current font.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower). These relative commands are used
+% in, e.g., the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+\def\textfonts{%
+ \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+ \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+ \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+ \let\tenttsl=\textttsl
+ \def\curfontsize{text}%
+ \def\lsize{reduced}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{\textleading}}
+\def\titlefonts{%
+ \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+ \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+ \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+ \let\tenttsl=\titlettsl
+ \def\curfontsize{title}%
+ \def\lsize{chap}\def\lllsize{subsec}%
+ \resetmathfonts \setleading{27pt}}
+\def\titlefont#1{{\titlefonts\rmisbold #1}}
+\def\chapfonts{%
+ \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+ \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+ \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+ \let\tenttsl=\chapttsl
+ \def\curfontsize{chap}%
+ \def\lsize{sec}\def\lllsize{text}%
+ \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+ \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+ \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+ \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+ \let\tenttsl=\secttsl
+ \def\curfontsize{sec}%
+ \def\lsize{subsec}\def\lllsize{reduced}%
+ \resetmathfonts \setleading{17pt}}
+\def\subsecfonts{%
+ \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+ \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+ \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+ \let\tenttsl=\ssecttsl
+ \def\curfontsize{ssec}%
+ \def\lsize{text}\def\lllsize{small}%
+ \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts
+\def\reducedfonts{%
+ \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl
+ \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc
+ \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy
+ \let\tenttsl=\reducedttsl
+ \def\curfontsize{reduced}%
+ \def\lsize{small}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{10.5pt}}
+\def\smallfonts{%
+ \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl
+ \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc
+ \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy
+ \let\tenttsl=\smallttsl
+ \def\curfontsize{small}%
+ \def\lsize{smaller}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{10.5pt}}
+\def\smallerfonts{%
+ \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl
+ \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc
+ \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy
+ \let\tenttsl=\smallerttsl
+ \def\curfontsize{smaller}%
+ \def\lsize{smaller}\def\lllsize{smaller}%
+ \resetmathfonts \setleading{9.5pt}}
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}{OT1}
+\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}{OT1}
+\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+
+% Define these just so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Set the fonts to use with the @small... environments.
+\let\smallexamplefonts = \smallfonts
+
+% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample
+% can fit this many characters:
+% 8.5x11=86 smallbook=72 a4=90 a5=69
+% If we use \scriptfonts (8pt), then we can fit this many characters:
+% 8.5x11=90+ smallbook=80 a4=90+ a5=77
+% For me, subjectively, the few extra characters that fit aren't worth
+% the additional smallness of 8pt. So I'm making the default 9pt.
+%
+% By the way, for comparison, here's what fits with @example (10pt):
+% 8.5x11=71 smallbook=60 a4=75 a5=58
+% --karl, 24jan03.
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\definetextfontsizexi
+
+
+\message{markup,}
+
+% Check if we are currently using a typewriter font. Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Markup style infrastructure. \defmarkupstylesetup\INITMACRO will
+% define and register \INITMACRO to be called on markup style changes.
+% \INITMACRO can check \currentmarkupstyle for the innermost
+% style and the set of \ifmarkupSTYLE switches for all styles
+% currently in effect.
+\newif\ifmarkupvar
+\newif\ifmarkupsamp
+\newif\ifmarkupkey
+%\newif\ifmarkupfile % @file == @samp.
+%\newif\ifmarkupoption % @option == @samp.
+\newif\ifmarkupcode
+\newif\ifmarkupkbd
+%\newif\ifmarkupenv % @env == @code.
+%\newif\ifmarkupcommand % @command == @code.
+\newif\ifmarkuptex % @tex (and part of @math, for now).
+\newif\ifmarkupexample
+\newif\ifmarkupverb
+\newif\ifmarkupverbatim
+
+\let\currentmarkupstyle\empty
+
+\def\setupmarkupstyle#1{%
+ \csname markup#1true\endcsname
+ \def\currentmarkupstyle{#1}%
+ \markupstylesetup
+}
+
+\let\markupstylesetup\empty
+
+\def\defmarkupstylesetup#1{%
+ \expandafter\def\expandafter\markupstylesetup
+ \expandafter{\markupstylesetup #1}%
+ \def#1%
+}
+
+% Markup style setup for left and right quotes.
+\defmarkupstylesetup\markupsetuplq{%
+ \expandafter\let\expandafter \temp
+ \csname markupsetuplq\currentmarkupstyle\endcsname
+ \ifx\temp\relax \markupsetuplqdefault \else \temp \fi
+}
+
+\defmarkupstylesetup\markupsetuprq{%
+ \expandafter\let\expandafter \temp
+ \csname markupsetuprq\currentmarkupstyle\endcsname
+ \ifx\temp\relax \markupsetuprqdefault \else \temp \fi
+}
+
+{
+\catcode`\'=\active
+\catcode`\`=\active
+
+\gdef\markupsetuplqdefault{\let`\lq}
+\gdef\markupsetuprqdefault{\let'\rq}
+
+\gdef\markupsetcodequoteleft{\let`\codequoteleft}
+\gdef\markupsetcodequoteright{\let'\codequoteright}
+}
+
+\let\markupsetuplqcode \markupsetcodequoteleft
+\let\markupsetuprqcode \markupsetcodequoteright
+%
+\let\markupsetuplqexample \markupsetcodequoteleft
+\let\markupsetuprqexample \markupsetcodequoteright
+%
+\let\markupsetuplqkbd \markupsetcodequoteleft
+\let\markupsetuprqkbd \markupsetcodequoteright
+%
+\let\markupsetuplqsamp \markupsetcodequoteleft
+\let\markupsetuprqsamp \markupsetcodequoteright
+%
+\let\markupsetuplqverb \markupsetcodequoteleft
+\let\markupsetuprqverb \markupsetcodequoteright
+%
+\let\markupsetuplqverbatim \markupsetcodequoteleft
+\let\markupsetuprqverbatim \markupsetcodequoteright
+
+% Allow an option to not use regular directed right quote/apostrophe
+% (char 0x27), but instead the undirected quote from cmtt (char 0x0d).
+% The undirected quote is ugly, so don't make it the default, but it
+% works for pasting with more pdf viewers (at least evince), the
+% lilypond developers report. xpdf does work with the regular 0x27.
+%
+\def\codequoteright{%
+ \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
+ \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+ '%
+ \else \char'15 \fi
+ \else \char'15 \fi
+}
+%
+% and a similar option for the left quote char vs. a grave accent.
+% Modern fonts display ASCII 0x60 as a grave accent, so some people like
+% the code environments to do likewise.
+%
+\def\codequoteleft{%
+ \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax
+ \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax
+ % [Knuth] pp. 380,381,391
+ % \relax disables Spanish ligatures ?` and !` of \tt font.
+ \relax`%
+ \else \char'22 \fi
+ \else \char'22 \fi
+}
+
+% Commands to set the quote options.
+%
+\parseargdef\codequoteundirected{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETtxicodequoteundirected\endcsname
+ = t%
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETtxicodequoteundirected\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}%
+ \fi\fi
+}
+%
+\parseargdef\codequotebacktick{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETtxicodequotebacktick\endcsname
+ = t%
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETtxicodequotebacktick\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}%
+ \fi\fi
+}
+
+% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font.
+\def\noligaturesquoteleft{\relax\lq}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Font commands.
+
+% #1 is the font command (\sl or \it), #2 is the text to slant.
+% If we are in a monospaced environment, however, 1) always use \ttsl,
+% and 2) do not add an italic correction.
+\def\dosmartslant#1#2{%
+ \ifusingtt
+ {{\ttsl #2}\let\next=\relax}%
+ {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+ \next
+}
+\def\smartslanted{\dosmartslant\sl}
+\def\smartitalic{\dosmartslant\it}
+
+% Output an italic correction unless \next (presumed to be the following
+% character) is such as not to need one.
+\def\smartitaliccorrection{%
+ \ifx\next,%
+ \else\ifx\next-%
+ \else\ifx\next.%
+ \else\ifx\next\.%
+ \else\ifx\next\comma%
+ \else\ptexslash
+ \fi\fi\fi\fi\fi
+ \aftersmartic
+}
+
+% Unconditional use \ttsl, and no ic. @var is set to this for defuns.
+\def\ttslanted#1{{\ttsl #1}}
+
+% @cite is like \smartslanted except unconditionally use \sl. We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+
+\def\aftersmartic{}
+\def\var#1{%
+ \let\saveaftersmartic = \aftersmartic
+ \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
+ \smartslanted{#1}%
+}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}} % roman font
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+% @b, explicit bold. Also @strong.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph. Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+ \def\plainfrenchspacing{%
+ \sfcode`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m
+ \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@m
+ \def\endofsentencespacefactor{1000}% for @. and friends
+ }
+ \def\plainnonfrenchspacing{%
+ \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000
+ \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250
+ \def\endofsentencespacefactor{3000}% for @. and friends
+ }
+\catcode`@=\other
+\def\endofsentencespacefactor{3000}% default
+
+% @t, explicit typewriter.
+\def\t#1{%
+ {\tt \rawbackslash \plainfrenchspacing #1}%
+ \null
+}
+
+% @samp.
+\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}}
+
+% @indicateurl is \samp, that is, with quotes.
+\let\indicateurl=\samp
+
+% @code (and similar) prints in typewriter, but with spaces the same
+% size as normal in the surrounding text, without hyphenation, etc.
+% This is a subroutine for that.
+\def\tclose#1{%
+ {%
+ % Change normal interword space to be same as for the current font.
+ \spaceskip = \fontdimen2\font
+ %
+ % Switch to typewriter.
+ \tt
+ %
+ % But `\ ' produces the large typewriter interword space.
+ \def\ {{\spaceskip = 0pt{} }}%
+ %
+ % Turn off hyphenation.
+ \nohyphenation
+ %
+ \rawbackslash
+ \plainfrenchspacing
+ #1%
+ }%
+ \null % reset spacefactor to 1000
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% (But see \codedashfinish below.)
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+%
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash. -- rms.
+{
+ \catcode`\-=\active \catcode`\_=\active
+ \catcode`\'=\active \catcode`\`=\active
+ \global\let'=\rq \global\let`=\lq % default definitions
+ %
+ \global\def\code{\begingroup
+ \setupmarkupstyle{code}%
+ % The following should really be moved into \setupmarkupstyle handlers.
+ \catcode\dashChar=\active \catcode\underChar=\active
+ \ifallowcodebreaks
+ \let-\codedash
+ \let_\codeunder
+ \else
+ \let-\normaldash
+ \let_\realunder
+ \fi
+ % Given -foo (with a single dash), we do not want to allow a break
+ % after the hyphen.
+ \global\let\codedashprev=\codedash
+ %
+ \codex
+ }
+ %
+ \gdef\codedash{\futurelet\next\codedashfinish}
+ \gdef\codedashfinish{%
+ \normaldash % always output the dash character itself.
+ %
+ % Now, output a discretionary to allow a line break, unless
+ % (a) the next character is a -, or
+ % (b) the preceding character is a -.
+ % E.g., given --posix, we do not want to allow a break after either -.
+ % Given --foo-bar, we do want to allow a break between the - and the b.
+ \ifx\next\codedash \else
+ \ifx\codedashprev\codedash
+ \else \discretionary{}{}{}\fi
+ \fi
+ % we need the space after the = for the case when \next itself is a
+ % space token; it would get swallowed otherwise. As in @code{- a}.
+ \global\let\codedashprev= \next
+ }
+}
+\def\normaldash{-}
+%
+\def\codex #1{\tclose{#1}\endgroup}
+
+\def\codeunder{%
+ % this is all so @math{@code{var_name}+1} can work. In math mode, _
+ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.)
+ % will therefore expand the active definition of _, which is us
+ % (inside @code that is), therefore an endless loop.
+ \ifusingtt{\ifmmode
+ \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_.
+ \else\normalunderscore \fi
+ \discretionary{}{}{}}%
+ {\_}%
+}
+
+% An additional complication: the above will allow breaks after, e.g.,
+% each of the four underscores in __typeof__. This is bad.
+% @allowcodebreaks provides a document-level way to turn breaking at -
+% and _ on and off.
+%
+\newif\ifallowcodebreaks \allowcodebreakstrue
+
+\def\keywordtrue{true}
+\def\keywordfalse{false}
+
+\parseargdef\allowcodebreaks{%
+ \def\txiarg{#1}%
+ \ifx\txiarg\keywordtrue
+ \allowcodebreakstrue
+ \else\ifx\txiarg\keywordfalse
+ \allowcodebreaksfalse
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}%
+ \fi\fi
+}
+
+% For @command, @env, @file, @option quotes seem unnecessary,
+% so use \code rather than \samp.
+\let\command=\code
+\let\env=\code
+\let\file=\code
+\let\option=\code
+
+% @uref (abbreviation for `urlref') aka @url takes an optional
+% (comma-separated) second argument specifying the text to display and
+% an optional third arg as text to display instead of (rather than in
+% addition to) the url itself. First (mandatory) arg is the url.
+
+% TeX-only option to allow changing PDF output to show only the second
+% arg (if given), and not the url (which is then just the link target).
+\newif\ifurefurlonlylink
+
+% The main macro is \urefbreak, which allows breaking at expected
+% places within the url. (There used to be another version, which
+% didn't support automatic breaking.)
+\def\urefbreak{\begingroup \urefcatcodes \dourefbreak}
+\let\uref=\urefbreak
+%
+\def\dourefbreak#1{\urefbreakfinish #1,,,\finish}
+\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example
+ \unsepspaces
+ \pdfurl{#1}%
+ \setbox0 = \hbox{\ignorespaces #3}%
+ \ifdim\wd0 > 0pt
+ \unhbox0 % third arg given, show only that
+ \else
+ \setbox0 = \hbox{\ignorespaces #2}% look for second arg
+ \ifdim\wd0 > 0pt
+ \ifpdf
+ \ifurefurlonlylink
+ % PDF plus option to not display url, show just arg
+ \unhbox0
+ \else
+ % PDF, normally display both arg and url for consistency,
+ % visibility, if the pdf is eventually used to print, etc.
+ \unhbox0\ (\urefcode{#1})%
+ \fi
+ \else
+ \unhbox0\ (\urefcode{#1})% DVI, always show arg and url
+ \fi
+ \else
+ \urefcode{#1}% only url given, so show it
+ \fi
+ \fi
+ \endlink
+\endgroup}
+
+% Allow line breaks around only a few characters (only).
+\def\urefcatcodes{%
+ \catcode`\&=\active \catcode`\.=\active
+ \catcode`\#=\active \catcode`\?=\active
+ \catcode`\/=\active
+}
+{
+ \urefcatcodes
+ %
+ \global\def\urefcode{\begingroup
+ \setupmarkupstyle{code}%
+ \urefcatcodes
+ \let&\urefcodeamp
+ \let.\urefcodedot
+ \let#\urefcodehash
+ \let?\urefcodequest
+ \let/\urefcodeslash
+ \codex
+ }
+ %
+ % By default, they are just regular characters.
+ \global\def&{\normalamp}
+ \global\def.{\normaldot}
+ \global\def#{\normalhash}
+ \global\def?{\normalquest}
+ \global\def/{\normalslash}
+}
+
+% we put a little stretch before and after the breakable chars, to help
+% line breaking of long url's. The unequal skips make look better in
+% cmtt at least, especially for dots.
+\def\urefprestretchamount{.13em}
+\def\urefpoststretchamount{.1em}
+\def\urefprestretch{\urefprebreak \hskip0pt plus\urefprestretchamount\relax}
+\def\urefpoststretch{\urefpostbreak \hskip0pt plus\urefprestretchamount\relax}
+%
+\def\urefcodeamp{\urefprestretch \&\urefpoststretch}
+\def\urefcodedot{\urefprestretch .\urefpoststretch}
+\def\urefcodehash{\urefprestretch \#\urefpoststretch}
+\def\urefcodequest{\urefprestretch ?\urefpoststretch}
+\def\urefcodeslash{\futurelet\next\urefcodeslashfinish}
+{
+ \catcode`\/=\active
+ \global\def\urefcodeslashfinish{%
+ \urefprestretch \slashChar
+ % Allow line break only after the final / in a sequence of
+ % slashes, to avoid line break between the slashes in http://.
+ \ifx\next/\else \urefpoststretch \fi
+ }
+}
+
+% One more complication: by default we'll break after the special
+% characters, but some people like to break before the special chars, so
+% allow that. Also allow no breaking at all, for manual control.
+%
+\parseargdef\urefbreakstyle{%
+ \def\txiarg{#1}%
+ \ifx\txiarg\wordnone
+ \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak}
+ \else\ifx\txiarg\wordbefore
+ \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak}
+ \else\ifx\txiarg\wordafter
+ \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak}
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @urefbreakstyle setting `\txiarg'}%
+ \fi\fi\fi
+}
+\def\wordafter{after}
+\def\wordbefore{before}
+\def\wordnone{none}
+
+\urefbreakstyle after
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdf
+ \def\email#1{\doemail#1,,\finish}
+ \def\doemail#1,#2,#3\finish{\begingroup
+ \unsepspaces
+ \pdfurl{mailto:#1}%
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+ \endlink
+ \endgroup}
+\else
+ \let\email=\uref
+\fi
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+% `example' (@kbd uses ttsl only inside of @example and friends),
+% or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+ \def\txiarg{#1}%
+ \ifx\txiarg\worddistinct
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+ \else\ifx\txiarg\wordexample
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+ \else\ifx\txiarg\wordcode
+ \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @kbdinputstyle setting `\txiarg'}%
+ \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}}
+
+\def\xkey{\key}
+\def\kbdsub#1#2#3\par{%
+ \def\one{#1}\def\three{#3}\def\threex{??}%
+ \ifx\one\xkey\ifx\threex\three \key{#2}%
+ \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+ \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+}
+
+% definition of @key that produces a lozenge. Doesn't adjust to text size.
+%\setfont\keyrm\rmshape{8}{1000}{OT1}
+%\font\keysy=cmsy9
+%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+% \vbox{\hrule\kern-0.4pt
+% \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+% \kern-0.4pt\hrule}%
+% \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+
+% definition of @key with no lozenge. If the current font is already
+% monospace, don't change it; that way, we respect @kbdinputstyle. But
+% if it isn't monospace, then use \tt.
+%
+\def\key#1{{\setupmarkupstyle{key}%
+ \nohyphenation
+ \ifmonospace\else\tt\fi
+ #1}\null}
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+% @acronym for "FBI", "NATO", and the like.
+% We print this one point size smaller, since it's intended for
+% all-uppercase.
+%
+\def\acronym#1{\doacronym #1,,\finish}
+\def\doacronym#1,#2,#3\finish{%
+ {\selectfonts\lsize #1}%
+ \def\temp{#2}%
+ \ifx\temp\empty \else
+ \space ({\unsepspaces \ignorespaces \temp \unskip})%
+ \fi
+ \null % reset \spacefactor=1000
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+ {\plainfrenchspacing #1}%
+ \def\temp{#2}%
+ \ifx\temp\empty \else
+ \space ({\unsepspaces \ignorespaces \temp \unskip})%
+ \fi
+ \null % reset \spacefactor=1000
+}
+
+% @asis just yields its argument. Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}. So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+ \catcode`\_ = \active
+ \gdef\mathunderscore{%
+ \catcode`\_=\active
+ \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+ }
+}
+% Another complication: we want \\ (and @\) to output a math (or tt) \.
+% FYI, plain.tex uses \\ as a temporary control sequence (for no
+% particular reason), but this is not advertised and we don't care.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+ \ifmmode\else % only go into math if not in math mode already
+ \tex
+ \mathunderscore
+ \let\\ = \mathbackslash
+ \mathactive
+ % make the texinfo accent commands work in math mode
+ \let\"=\ddot
+ \let\'=\acute
+ \let\==\bar
+ \let\^=\hat
+ \let\`=\grave
+ \let\u=\breve
+ \let\v=\check
+ \let\~=\tilde
+ \let\dotaccent=\dot
+ % have to provide another name for sup operator
+ \let\mathopsup=\sup
+ $\expandafter\finishmath\fi
+}
+\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex.
+
+% Some active characters (such as <) are spaced differently in math.
+% We have to reset their definitions in case the @math was an argument
+% to a command which sets the catcodes (such as @item or @section).
+%
+{
+ \catcode`^ = \active
+ \catcode`< = \active
+ \catcode`> = \active
+ \catcode`+ = \active
+ \catcode`' = \active
+ \gdef\mathactive{%
+ \let^ = \ptexhat
+ \let< = \ptexless
+ \let> = \ptexgtr
+ \let+ = \ptexplus
+ \let' = \ptexquoteright
+ }
+}
+
+% for @sub and @sup, if in math mode, just do a normal sub/superscript.
+% If in text, use math to place as sub/superscript, but switch
+% into text mode, with smaller fonts. This is a different font than the
+% one used for real math sub/superscripts (8pt vs. 7pt), but let's not
+% fix it (significant additions to font machinery) until someone notices.
+%
+\def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi}
+\def\finishsub#1{$\sb{\hbox{\selectfonts\lllsize #1}}$}%
+%
+\def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi}
+\def\finishsup#1{$\ptexsp{\hbox{\selectfonts\lllsize #1}}$}%
+
+% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
+% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
+% except specified as a normal braced arg, so no newlines to worry about.
+%
+\def\outfmtnametex{tex}
+%
+\long\def\inlinefmt#1{\doinlinefmt #1,\finish}
+\long\def\doinlinefmt#1,#2,\finish{%
+ \def\inlinefmtname{#1}%
+ \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi
+}
+%
+% @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if
+% FMTNAME is tex, else ELSE-TEXT.
+\long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish}
+\long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{%
+ \def\inlinefmtname{#1}%
+ \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi
+}
+%
+% For raw, must switch into @tex before parsing the argument, to avoid
+% setting catcodes prematurely. Doing it this way means that, for
+% example, @inlineraw{html, foo{bar} gets a parse error instead of being
+% ignored. But this isn't important because if people want a literal
+% *right* brace they would have to use a command anyway, so they may as
+% well use a command to get a left brace too. We could re-use the
+% delimiter character idea from \verb, but it seems like overkill.
+%
+\long\def\inlineraw{\tex \doinlineraw}
+\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish}
+\def\doinlinerawtwo#1,#2,\finish{%
+ \def\inlinerawname{#1}%
+ \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi
+ \endgroup % close group opened by \tex.
+}
+
+% @inlineifset{VAR, TEXT} expands TEXT if VAR is @set.
+%
+\long\def\inlineifset#1{\doinlineifset #1,\finish}
+\long\def\doinlineifset#1,#2,\finish{%
+ \def\inlinevarname{#1}%
+ \expandafter\ifx\csname SET\inlinevarname\endcsname\relax
+ \else\ignorespaces#2\fi
+}
+
+% @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set.
+%
+\long\def\inlineifclear#1{\doinlineifclear #1,\finish}
+\long\def\doinlineifclear#1,#2,\finish{%
+ \def\inlinevarname{#1}%
+ \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi
+}
+
+
+\message{glyphs,}
+% and logos.
+
+% @@ prints an @, as does @atchar{}.
+\def\@{\char64 }
+\let\atchar=\@
+
+% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
+% Unless we're in typewriter, use \ecfont because the CM text fonts do
+% not have braces, and we don't want to switch into math.
+\def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}}
+\def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}}
+\let\{=\mylbrace \let\lbracechar=\{
+\let\}=\myrbrace \let\rbracechar=\}
+\begingroup
+ % Definitions to produce \{ and \} commands for indices,
+ % and @{ and @} for the aux/toc files.
+ \catcode`\{ = \other \catcode`\} = \other
+ \catcode`\[ = 1 \catcode`\] = 2
+ \catcode`\! = 0 \catcode`\\ = \other
+ !gdef!lbracecmd[\{]%
+ !gdef!rbracecmd[\}]%
+ !gdef!lbraceatcmd[@{]%
+ !gdef!rbraceatcmd[@}]%
+!endgroup
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \ptexc
+\let\dotaccent = \ptexdot
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \ptext
+\let\ubaraccent = \ptexb
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+ \def\temp{#1}%
+ \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi
+ \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi
+ \else \errmessage{@dotless can be used only with i or j}%
+ \fi\fi
+}
+
+% The \TeX{} logo, as in plain, but resetting the spacing so that a
+% period following counts as ending a sentence. (Idea found in latex.)
+%
+\edef\TeX{\TeX \spacefactor=1000 }
+
+% @LaTeX{} logo. Not quite the same results as the definition in
+% latex.ltx, since we use a different font for the raised A; it's most
+% convenient for us to use an explicitly smaller font, rather than using
+% the \scriptstyle font (since we don't reset \scriptstyle and
+% \scriptscriptstyle).
+%
+\def\LaTeX{%
+ L\kern-.36em
+ {\setbox0=\hbox{T}%
+ \vbox to \ht0{\hbox{%
+ \ifx\textnominalsize\xwordpt
+ % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX.
+ % Revert to plain's \scriptsize, which is 7pt.
+ \count255=\the\fam $\fam\count255 \scriptstyle A$%
+ \else
+ % For 11pt, we can use our lllsize.
+ \selectfonts\lllsize A%
+ \fi
+ }%
+ \vss
+ }}%
+ \kern-.15em
+ \TeX
+}
+
+% Some math mode symbols. Define \ensuremath to switch into math mode
+% unless we are already there. Expansion tricks may not be needed here,
+% but safer, and can't hurt.
+\def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi}
+\def\ensuredmath#1{$\relax#1$}
+%
+\def\bullet{\ensuremath\ptexbullet}
+\def\geq{\ensuremath\ge}
+\def\leq{\ensuremath\le}
+\def\minus{\ensuremath-}
+
+% @dots{} outputs an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in the cm
+% typewriter fonts as three actual period characters; on the other hand,
+% in other typewriter fonts three periods are wider than 1.5em. So do
+% whichever is larger.
+%
+\def\dots{%
+ \leavevmode
+ \setbox0=\hbox{...}% get width of three periods
+ \ifdim\wd0 > 1.5em
+ \dimen0 = \wd0
+ \else
+ \dimen0 = 1.5em
+ \fi
+ \hbox to \dimen0{%
+ \hskip 0pt plus.25fil
+ .\hskip 0pt plus1fil
+ .\hskip 0pt plus1fil
+ .\hskip 0pt plus.5fil
+ }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+ \dots
+ \spacefactor=\endofsentencespacefactor
+}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+%
+% Since these characters are used in examples, they should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+%
+\def\point{$\star$}
+\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}}
+\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% The @error{} command.
+% Adapted from the TeXbook's \boxit.
+%
+\newbox\errorbox
+%
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{%
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{{\it\$}}
+
+% @euro{} comes from a separate font, depending on the current style.
+% We use the free feym* fonts from the eurosym package by Henrik
+% Theiling, which support regular, slanted, bold and bold slanted (and
+% "outlined" (blackboard board, sort of) versions, which we don't need).
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
+%
+% Although only regular is the truly official Euro symbol, we ignore
+% that. The Euro is designed to be slightly taller than the regular
+% font height.
+%
+% feymr - regular
+% feymo - slanted
+% feybr - bold
+% feybo - bold slanted
+%
+% There is no good (free) typewriter version, to my knowledge.
+% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide.
+% Hmm.
+%
+% Also doesn't work in math. Do we need to do math with euro symbols?
+% Hope not.
+%
+%
+\def\euro{{\eurofont e}}
+\def\eurofont{%
+ % We set the font at each command, rather than predefining it in
+ % \textfonts and the other font-switching commands, so that
+ % installations which never need the symbol don't have to have the
+ % font installed.
+ %
+ % There is only one designed size (nominal 10pt), so we always scale
+ % that to the current nominal size.
+ %
+ % By the way, simply using "at 1em" works for cmr10 and the like, but
+ % does not work for cmbx10 and other extended/shrunken fonts.
+ %
+ \def\eurosize{\csname\curfontsize nominalsize\endcsname}%
+ %
+ \ifx\curfontstyle\bfstylename
+ % bold:
+ \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize
+ \else
+ % regular:
+ \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize
+ \fi
+ \thiseurofont
+}
+
+% Glyphs from the EC fonts. We don't use \let for the aliases, because
+% sometimes we redefine the original macro, and the alias should reflect
+% the redefinition.
+%
+% Use LaTeX names for the Icelandic letters.
+\def\DH{{\ecfont \char"D0}} % Eth
+\def\dh{{\ecfont \char"F0}} % eth
+\def\TH{{\ecfont \char"DE}} % Thorn
+\def\th{{\ecfont \char"FE}} % thorn
+%
+\def\guillemetleft{{\ecfont \char"13}}
+\def\guillemotleft{\guillemetleft}
+\def\guillemetright{{\ecfont \char"14}}
+\def\guillemotright{\guillemetright}
+\def\guilsinglleft{{\ecfont \char"0E}}
+\def\guilsinglright{{\ecfont \char"0F}}
+\def\quotedblbase{{\ecfont \char"12}}
+\def\quotesinglbase{{\ecfont \char"0D}}
+%
+% This positioning is not perfect (see the ogonek LaTeX package), but
+% we have the precomposed glyphs for the most common cases. We put the
+% tests to use those glyphs in the single \ogonek macro so we have fewer
+% dummy definitions to worry about for index entries, etc.
+%
+% ogonek is also used with other letters in Lithuanian (IOU), but using
+% the precomposed glyphs for those is not so easy since they aren't in
+% the same EC font.
+\def\ogonek#1{{%
+ \def\temp{#1}%
+ \ifx\temp\macrocharA\Aogonek
+ \else\ifx\temp\macrochara\aogonek
+ \else\ifx\temp\macrocharE\Eogonek
+ \else\ifx\temp\macrochare\eogonek
+ \else
+ \ecfont \setbox0=\hbox{#1}%
+ \ifdim\ht0=1ex\accent"0C #1%
+ \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}%
+ \fi
+ \fi\fi\fi\fi
+ }%
+}
+\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A}
+\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a}
+\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E}
+\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e}
+%
+% Use the European Computer Modern fonts (cm-super in outline format)
+% for non-CM glyphs. That is ec* for regular text and tc* for the text
+% companion symbols (LaTeX TS1 encoding). Both are part of the ec
+% package and follow the same conventions.
+%
+\def\ecfont{\etcfont{e}}
+\def\tcfont{\etcfont{t}}
+%
+\def\etcfont#1{%
+ % We can't distinguish serif/sans and italic/slanted, but this
+ % is used for crude hacks anyway (like adding French and German
+ % quotes to documents typeset with CM, where we lose kerning), so
+ % hopefully nobody will notice/care.
+ \edef\ecsize{\csname\curfontsize ecsize\endcsname}%
+ \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}%
+ \ifmonospace
+ % typewriter:
+ \font\thisecfont = #1ctt\ecsize \space at \nominalsize
+ \else
+ \ifx\curfontstyle\bfstylename
+ % bold:
+ \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize
+ \else
+ % regular:
+ \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize
+ \fi
+ \fi
+ \thisecfont
+}
+
+% @registeredsymbol - R in a circle. The font for the R should really
+% be smaller yet, but lllsize is the best we can do for now.
+% Adapted from the plain.tex definition of \copyright.
+%
+\def\registeredsymbol{%
+ $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}%
+ \hfil\crcr\Orb}}%
+ }$%
+}
+
+% @textdegree - the normal degrees sign.
+%
+\def\textdegree{$^\circ$}
+
+% Laurent Siebenmann reports \Orb undefined with:
+% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38
+% so we'll define it if necessary.
+%
+\ifx\Orb\thisisundefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+% Quotes.
+\chardef\quotedblleft="5C
+\chardef\quotedblright=`\"
+\chardef\quoteleft=`\`
+\chardef\quoteright=`\'
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+%
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\parseargdef\shorttitlepage{%
+ \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+ \endgroup\page\hbox{}\page}
+
+\envdef\titlepage{%
+ % Open one extra group, as we want to close it in the middle of \Etitlepage.
+ \begingroup
+ \parindent=0pt \textfonts
+ % Leave some space at the very top of the page.
+ \vglue\titlepagetopglue
+ % No rule at page bottom unless we print one at the top with @title.
+ \finishedtitlepagetrue
+ %
+ % Most title ``pages'' are actually two pages long, with space
+ % at the top of the second. We don't want the ragged left on the second.
+ \let\oldpage = \page
+ \def\page{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ \let\page = \oldpage
+ \page
+ \null
+ }%
+}
+
+\def\Etitlepage{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ % It is important to do the page break before ending the group,
+ % because the headline and footline are only empty inside the group.
+ % If we use the new definition of \page, we always get a blank page
+ % after the title page, which we certainly don't want.
+ \oldpage
+ \endgroup
+ %
+ % Need this before the \...aftertitlepage checks so that if they are
+ % in effect the toc pages will come out with page numbers.
+ \HEADINGSon
+ %
+ % If they want short, they certainly want long too.
+ \ifsetshortcontentsaftertitlepage
+ \shortcontents
+ \contents
+ \global\let\shortcontents = \relax
+ \global\let\contents = \relax
+ \fi
+ %
+ \ifsetcontentsaftertitlepage
+ \contents
+ \global\let\contents = \relax
+ \global\let\shortcontents = \relax
+ \fi
+}
+
+\def\finishtitlepage{%
+ \vskip4pt \hrule height 2pt width \hsize
+ \vskip\titlepagebottomglue
+ \finishedtitlepagetrue
+}
+
+% Settings used for typesetting titles: no hyphenation, no indentation,
+% don't worry much about spacing, ragged right. This should be used
+% inside a \vbox, and fonts need to be set appropriately first. Because
+% it is always used for titles, nothing else, we call \rmisbold. \par
+% should be specified before the end of the \vbox, since a vbox is a group.
+%
+\def\raggedtitlesettings{%
+ \rmisbold
+ \hyphenpenalty=10000
+ \parindent=0pt
+ \tolerance=5000
+ \ptexraggedright
+}
+
+% Macros to be used within @titlepage:
+
+\let\subtitlerm=\tenrm
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+ \checkenv\titlepage
+ \vbox{\titlefonts \raggedtitlesettings #1\par}%
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+ \checkenv\titlepage
+ {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+ \def\temp{\quotation}%
+ \ifx\thisenv\temp
+ \def\quotationauthor{#1}% printed in \Equotation.
+ \else
+ \checkenv\titlepage
+ \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+ {\secfonts\rmisbold \leftline{#1}}%
+ \fi
+}
+
+
+% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline % headline on even pages
+\newtoks\oddheadline % headline on odd pages
+\newtoks\evenfootline % footline on even pages
+\newtoks\oddfootline % footline on odd pages
+
+% Now make \makeheadline and \makefootline in Plain TeX use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+ \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+ \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what @headings on does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish}
+\def\evenheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish}
+\def\oddheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish}
+\def\evenfootingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish}
+\def\oddfootingyyy #1\|#2\|#3\|#4\finish{%
+ \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+ %
+ % Leave some space for the footline. Hopefully ok to assume
+ % @evenfooting will not be used by itself.
+ \global\advance\pageheight by -12pt
+ \global\advance\vsize by -12pt
+}
+
+\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+
+% @evenheadingmarks top \thischapter <- chapter at the top of a page
+% @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page
+%
+% The same set of arguments for:
+%
+% @oddheadingmarks
+% @evenfootingmarks
+% @oddfootingmarks
+% @everyheadingmarks
+% @everyfootingmarks
+
+% These define \getoddheadingmarks, \getevenheadingmarks,
+% \getoddfootingmarks, and \getevenfootingmarks, each to one of
+% \gettopheadingmarks, \getbottomheadingmarks.
+%
+\def\evenheadingmarks{\headingmarks{even}{heading}}
+\def\oddheadingmarks{\headingmarks{odd}{heading}}
+\def\evenfootingmarks{\headingmarks{even}{footing}}
+\def\oddfootingmarks{\headingmarks{odd}{footing}}
+\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1}
+ \headingmarks{odd}{heading}{#1} }
+\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1}
+ \headingmarks{odd}{footing}{#1} }
+% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
+\def\headingmarks#1#2#3 {%
+ \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname
+ \global\expandafter\let\csname get#1#2marks\endcsname \temp
+}
+
+\everyheadingmarks bottom
+\everyfootingmarks bottom
+
+% @headings double turns headings on for double-sided printing.
+% @headings single turns headings on for single-sided printing.
+% @headings off turns them off.
+% @headings on same as @headings double, retained for compatibility.
+% @headings after turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\headingsoff{% non-global headings elimination
+ \evenheadline={\hfil}\evenfootline={\hfil}%
+ \oddheadline={\hfil}\oddfootline={\hfil}%
+}
+
+\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting
+\HEADINGSoff % it's the default
+
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapterheading\hfil\folio}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapterheading\hfil\folio}}
+\global\oddheadline={\line{\thischapterheading\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% This produces Day Month Year style of output.
+% Only define if not already defined, in case a txi-??.tex file has set
+% up a different format (e.g., txi-cs.tex does this).
+\ifx\today\thisisundefined
+\def\today{%
+ \number\day\space
+ \ifcase\month
+ \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+ \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+ \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+ \fi
+ \space\number\year}
+\fi
+
+% @settitle line... specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemindicate{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % If the item text does not fit in the space we have, put it on a line
+ % by itself, and do not allow a page break either before or after that
+ % line. We do not start a paragraph here because then if the next
+ % command is, e.g., @kindex, the whatsit would get put into the
+ % horizontal list on a line by itself, resulting in extra blank space.
+ \ifdim \wd0>\itemmax
+ %
+ % Make this a paragraph so we get the \parskip glue and wrapping,
+ % but leave it ragged-right.
+ \begingroup
+ \advance\leftskip by-\tableindent
+ \advance\hsize by\tableindent
+ \advance\rightskip by0pt plus1fil\relax
+ \leavevmode\unhbox0\par
+ \endgroup
+ %
+ % We're going to be starting a paragraph, but we don't want the
+ % \parskip glue -- logically it's part of the @item we just started.
+ \nobreak \vskip-\parskip
+ %
+ % Stop a page break at the \parskip glue coming up. However, if
+ % what follows is an environment such as @example, there will be no
+ % \parskip glue; then the negative vskip we just inserted would
+ % cause the example and the item to crash together. So we use this
+ % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+ % \parskip glue after all. Section titles are handled this way also.
+ %
+ \penalty 10001
+ \endgroup
+ \itemxneedsnegativevskipfalse
+ \else
+ % The item text fits into the space. Start a paragraph, so that the
+ % following text (if any) will end up on the same line.
+ \noindent
+ % Do this with kerns and \unhbox so that if there is a footnote in
+ % the item text, it can migrate to the main vertical list and
+ % eventually be printed.
+ \nobreak\kern-\tableindent
+ \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+ \unhbox0
+ \nobreak\kern\dimen0
+ \endgroup
+ \itemxneedsnegativevskiptrue
+ \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+ \let\itemindex\gobble
+ \tablecheck{table}%
+}
+\envdef\ftable{%
+ \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+ \tablecheck{ftable}%
+}
+\envdef\vtable{%
+ \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+ \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+ \ifnum \the\catcode`\^^M=\active
+ \endgroup
+ \errmessage{This command won't work in this context; perhaps the problem is
+ that we are \inenvironment\thisenv}%
+ \def\next{\doignore{#1}}%
+ \else
+ \let\next\tablex
+ \fi
+ \next
+}
+\def\tablex#1{%
+ \def\itemindicate{#1}%
+ \parsearg\tabley
+}
+\def\tabley#1{%
+ {%
+ \makevalueexpandable
+ \edef\temp{\noexpand\tablez #1\space\space\space}%
+ \expandafter
+ }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+ \aboveenvbreak
+ \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+ \ifnum 0#2>0 \tableindent=#2\mil \fi
+ \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+ \itemmax=\tableindent
+ \advance \itemmax by -\itemmargin
+ \advance \leftskip by \tableindent
+ \exdentamount=\tableindent
+ \parindent = 0pt
+ \parskip = \smallskipamount
+ \ifdim \parskip=0pt \parskip=2pt \fi
+ \let\item = \internalBitem
+ \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+ \aboveenvbreak
+ \itemmax=\itemindent
+ \advance\itemmax by -\itemmargin
+ \advance\leftskip by \itemindent
+ \exdentamount=\itemindent
+ \parindent=0pt
+ \parskip=\smallskipamount
+ \ifdim\parskip=0pt \parskip=2pt \fi
+ %
+ % Try typesetting the item mark so that if the document erroneously says
+ % something like @itemize @samp (intending @table), there's an error
+ % right away at the @itemize. It's not the best error message in the
+ % world, but it's better than leaving it to the @item. This means if
+ % the user wants an empty mark, they have to say @w{} not just @w.
+ \def\itemcontents{#1}%
+ \setbox0 = \hbox{\itemcontents}%
+ %
+ % @itemize with no arg is equivalent to @itemize @bullet.
+ \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi
+ %
+ \let\item=\itemizeitem
+}
+
+% Definition of @item while inside @itemize and @enumerate.
+%
+\def\itemizeitem{%
+ \advance\itemno by 1 % for enumerations
+ {\let\par=\endgraf \smallbreak}% reasonable place to break
+ {%
+ % If the document has an @itemize directly after a section title, a
+ % \nobreak will be last on the list, and \sectionheading will have
+ % done a \vskip-\parskip. In that case, we don't want to zero
+ % parskip, or the item text will crash with the heading. On the
+ % other hand, when there is normal text preceding the item (as there
+ % usually is), we do want to zero parskip, or there would be too much
+ % space. In that case, we won't have a \nobreak before. At least
+ % that's the theory.
+ \ifnum\lastpenalty<10000 \parskip=0in \fi
+ \noindent
+ \hbox to 0pt{\hss \itemcontents \kern\itemmargin}%
+ %
+ \ifinner\else
+ \vadjust{\penalty 1200}% not good to break after first line of item.
+ \fi
+ % We can be in inner vertical mode in a footnote, although an
+ % @itemize looks awful there.
+ }%
+ \flushcr
+}
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list. No
+% argument is the same as `1'.
+%
+\envparseargdef\enumerate{\enumeratey #1 \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+ % If we were given no argument, pretend we were given `1'.
+ \def\thearg{#1}%
+ \ifx\thearg\empty \def\thearg{1}\fi
+ %
+ % Detect if the argument is a single token. If so, it might be a
+ % letter. Otherwise, the only valid thing it can be is a number.
+ % (We will always have one token, because of the test we just made.
+ % This is a good thing, since \splitoff doesn't work given nothing at
+ % all -- the first parameter is undelimited.)
+ \expandafter\splitoff\thearg\endmark
+ \ifx\rest\empty
+ % Only one token in the argument. It could still be anything.
+ % A ``lowercase letter'' is one whose \lccode is nonzero.
+ % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+ % not equal to itself.
+ % Otherwise, we assume it's a number.
+ %
+ % We need the \relax at the end of the \ifnum lines to stop TeX from
+ % continuing to look for a <number>.
+ %
+ \ifnum\lccode\expandafter`\thearg=0\relax
+ \numericenumerate % a number (we hope)
+ \else
+ % It's a letter.
+ \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+ \lowercaseenumerate % lowercase letter
+ \else
+ \uppercaseenumerate % uppercase letter
+ \fi
+ \fi
+ \else
+ % Multiple tokens in the argument. We hope it's a number.
+ \numericenumerate
+ \fi
+}
+
+% An @enumerate whose labels are integers. The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+ \itemno = \thearg
+ \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more lowercase letters in @enumerate; get a bigger
+ alphabet}%
+ \fi
+ \char\lccode\itemno
+ }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more uppercase letters in @enumerate; get a bigger
+ alphabet}
+ \fi
+ \char\uccode\itemno
+ }%
+}
+
+% Call \doitemize, adding a period to the first argument and supplying the
+% common last two arguments. Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+ \advance\itemno by -1
+ \doitemize{#1.}\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble. Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+% @multitable @columnfractions .25 .3 .45
+% @item ...
+%
+% Numbers following @columnfractions are the percent of the total
+% current hsize to be used for each column. You may use as many
+% columns as desired.
+
+
+% Or use a template:
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item ...
+% using the widest term desired in each column.
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab do not need to be on their own lines, but it will not hurt
+% if they are.
+
+% Sample multitable:
+
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item first col stuff @tab second col stuff @tab third col
+% @item
+% first col stuff
+% @tab
+% second col stuff
+% @tab
+% third col
+% @item first col stuff @tab second col stuff
+% @tab Many paragraphs of text may be used in any column.
+%
+% They will wrap at the width determined by the template.
+% @item@tab@tab This will be in third column.
+% @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+% to baseline.
+% 0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the @columnfraction, usually a decimal number like .5, but might
+% be just 1. We just use it, whatever it is.
+%
+\def\pickupwholefraction#1 {%
+ \global\advance\colcount by 1
+ \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}%
+ \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+ \def\firstarg{#1}%
+ \ifx\firstarg\xendsetuptable
+ \let\go = \relax
+ \else
+ \ifx\firstarg\xcolumnfractions
+ \global\setpercenttrue
+ \else
+ \ifsetpercent
+ \let\go\pickupwholefraction
+ \else
+ \global\advance\colcount by 1
+ \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a
+ % separator; typically that is always in the input, anyway.
+ \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+ \fi
+ \fi
+ \ifx\go\pickupwholefraction
+ % Put the argument back for the \pickupwholefraction call, so
+ % we'll always have a period there to be parsed.
+ \def\go{\pickupwholefraction#1}%
+ \else
+ \let\go = \setuptable
+ \fi%
+ \fi
+ \go
+}
+
+% multitable-only commands.
+%
+% @headitem starts a heading row, which we typeset in bold. Assignments
+% have to be global since we are inside the implicit group of an
+% alignment entry. \everycr below resets \everytab so we don't have to
+% undo it ourselves.
+\def\headitemfont{\b}% for people to use in the template row; not changeable
+\def\headitem{%
+ \checkenv\multitable
+ \crcr
+ \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings
+ \global\everytab={\bf}% can't use \headitemfont since the parsing differs
+ \the\everytab % for the first item
+}%
+%
+% default for tables with no headings.
+\let\headitemcrhook=\relax
+%
+% A \tab used to include \hskip1sp. But then the space in a template
+% line is not enough. That is bad. So let's go back to just `&' until
+% we again encounter the problem the 1sp was intended to solve.
+% --karl, nathan@acm.org, 20apr99.
+\def\tab{\checkenv\multitable &\the\everytab}%
+
+% @multitable ... @end multitable definitions:
+%
+\newtoks\everytab % insert after every tab.
+%
+\envdef\multitable{%
+ \vskip\parskip
+ \startsavinginserts
+ %
+ % @item within a multitable starts a normal row.
+ % We use \def instead of \let so that if one of the multitable entries
+ % contains an @itemize, we don't choke on the \item (seen as \crcr aka
+ % \endtemplate) expanding \doitemize.
+ \def\item{\crcr}%
+ %
+ \tolerance=9500
+ \hbadness=9500
+ \setmultitablespacing
+ \parskip=\multitableparskip
+ \parindent=\multitableparindent
+ \overfullrule=0pt
+ \global\colcount=0
+ %
+ \everycr = {%
+ \noalign{%
+ \global\everytab={}% Reset from possible headitem.
+ \global\colcount=0 % Reset the column counter.
+ %
+ % Check for saved footnotes, etc.:
+ \checkinserts
+ %
+ % Perhaps a \nobreak, then reset:
+ \headitemcrhook
+ \global\let\headitemcrhook=\relax
+ }%
+ }%
+ %
+ \parsearg\domultitable
+}
+\def\domultitable#1{%
+ % To parse everything between @multitable and @item:
+ \setuptable#1 \endsetuptable
+ %
+ % This preamble sets up a generic column definition, which will
+ % be used as many times as user calls for columns.
+ % \vtop will set a single line and will also let text wrap and
+ % continue for many paragraphs if desired.
+ \halign\bgroup &%
+ \global\advance\colcount by 1
+ \multistrut
+ \vtop{%
+ % Use the current \colcount to find the correct column width:
+ \hsize=\expandafter\csname col\the\colcount\endcsname
+ %
+ % In order to keep entries from bumping into each other
+ % we will add a \leftskip of \multitablecolspace to all columns after
+ % the first one.
+ %
+ % If a template has been used, we will add \multitablecolspace
+ % to the width of each template entry.
+ %
+ % If the user has set preamble in terms of percent of \hsize we will
+ % use that dimension as the width of the column, and the \leftskip
+ % will keep entries from bumping into each other. Table will start at
+ % left margin and final column will justify at right margin.
+ %
+ % Make sure we don't inherit \rightskip from the outer environment.
+ \rightskip=0pt
+ \ifnum\colcount=1
+ % The first column will be indented with the surrounding text.
+ \advance\hsize by\leftskip
+ \else
+ \ifsetpercent \else
+ % If user has not set preamble in terms of percent of \hsize
+ % we will advance \hsize by \multitablecolspace.
+ \advance\hsize by \multitablecolspace
+ \fi
+ % In either case we will make \leftskip=\multitablecolspace:
+ \leftskip=\multitablecolspace
+ \fi
+ % Ignoring space at the beginning and end avoids an occasional spurious
+ % blank line, when TeX decides to break the line at the space before the
+ % box from the multistrut, so the strut ends up on a line by itself.
+ % For example:
+ % @multitable @columnfractions .11 .89
+ % @item @code{#}
+ % @tab Legal holiday which is valid in major parts of the whole country.
+ % Is automatically provided with highlighting sequences respectively
+ % marking characters.
+ \noindent\ignorespaces##\unskip\multistrut
+ }\cr
+}
+\def\Emultitable{%
+ \crcr
+ \egroup % end the \halign
+ \global\setpercentfalse
+}
+
+\def\setmultitablespacing{%
+ \def\multistrut{\strut}% just use the standard line spacing
+ %
+ % Compute \multitablelinespace (if not defined by user) for use in
+ % \multitableparskip calculation. We used define \multistrut based on
+ % this, but (ironically) that caused the spacing to be off.
+ % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
+\ifdim\multitablelinespace=0pt
+\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
+\global\advance\multitablelinespace by-\ht0
+\fi
+% Test to see if parskip is larger than space between lines of
+% table. If not, do nothing.
+% If so, set to same dimension as multitablelinespace.
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+ % than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+ % than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @ifnotxml always succeed. They currently do nothing; we don't
+% attempt to check whether the conditionals are properly nested. But we
+% have to remember that they are conditionals, so that @end doesn't
+% attempt to close an environment group.
+%
+\def\makecond#1{%
+ \expandafter\let\csname #1\endcsname = \relax
+ \expandafter\let\csname iscond.#1\endcsname = 1
+}
+\makecond{iftex}
+\makecond{ifnotdocbook}
+\makecond{ifnothtml}
+\makecond{ifnotinfo}
+\makecond{ifnotplaintext}
+\makecond{ifnotxml}
+
+% Ignore @ignore, @ifhtml, @ifinfo, and the like.
+%
+\def\direntry{\doignore{direntry}}
+\def\documentdescription{\doignore{documentdescription}}
+\def\docbook{\doignore{docbook}}
+\def\html{\doignore{html}}
+\def\ifdocbook{\doignore{ifdocbook}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\ifplaintext{\doignore{ifplaintext}}
+\def\ifxml{\doignore{ifxml}}
+\def\ignore{\doignore{ignore}}
+\def\menu{\doignore{menu}}
+\def\xml{\doignore{xml}}
+
+% Ignore text until a line `@end #1', keeping track of nested conditionals.
+%
+% A count to remember the depth of nesting.
+\newcount\doignorecount
+
+\def\doignore#1{\begingroup
+ % Scan in ``verbatim'' mode:
+ \obeylines
+ \catcode`\@ = \other
+ \catcode`\{ = \other
+ \catcode`\} = \other
+ %
+ % Make sure that spaces turn into tokens that match what \doignoretext wants.
+ \spaceisspace
+ %
+ % Count number of #1's that we've seen.
+ \doignorecount = 0
+ %
+ % Swallow text until we reach the matching `@end #1'.
+ \dodoignore{#1}%
+}
+
+{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source.
+ \obeylines %
+ %
+ \gdef\dodoignore#1{%
+ % #1 contains the command name as a string, e.g., `ifinfo'.
+ %
+ % Define a command to find the next `@end #1'.
+ \long\def\doignoretext##1^^M@end #1{%
+ \doignoretextyyy##1^^M@#1\_STOP_}%
+ %
+ % And this command to find another #1 command, at the beginning of a
+ % line. (Otherwise, we would consider a line `@c @ifset', for
+ % example, to count as an @ifset for nesting.)
+ \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}%
+ %
+ % And now expand that command.
+ \doignoretext ^^M%
+ }%
+}
+
+\def\doignoreyyy#1{%
+ \def\temp{#1}%
+ \ifx\temp\empty % Nothing found.
+ \let\next\doignoretextzzz
+ \else % Found a nested condition, ...
+ \advance\doignorecount by 1
+ \let\next\doignoretextyyy % ..., look for another.
+ % If we're here, #1 ends with ^^M\ifinfo (for example).
+ \fi
+ \next #1% the token \_STOP_ is present just after this macro.
+}
+
+% We have to swallow the remaining "\_STOP_".
+%
+\def\doignoretextzzz#1{%
+ \ifnum\doignorecount = 0 % We have just found the outermost @end.
+ \let\next\enddoignore
+ \else % Still inside a nested condition.
+ \advance\doignorecount by -1
+ \let\next\doignoretext % Look for the next @end.
+ \fi
+ \next
+}
+
+% Finish off ignored text.
+{ \obeylines%
+ % Ignore anything after the last `@end #1'; this matters in verbatim
+ % environments, where otherwise the newline after an ignored conditional
+ % would result in a blank line in the output.
+ \gdef\enddoignore#1^^M{\endgroup\ignorespaces}%
+}
+
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+% We rely on the fact that \parsearg sets \catcode`\ =10.
+%
+\parseargdef\set{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+ {%
+ \makevalueexpandable
+ \def\temp{#2}%
+ \edef\next{\gdef\makecsname{SET#1}}%
+ \ifx\temp\empty
+ \next{}%
+ \else
+ \setzzz#2\endsetzzz
+ \fi
+ }%
+}
+% Remove the trailing space \setxxx inserted.
+\def\setzzz#1 \endsetzzz{\next{#1}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\parseargdef\clear{%
+ {%
+ \makevalueexpandable
+ \global\expandafter\let\csname SET#1\endcsname=\relax
+ }%
+}
+
+% @value{foo} gets the text saved in variable foo.
+\def\value{\begingroup\makevalueexpandable\valuexxx}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+{
+ \catcode`\-=\active \catcode`\_=\active
+ %
+ \gdef\makevalueexpandable{%
+ \let\value = \expandablevalue
+ % We don't want these characters active, ...
+ \catcode`\-=\other \catcode`\_=\other
+ % ..., but we might end up with active ones in the argument if
+ % we're called from @code, as @code{@value{foo-bar_}}, though.
+ % So \let them to their normal equivalents.
+ \let-\normaldash \let_\normalunderscore
+ }
+}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we call \makevalueexpandable in \indexdummies).
+% The command has to be fully expandable (if the variable is set), since
+% the result winds up in the index file. This means that if the
+% variable's value contains other Texinfo commands, it's almost certain
+% it will fail (although perhaps we could fix that with sufficient work
+% to do a one-level expansion on the result, instead of complete).
+%
+% Unfortunately, this has the consequence that when _ is in the *value*
+% of an @set, it does not print properly in the roman fonts (get the cmr
+% dot accent at position 126 instead). No fix comes to mind, and it's
+% been this way since 2003 or earlier, so just ignore it.
+%
+\def\expandablevalue#1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ {[No value for ``#1'']}%
+ \message{Variable `#1', used in @value, is not set.}%
+ \else
+ \csname SET#1\endcsname
+ \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get the special treatment we need for `@end ifset,' we call
+% \makecond and then redefine.
+%
+\makecond{ifset}
+\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}}
+\def\doifset#1#2{%
+ {%
+ \makevalueexpandable
+ \let\next=\empty
+ \expandafter\ifx\csname SET#2\endcsname\relax
+ #1% If not set, redefine \next.
+ \fi
+ \expandafter
+ }\next
+}
+\def\ifsetfail{\doignore{ifset}}
+
+% @ifclear VAR ... @end executes the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written
+% without the @) is in fact defined. We can only feasibly check at the
+% TeX level, so something like `mathcode' is going to considered
+% defined even though it is not a Texinfo command.
+%
+\makecond{ifcommanddefined}
+\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}}
+%
+\def\doifcmddefined#1#2{{%
+ \makevalueexpandable
+ \let\next=\empty
+ \expandafter\ifx\csname #2\endcsname\relax
+ #1% If not defined, \let\next as above.
+ \fi
+ \expandafter
+ }\next
+}
+\def\ifcmddefinedfail{\doignore{ifcommanddefined}}
+
+% @ifcommandnotdefined CMD ... handled similar to @ifclear above.
+\makecond{ifcommandnotdefined}
+\def\ifcommandnotdefined{%
+ \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}}
+\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}}
+
+% Set the `txicommandconditionals' variable, so documents have a way to
+% test if the @ifcommand...defined conditionals are available.
+\set txicommandconditionals
+
+% @dircategory CATEGORY -- specify a category of the dir file
+% which this file should belong to. Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named IX.
+% It automatically defines \IXindex such that
+% \IXindex ...rest of line... puts an entry in the index IX.
+% It also defines \IXindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is IX.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+ \expandafter\chardef\csname#1indfile\endcsname=0
+ \expandafter\xdef\csname#1index\endcsname{% % Define @#1index
+ \noexpand\doindex{#1}}
+}
+
+% @defindex foo == \newindex{foo}
+%
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+%
+\def\defcodeindex{\parsearg\newcodeindex}
+%
+\def\newcodeindex#1{%
+ \expandafter\chardef\csname#1indfile\endcsname=0
+ \expandafter\xdef\csname#1index\endcsname{%
+ \noexpand\docodeindex{#1}}%
+}
+
+% The default indices:
+\newindex{cp}% concepts,
+\newcodeindex{fn}% functions,
+\newcodeindex{vr}% variables,
+\newcodeindex{tp}% types,
+\newcodeindex{ky}% keys
+\newcodeindex{pg}% and programs.
+
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+%
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+%
+\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}}
+\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}}
+
+% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
+% #3 the target index (bar).
+\def\dosynindex#1#2#3{%
+ % Only do \closeout if we haven't already done it, else we'll end up
+ % closing the target index.
+ \expandafter \ifx\csname donesynindex#2\endcsname \relax
+ % The \closeout helps reduce unnecessary open files; the limit on the
+ % Acorn RISC OS is a mere 16 files.
+ \expandafter\closeout\csname#2indfile\endcsname
+ \expandafter\let\csname donesynindex#2\endcsname = 1
+ \fi
+ % redefine \fooindfile:
+ \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
+ \expandafter\let\csname#2indfile\endcsname=\temp
+ % redefine \fooindex:
+ \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}%
+}
+
+% Define \doindex, the driver for all index macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it the two-letter name of the index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx}
+\def\doindexxxx #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx}
+\def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}}
+
+% Used when writing an index entry out to an index file, to prevent
+% expansion of Texinfo commands that can appear in an index entry.
+%
+\def\indexdummies{%
+ \escapechar = `\\ % use backslash in output files.
+ \def\@{@}% change to @@ when we switch to @ as escape char in index files.
+ \def\ {\realbackslash\space }%
+ %
+ % Need these unexpandable (because we define \tt as a dummy)
+ % definitions when @{ or @} appear in index entry text. Also, more
+ % complicated, when \tex is in effect and \{ is a \delimiter again.
+ % We can't use \lbracecmd and \rbracecmd because texindex assumes
+ % braces and backslashes are used only as delimiters. Perhaps we
+ % should use @lbracechar and @rbracechar?
+ \def\{{{\tt\char123}}%
+ \def\}{{\tt\char125}}%
+ %
+ % Do the redefinitions.
+ \commondummies
+}
+
+% For the aux and toc files, @ is the escape character. So we want to
+% redefine everything using @ as the escape character (instead of
+% \realbackslash, still used for index files). When everything uses @,
+% this will be simpler.
+%
+\def\atdummies{%
+ \def\@{@@}%
+ \def\ {@ }%
+ \let\{ = \lbraceatcmd
+ \let\} = \rbraceatcmd
+ %
+ % Do the redefinitions.
+ \commondummies
+ \otherbackslash
+}
+
+% Called from \indexdummies and \atdummies.
+%
+\def\commondummies{%
+ % \definedummyword defines \#1 as \string\#1\space, thus effectively
+ % preventing its expansion. This is used only for control words,
+ % not control letters, because the \space would be incorrect for
+ % control characters, but is needed to separate the control word
+ % from whatever follows.
+ %
+ % For control letters, we have \definedummyletter, which omits the
+ % space.
+ %
+ % These can be used both for control words that take an argument and
+ % those that do not. If it is followed by {arg} in the input, then
+ % that will dutifully get written to the index (or wherever).
+ %
+ \def\definedummyword ##1{\def##1{\string##1\space}}%
+ \def\definedummyletter##1{\def##1{\string##1}}%
+ \let\definedummyaccent\definedummyletter
+ %
+ \commondummiesnofonts
+ %
+ \definedummyletter\_%
+ \definedummyletter\-%
+ %
+ % Non-English letters.
+ \definedummyword\AA
+ \definedummyword\AE
+ \definedummyword\DH
+ \definedummyword\L
+ \definedummyword\O
+ \definedummyword\OE
+ \definedummyword\TH
+ \definedummyword\aa
+ \definedummyword\ae
+ \definedummyword\dh
+ \definedummyword\exclamdown
+ \definedummyword\l
+ \definedummyword\o
+ \definedummyword\oe
+ \definedummyword\ordf
+ \definedummyword\ordm
+ \definedummyword\questiondown
+ \definedummyword\ss
+ \definedummyword\th
+ %
+ % Although these internal commands shouldn't show up, sometimes they do.
+ \definedummyword\bf
+ \definedummyword\gtr
+ \definedummyword\hat
+ \definedummyword\less
+ \definedummyword\sf
+ \definedummyword\sl
+ \definedummyword\tclose
+ \definedummyword\tt
+ %
+ \definedummyword\LaTeX
+ \definedummyword\TeX
+ %
+ % Assorted special characters.
+ \definedummyword\arrow
+ \definedummyword\bullet
+ \definedummyword\comma
+ \definedummyword\copyright
+ \definedummyword\registeredsymbol
+ \definedummyword\dots
+ \definedummyword\enddots
+ \definedummyword\entrybreak
+ \definedummyword\equiv
+ \definedummyword\error
+ \definedummyword\euro
+ \definedummyword\expansion
+ \definedummyword\geq
+ \definedummyword\guillemetleft
+ \definedummyword\guillemetright
+ \definedummyword\guilsinglleft
+ \definedummyword\guilsinglright
+ \definedummyword\lbracechar
+ \definedummyword\leq
+ \definedummyword\mathopsup
+ \definedummyword\minus
+ \definedummyword\ogonek
+ \definedummyword\pounds
+ \definedummyword\point
+ \definedummyword\print
+ \definedummyword\quotedblbase
+ \definedummyword\quotedblleft
+ \definedummyword\quotedblright
+ \definedummyword\quoteleft
+ \definedummyword\quoteright
+ \definedummyword\quotesinglbase
+ \definedummyword\rbracechar
+ \definedummyword\result
+ \definedummyword\sub
+ \definedummyword\sup
+ \definedummyword\textdegree
+ %
+ % We want to disable all macros so that they are not expanded by \write.
+ \macrolist
+ %
+ \normalturnoffactive
+ %
+ % Handle some cases of @value -- where it does not contain any
+ % (non-fully-expandable) commands.
+ \makevalueexpandable
+}
+
+% \commondummiesnofonts: common to \commondummies and \indexnofonts.
+% Define \definedumyletter, \definedummyaccent and \definedummyword before
+% using.
+%
+\def\commondummiesnofonts{%
+ % Control letters and accents.
+ \definedummyletter\!%
+ \definedummyaccent\"%
+ \definedummyaccent\'%
+ \definedummyletter\*%
+ \definedummyaccent\,%
+ \definedummyletter\.%
+ \definedummyletter\/%
+ \definedummyletter\:%
+ \definedummyaccent\=%
+ \definedummyletter\?%
+ \definedummyaccent\^%
+ \definedummyaccent\`%
+ \definedummyaccent\~%
+ \definedummyword\u
+ \definedummyword\v
+ \definedummyword\H
+ \definedummyword\dotaccent
+ \definedummyword\ogonek
+ \definedummyword\ringaccent
+ \definedummyword\tieaccent
+ \definedummyword\ubaraccent
+ \definedummyword\udotaccent
+ \definedummyword\dotless
+ %
+ % Texinfo font commands.
+ \definedummyword\b
+ \definedummyword\i
+ \definedummyword\r
+ \definedummyword\sansserif
+ \definedummyword\sc
+ \definedummyword\slanted
+ \definedummyword\t
+ %
+ % Commands that take arguments.
+ \definedummyword\abbr
+ \definedummyword\acronym
+ \definedummyword\anchor
+ \definedummyword\cite
+ \definedummyword\code
+ \definedummyword\command
+ \definedummyword\dfn
+ \definedummyword\dmn
+ \definedummyword\email
+ \definedummyword\emph
+ \definedummyword\env
+ \definedummyword\file
+ \definedummyword\image
+ \definedummyword\indicateurl
+ \definedummyword\inforef
+ \definedummyword\kbd
+ \definedummyword\key
+ \definedummyword\math
+ \definedummyword\option
+ \definedummyword\pxref
+ \definedummyword\ref
+ \definedummyword\samp
+ \definedummyword\strong
+ \definedummyword\tie
+ \definedummyword\U
+ \definedummyword\uref
+ \definedummyword\url
+ \definedummyword\var
+ \definedummyword\verb
+ \definedummyword\w
+ \definedummyword\xref
+}
+
+% For testing: output @{ and @} in index sort strings as \{ and \}.
+\newif\ifusebracesinindexes
+
+\let\indexlbrace\relax
+\let\indexrbrace\relax
+
+{\catcode`\@=0
+\catcode`\\=13
+ @gdef@backslashdisappear{@def\{}}
+}
+
+{
+\catcode`\<=13
+\catcode`\-=13
+\catcode`\`=13
+ \gdef\indexnonalnumdisappear{%
+ \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else
+ % @set txiindexlquoteignore makes us ignore left quotes in the sort term.
+ % (Introduced for FSFS 2nd ed.)
+ \let`=\empty
+ \fi
+ %
+ \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else
+ \backslashdisappear
+ \fi
+ %
+ \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else
+ \def-{}%
+ \fi
+ \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else
+ \def<{}%
+ \fi
+ \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else
+ \def\@{}%
+ \fi
+ }
+
+ \gdef\indexnonalnumreappear{%
+ \useindexbackslash
+ \let-\normaldash
+ \let<\normalless
+ \def\@{@}%
+ }
+}
+
+
+% \indexnofonts is used when outputting the strings to sort the index
+% by, and when constructing control sequence names. It eliminates all
+% control sequences and just writes whatever the best ASCII sort string
+% would be for a given command (usually its argument).
+%
+\def\indexnofonts{%
+ % Accent commands should become @asis.
+ \def\definedummyaccent##1{\let##1\asis}%
+ % We can just ignore other control letters.
+ \def\definedummyletter##1{\let##1\empty}%
+ % All control words become @asis by default; overrides below.
+ \let\definedummyword\definedummyaccent
+ \commondummiesnofonts
+ %
+ % Don't no-op \tt, since it isn't a user-level command
+ % and is used in the definitions of the active chars like <, >, |, etc.
+ % Likewise with the other plain tex font commands.
+ %\let\tt=\asis
+ %
+ \def\ { }%
+ \def\@{@}%
+ \def\_{\normalunderscore}%
+ \def\-{}% @- shouldn't affect sorting
+ %
+ \uccode`\1=`\{ \uppercase{\def\{{1}}%
+ \uccode`\1=`\} \uppercase{\def\}{1}}%
+ \let\lbracechar\{%
+ \let\rbracechar\}%
+ %
+ % Non-English letters.
+ \def\AA{AA}%
+ \def\AE{AE}%
+ \def\DH{DZZ}%
+ \def\L{L}%
+ \def\OE{OE}%
+ \def\O{O}%
+ \def\TH{TH}%
+ \def\aa{aa}%
+ \def\ae{ae}%
+ \def\dh{dzz}%
+ \def\exclamdown{!}%
+ \def\l{l}%
+ \def\oe{oe}%
+ \def\ordf{a}%
+ \def\ordm{o}%
+ \def\o{o}%
+ \def\questiondown{?}%
+ \def\ss{ss}%
+ \def\th{th}%
+ %
+ \def\LaTeX{LaTeX}%
+ \def\TeX{TeX}%
+ %
+ % Assorted special characters.
+ % (The following {} will end up in the sort string, but that's ok.)
+ \def\arrow{->}%
+ \def\bullet{bullet}%
+ \def\comma{,}%
+ \def\copyright{copyright}%
+ \def\dots{...}%
+ \def\enddots{...}%
+ \def\equiv{==}%
+ \def\error{error}%
+ \def\euro{euro}%
+ \def\expansion{==>}%
+ \def\geq{>=}%
+ \def\guillemetleft{<<}%
+ \def\guillemetright{>>}%
+ \def\guilsinglleft{<}%
+ \def\guilsinglright{>}%
+ \def\leq{<=}%
+ \def\minus{-}%
+ \def\point{.}%
+ \def\pounds{pounds}%
+ \def\print{-|}%
+ \def\quotedblbase{"}%
+ \def\quotedblleft{"}%
+ \def\quotedblright{"}%
+ \def\quoteleft{`}%
+ \def\quoteright{'}%
+ \def\quotesinglbase{,}%
+ \def\registeredsymbol{R}%
+ \def\result{=>}%
+ \def\textdegree{o}%
+ %
+ % We need to get rid of all macros, leaving only the arguments (if present).
+ % Of course this is not nearly correct, but it is the best we can do for now.
+ % makeinfo does not expand macros in the argument to @deffn, which ends up
+ % writing an index entry, and texindex isn't prepared for an index sort entry
+ % that starts with \.
+ %
+ % Since macro invocations are followed by braces, we can just redefine them
+ % to take a single TeX argument. The case of a macro invocation that
+ % goes to end-of-line is not handled.
+ %
+ \macrolist
+}
+
+
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% Most index entries go through here, but \dosubind is the general case.
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{\dosubind{#1}{#2}{}}
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+% TODO: Two-level index? Operation index?
+
+% Workhorse for all indexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% empty if called from \doind, as we usually are (the main exception
+% is with most defuns, which call us directly).
+%
+\def\dosubind#1#2#3{%
+ \iflinks
+ {%
+ \requireopenindexfile{#1}%
+ % Store the main index entry text (including the third arg).
+ \toks0 = {#2}%
+ % If third arg is present, precede it with a space.
+ \def\thirdarg{#3}%
+ \ifx\thirdarg\empty \else
+ \toks0 = \expandafter{\the\toks0 \space #3}%
+ \fi
+ %
+ \edef\writeto{\csname#1indfile\endcsname}%
+ %
+ \safewhatsit\dosubindwrite
+ }%
+ \fi
+}
+
+% Check if an index file has been opened, and if not, open it.
+\def\requireopenindexfile#1{%
+\ifnum\csname #1indfile\endcsname=0
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \edef\suffix{#1}%
+ % A .fls suffix would conflict with the file extension for the output
+ % of -recorder, so use .f1s instead.
+ \ifx\suffix\indexisfl\def\suffix{f1}\fi
+ % Open the file
+ \immediate\openout\csname#1indfile\endcsname \jobname.\suffix
+ % Using \immediate here prevents an object entering into the current box,
+ % which could confound checks such as those in \safewhatsit for preceding
+ % skips.
+\fi}
+\def\indexisfl{fl}
+
+% Output \ as {\indexbackslash}, because \ is an escape character in
+% the index files.
+\let\indexbackslash=\relax
+{\catcode`\@=0 \catcode`\\=\active
+ @gdef@useindexbackslash{@def\{{@indexbackslash}}}
+}
+
+% Definition for writing index entry text.
+\def\sortas#1{\ignorespaces}%
+
+% Definition for writing index entry sort key. Should occur at the at
+% the beginning of the index entry, like
+% @cindex @sortas{september} \september
+% The \ignorespaces takes care of following space, but there's no way
+% to remove space before it.
+{
+\catcode`\-=13
+\gdef\indexwritesortas{%
+ \begingroup
+ \indexnonalnumreappear
+ \indexwritesortasxxx}
+\gdef\indexwritesortasxxx#1{%
+ \xdef\indexsortkey{#1}\endgroup}
+}
+
+
+% Write the entry in \toks0 to the index file.
+%
+\def\dosubindwrite{%
+ % Put the index entry in the margin if desired.
+ \ifx\SETmarginindex\relax\else
+ \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}%
+ \fi
+ %
+ % Remember, we are within a group.
+ \indexdummies % Must do this here, since \bf, etc expand at this stage
+ \useindexbackslash % \indexbackslash isn't defined now so it will be output
+ % as is; and it will print as backslash.
+ % The braces around \indexbrace are recognized by texindex.
+ %
+ % Get the string to sort by, by processing the index entry with all
+ % font commands turned off.
+ {\indexnofonts
+ \def\lbracechar{{\indexlbrace}}%
+ \def\rbracechar{{\indexrbrace}}%
+ \let\{=\lbracechar
+ \let\}=\rbracechar
+ \indexnonalnumdisappear
+ \xdef\indexsortkey{}%
+ \let\sortas=\indexwritesortas
+ \edef\temp{\the\toks0}%
+ \setbox\dummybox = \hbox{\temp}% Make sure to execute any \sortas
+ \ifx\indexsortkey\empty
+ \xdef\indexsortkey{\temp}%
+ \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi
+ \fi
+ }%
+ %
+ % Set up the complete index entry, with both the sort key and
+ % the original text, including any font commands. We write
+ % three arguments to \entry to the .?? file (four in the
+ % subentry case), texindex reduces to two when writing the .??s
+ % sorted result.
+ \edef\temp{%
+ \write\writeto{%
+ \string\entry{\indexsortkey}{\noexpand\folio}{\the\toks0}}%
+ }%
+ \temp
+}
+\newbox\dummybox % used above
+
+% Take care of unwanted page breaks/skips around a whatsit:
+%
+% If a skip is the last thing on the list now, preserve it
+% by backing up by \lastskip, doing the \write, then inserting
+% the skip again. Otherwise, the whatsit generated by the
+% \write or \pdfdest will make \lastskip zero. The result is that
+% sequences like this:
+% @end defun
+% @tindex whatever
+% @defun ...
+% will have extra space inserted, because the \medbreak in the
+% start of the @defun won't see the skip inserted by the @end of
+% the previous defun.
+%
+% But don't do any of this if we're not in vertical mode. We
+% don't want to do a \vskip and prematurely end a paragraph.
+%
+% Avoid page breaks due to these extra skips, too.
+%
+% But wait, there is a catch there:
+% We'll have to check whether \lastskip is zero skip. \ifdim is not
+% sufficient for this purpose, as it ignores stretch and shrink parts
+% of the skip. The only way seems to be to check the textual
+% representation of the skip.
+%
+% The following is almost like \def\zeroskipmacro{0.0pt} except that
+% the ``p'' and ``t'' characters have catcode \other, not 11 (letter).
+%
+\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname}
+%
+\newskip\whatsitskip
+\newcount\whatsitpenalty
+%
+% ..., ready, GO:
+%
+\def\safewhatsit#1{\ifhmode
+ #1%
+ \else
+ % \lastskip and \lastpenalty cannot both be nonzero simultaneously.
+ \whatsitskip = \lastskip
+ \edef\lastskipmacro{\the\lastskip}%
+ \whatsitpenalty = \lastpenalty
+ %
+ % If \lastskip is nonzero, that means the last item was a
+ % skip. And since a skip is discardable, that means this
+ % -\whatsitskip glue we're inserting is preceded by a
+ % non-discardable item, therefore it is not a potential
+ % breakpoint, therefore no \nobreak needed.
+ \ifx\lastskipmacro\zeroskipmacro
+ \else
+ \vskip-\whatsitskip
+ \fi
+ %
+ #1%
+ %
+ \ifx\lastskipmacro\zeroskipmacro
+ % If \lastskip was zero, perhaps the last item was a penalty, and
+ % perhaps it was >=10000, e.g., a \nobreak. In that case, we want
+ % to re-insert the same penalty (values >10000 are used for various
+ % signals); since we just inserted a non-discardable item, any
+ % following glue (such as a \parskip) would be a breakpoint. For example:
+ % @deffn deffn-whatever
+ % @vindex index-whatever
+ % Description.
+ % would allow a break between the index-whatever whatsit
+ % and the "Description." paragraph.
+ \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi
+ \else
+ % On the other hand, if we had a nonzero \lastskip,
+ % this make-up glue would be preceded by a non-discardable item
+ % (the whatsit from the \write), so we must insert a \nobreak.
+ \nobreak\vskip\whatsitskip
+ \fi
+\fi}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\parseargdef\printindex{\begingroup
+ \dobreak \chapheadingskip{10000}%
+ %
+ \smallfonts \rm
+ \tolerance = 9500
+ \plainfrenchspacing
+ \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+ %
+ % See if the index file exists and is nonempty.
+ % Change catcode of @ here so that if the index file contains
+ % \initial {@}
+ % as its first line, TeX doesn't complain about mismatched braces
+ % (because it thinks @} is a control sequence).
+ \catcode`\@ = 11
+ % See comment in \requireopenindexfile.
+ \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi
+ \openin 1 \jobname.\indexname s
+ \ifeof 1
+ % \enddoublecolumns gets confused if there is no text in the index,
+ % and it loses the chapter title and the aux file entries for the
+ % index. The easiest way to prevent this problem is to make sure
+ % there is some text.
+ \putwordIndexNonexistent
+ \else
+ \catcode`\\ = 0
+ \escapechar = `\\
+ %
+ % If the index file exists but is empty, then \openin leaves \ifeof
+ % false. We have to make TeX try to read something from the file, so
+ % it can discover if there is anything in it.
+ \read 1 to \thisline
+ \ifeof 1
+ \putwordIndexIsEmpty
+ \else
+ % Index files are almost Texinfo source, but we use \ as the escape
+ % character. It would be better to use @, but that's too big a change
+ % to make right now.
+ \def\indexbackslash{\ttbackslash}%
+ \let\indexlbrace\{ % Likewise, set these sequences for braces
+ \let\indexrbrace\} % used in the sort key.
+ \begindoublecolumns
+ \let\entryorphanpenalty=\indexorphanpenalty
+ %
+ % Read input from the index file line by line.
+ \loopdo
+ \ifeof1
+ \let\firsttoken\relax
+ \else
+ \read 1 to \nextline
+ \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}%
+ \act
+ \fi
+ \thisline
+ %
+ \ifeof1\else
+ \let\thisline\nextline
+ \repeat
+ %%
+ \enddoublecolumns
+ \fi
+ \fi
+ \closein 1
+\endgroup}
+
+\def\getfirsttoken#1{\expandafter\getfirsttokenx#1\endfirsttoken}
+\long\def\getfirsttokenx#1#2\endfirsttoken{\noexpand#1}
+
+\def\loopdo#1\repeat{\def\body{#1}\loopdoxxx}
+\def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+{\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13
+\catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13
+\catcode`\$=3
+\gdef\initialglyphs{%
+ % Some changes for non-alphabetic characters. Using the glyphs from the
+ % math fonts looks more consistent than the typewriter font used elsewhere
+ % for these characters.
+ \def\indexbackslash{\math{\backslash}}%
+ \let\\=\indexbackslash
+ %
+ % Can't get bold backslash so don't use bold forward slash
+ \catcode`\/=13
+ \def/{{\secrmnotbold \normalslash}}%
+ \def-{{\normaldash\normaldash}}% en dash `--'
+ \def^{{\chapbf \normalcaret}}%
+ \def~{{\chapbf \normaltilde}}%
+ \def\_{%
+ \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }%
+ \def|{$\vert$}%
+ \def<{$\less$}%
+ \def>{$\gtr$}%
+ \def+{$\normalplus$}%
+}}
+
+\def\initial{%
+ \bgroup
+ \initialglyphs
+ \initialx
+}
+
+\def\initialx#1{%
+ % Remove any glue we may have, we'll be inserting our own.
+ \removelastskip
+ %
+ % We like breaks before the index initials, so insert a bonus.
+ % The glue before the bonus allows a little bit of space at the
+ % bottom of a column to reduce an increase in inter-line spacing.
+ \nobreak
+ \vskip 0pt plus 5\baselineskip
+ \penalty -300
+ \vskip 0pt plus -5\baselineskip
+ %
+ % Typeset the initial. Making this add up to a whole number of
+ % baselineskips increases the chance of the dots lining up from column
+ % to column. It still won't often be perfect, because of the stretch
+ % we need before each entry, but it's better.
+ %
+ % No shrink because it confuses \balancecolumns.
+ \vskip 1.67\baselineskip plus 1\baselineskip
+ \leftline{\secfonts \kern-0.05em \secbf #1}%
+ % \secfonts is inside the argument of \leftline so that the change of
+ % \baselineskip will not affect any glue inserted before the vbox that
+ % \leftline creates.
+ % Do our best not to break after the initial.
+ \nobreak
+ \vskip .33\baselineskip plus .1\baselineskip
+ \egroup % \initialglyphs
+}
+
+\newdimen\entryrightmargin
+\entryrightmargin=0pt
+
+% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
+% then page number (#2) flushed to the right margin. It is used for index
+% and table of contents entries. The paragraph is indented by \leftskip.
+%
+\def\entry{%
+ \begingroup
+ %
+ % Start a new paragraph if necessary, so our assignments below can't
+ % affect previous text.
+ \par
+ %
+ % No extra space above this paragraph.
+ \parskip = 0in
+ %
+ % When reading the text of entry, convert explicit line breaks
+ % from @* into spaces. The user might give these in long section
+ % titles, for instance.
+ \def\*{\unskip\space\ignorespaces}%
+ \def\entrybreak{\hfil\break}% An undocumented command
+ %
+ % A bit of stretch before each entry for the benefit of balancing
+ % columns.
+ \vskip 0pt plus0.5pt
+ %
+ % Swallow the left brace of the text (first parameter):
+ \afterassignment\doentry
+ \let\temp =
+}
+\def\entrybreak{\unskip\space\ignorespaces}%
+\def\doentry{%
+ % Save the text of the entry
+ \global\setbox\boxA=\hbox\bgroup
+ \bgroup % Instead of the swallowed brace.
+ \noindent
+ \aftergroup\finishentry
+ % And now comes the text of the entry.
+ % Not absorbing as a macro argument reduces the chance of problems
+ % with catcodes occurring.
+}
+{\catcode`\@=11
+\gdef\finishentry#1{%
+ \egroup % end box A
+ \dimen@ = \wd\boxA % Length of text of entry
+ \global\setbox\boxA=\hbox\bgroup\unhbox\boxA
+ % #1 is the page number.
+ %
+ % Get the width of the page numbers, and only use
+ % leaders if they are present.
+ \global\setbox\boxB = \hbox{#1}%
+ \ifdim\wd\boxB = 0pt
+ \null\nobreak\hfill\ %
+ \else
+ %
+ \null\nobreak\indexdotfill % Have leaders before the page number.
+ %
+ \ifpdf
+ \pdfgettoks#1.%
+ \bgroup\let\domark\relax
+ \hskip\skip\thinshrinkable\the\toksA
+ \egroup
+ % The redefinion of \domark stops marks being added in \pdflink to
+ % preserve coloured links across page boundaries. Otherwise the marks
+ % would get in the way of \lastbox in \insertindexentrybox.
+ \else
+ \hskip\skip\thinshrinkable #1%
+ \fi
+ \fi
+ \egroup % end \boxA
+ \ifdim\wd\boxB = 0pt
+ \global\setbox\entryindexbox=\vbox{\unhbox\boxA}%
+ \else
+ \global\setbox\entryindexbox=\vbox\bgroup
+ \prevdepth=\entrylinedepth
+ \noindent
+ % We want the text of the entries to be aligned to the left, and the
+ % page numbers to be aligned to the right.
+ %
+ \advance\leftskip by 0pt plus 1fil
+ \advance\leftskip by 0pt plus -1fill
+ \rightskip = 0pt plus -1fil
+ \advance\rightskip by 0pt plus 1fill
+ % Cause last line, which could consist of page numbers on their own
+ % if the list of page numbers is long, to be aligned to the right.
+ \parfillskip=0pt plus -1fill
+ %
+ \hangindent=1em
+ %
+ \advance\rightskip by \entryrightmargin
+ % Determine how far we can stretch into the margin.
+ % This allows, e.g., "Appendix H GNU Free Documentation License" to
+ % fit on one line in @letterpaper format.
+ \ifdim\entryrightmargin>2.1em
+ \dimen@i=2.1em
+ \else
+ \dimen@i=0em
+ \fi
+ \advance \parfillskip by 0pt minus 1\dimen@i
+ %
+ \dimen@ii = \hsize
+ \advance\dimen@ii by -1\leftskip
+ \advance\dimen@ii by -1\entryrightmargin
+ \advance\dimen@ii by 1\dimen@i
+ \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line
+ \ifdim\dimen@ > 0.8\dimen@ii % due to long index text
+ \dimen@ = 0.7\dimen@ % Try to split the text roughly evenly
+ \dimen@ii = \hsize
+ \advance \dimen@ii by -1em
+ \ifnum\dimen@>\dimen@ii
+ % If the entry is too long, use the whole line
+ \dimen@ = \dimen@ii
+ \fi
+ \advance\leftskip by 0pt plus 1fill % ragged right
+ \advance \dimen@ by 1\rightskip
+ \parshape = 2 0pt \dimen@ 1em \dimen@ii
+ % Ideally we'd add a finite glue at the end of the first line only, but
+ % TeX doesn't seem to provide a way to do such a thing.
+ \fi\fi
+ \unhbox\boxA
+ %
+ % Do not prefer a separate line ending with a hyphen to fewer lines.
+ \finalhyphendemerits = 0
+ %
+ % Word spacing - no stretch
+ \spaceskip=\fontdimen2\font minus \fontdimen4\font
+ %
+ \linepenalty=1000 % Discourage line breaks.
+ \hyphenpenalty=5000 % Discourage hyphenation.
+ %
+ \par % format the paragraph
+ \egroup % The \vbox
+ \fi
+ \endgroup
+ % delay text of entry until after penalty
+ \bgroup\aftergroup\insertindexentrybox
+ \entryorphanpenalty
+}}
+
+\newskip\thinshrinkable
+\skip\thinshrinkable=.15em minus .15em
+
+\newbox\entryindexbox
+\def\insertindexentrybox{%
+ \copy\entryindexbox
+ % The following gets the depth of the last box. This is for even
+ % line spacing when entries span several lines.
+ \setbox\dummybox\vbox{%
+ \unvbox\entryindexbox
+ \nointerlineskip
+ \lastbox
+ \global\entrylinedepth=\prevdepth
+ }%
+ % Note that we couldn't simply \unvbox\entryindexbox followed by
+ % \nointerlineskip\lastbox to remove the last box and then reinstate it,
+ % because this resets how far the box has been \moveleft'ed to 0. \unvbox
+ % doesn't affect \prevdepth either.
+}
+\newdimen\entrylinedepth
+
+% Default is no penalty
+\let\entryorphanpenalty\egroup
+
+% Used from \printindex. \firsttoken should be the first token
+% after the \entry. If it's not another \entry, we are at the last
+% line of a group of index entries, so insert a penalty to discourage
+% orphaned index entries.
+\long\def\indexorphanpenalty{%
+ \def\isentry{\entry}%
+ \ifx\firsttoken\isentry
+ \else
+ \unskip\penalty 9000
+ % The \unskip here stops breaking before the glue. It relies on the
+ % \vskip above being there, otherwise there is an error
+ % "You can't use `\unskip' in vertical mode". There has to be glue
+ % in the current vertical list that hasn't been added to the
+ % "current page". See Chapter 24 of the TeXbook. This contradicts
+ % Section 8.3.7 in "TeX by Topic," though.
+ \fi
+ \egroup % now comes the box added with \aftergroup
+}
+
+% Like plain.tex's \dotfill, except uses up at least 1 em.
+% The filll stretch here overpowers both the fil and fill stretch to push
+% the page number to the right.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll}
+
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+\def\secondary#1#2{{%
+ \parfillskip=0in
+ \parskip=0in
+ \hangindent=1in
+ \hangafter=1
+ \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill
+ \ifpdf
+ \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph.
+ \else
+ #2
+ \fi
+ \par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11 % private names
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+\newdimen\doublecolumntopgap
+\doublecolumntopgap = 0pt
+
+% Use inside an output routine to save \topmark and \firstmark
+\def\savemarks{%
+ \global\savedtopmark=\expandafter{\topmark }%
+ \global\savedfirstmark=\expandafter{\firstmark }%
+}
+\newtoks\savedtopmark
+\newtoks\savedfirstmark
+
+% Set \topmark and \firstmark for next time \output runs.
+% Can't be run from withinside \output (because any material
+% added while an output routine is active, including
+% penalties, is saved for after it finishes). The page so far
+% should be empty, otherwise what's on it will be thrown away.
+\def\restoremarks{%
+ \mark{\the\savedtopmark}%
+ \bgroup\output = {%
+ \setbox\dummybox=\box\PAGE
+ }abc\eject\egroup
+ % "abc" because output routine doesn't fire for a completely empty page.
+ \mark{\the\savedfirstmark}%
+}
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+ % If not much space left on page, start a new page.
+ \ifdim\pagetotal>0.8\vsize\vfill\eject\fi
+ %
+ % Grab any single-column material above us.
+ \output = {%
+ %
+ % Here is a possibility not foreseen in manmac: if we accumulate a
+ % whole lot of material, we might end up calling this \output
+ % routine twice in a row (see the doublecol-lose test, which is
+ % essentially a couple of indexes with @setchapternewpage off). In
+ % that case we just ship out what is in \partialpage with the normal
+ % output routine. Generally, \partialpage will be empty when this
+ % runs and this will be a no-op. See the indexspread.tex test case.
+ \ifvoid\partialpage \else
+ \onepageout{\pagecontents\partialpage}%
+ \fi
+ %
+ \global\setbox\partialpage = \vbox{%
+ % Unvbox the main output page.
+ \unvbox\PAGE
+ \kern-\topskip \kern\baselineskip
+ }%
+ \savemarks
+ }%
+ \eject % run that output routine to set \partialpage
+ \restoremarks
+ %
+ % We recover the two marks that the last output routine saved in order
+ % to propagate the information in marks added around a chapter heading,
+ % which could be otherwise be lost by the time the final page is output.
+ %
+ %
+ % Use the double-column output routine for subsequent pages.
+ \output = {\doublecolumnout}%
+ %
+ % Change the page size parameters. We could do this once outside this
+ % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+ % format, but then we repeat the same computation. Repeating a couple
+ % of assignments once per index is clearly meaningless for the
+ % execution time, so we may as well do it in one place.
+ %
+ % First we halve the line length, less a little for the gutter between
+ % the columns. We compute the gutter based on the line length, so it
+ % changes automatically with the paper format. The magic constant
+ % below is chosen so that the gutter has the same value (well, +-<1pt)
+ % as it did when we hard-coded it.
+ %
+ % We put the result in a separate register, \doublecolumhsize, so we
+ % can restore it in \pagesofar, after \hsize itself has (potentially)
+ % been clobbered.
+ %
+ \doublecolumnhsize = \hsize
+ \advance\doublecolumnhsize by -.04154\hsize
+ \divide\doublecolumnhsize by 2
+ \hsize = \doublecolumnhsize
+ %
+ % Double the \vsize as well. (We don't need a separate register here,
+ % since nobody clobbers \vsize.)
+ \global\doublecolumntopgap = \topskip
+ \global\advance\doublecolumntopgap by -1\baselineskip
+ \advance\vsize by -1\doublecolumntopgap
+ \vsize = 2\vsize
+ \topskip=0pt
+ \global\entrylinedepth=0pt\relax
+}
+
+% The double-column output routine for all double-column pages except
+% the last, which is done by \balancecolumns.
+%
+\def\doublecolumnout{%
+ %
+ \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ % Get the available space for the double columns -- the normal
+ % (undoubled) page height minus any material left over from the
+ % previous page.
+ \dimen@ = \vsize
+ \divide\dimen@ by 2
+ \advance\dimen@ by -\ht\partialpage
+ %
+ % box0 will be the left-hand column, box2 the right.
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar
+ \unvbox255
+ \penalty\outputpenalty
+}
+%
+% Re-output the contents of the output page -- any previous material,
+% followed by the two boxes we just split, in box0 and box2.
+\def\pagesofar{%
+ \unvbox\partialpage
+ %
+ \hsize = \doublecolumnhsize
+ \wd0=\hsize \wd2=\hsize
+ \vbox{%
+ \vskip\doublecolumntopgap
+ \hbox to\pagewidth{\box0\hfil\box2}}%
+}
+
+
+% Finished with with double columns.
+\def\enddoublecolumns{%
+ % The following penalty ensures that the page builder is exercised
+ % _before_ we change the output routine. This is necessary in the
+ % following situation:
+ %
+ % The last section of the index consists only of a single entry.
+ % Before this section, \pagetotal is less than \pagegoal, so no
+ % break occurs before the last section starts. However, the last
+ % section, consisting of \initial and the single \entry, does not
+ % fit on the page and has to be broken off. Without the following
+ % penalty the page builder will not be exercised until \eject
+ % below, and by that time we'll already have changed the output
+ % routine to the \balancecolumns version, so the next-to-last
+ % double-column page will be processed with \balancecolumns, which
+ % is wrong: The two columns will go to the main vertical list, with
+ % the broken-off section in the recent contributions. As soon as
+ % the output routine finishes, TeX starts reconsidering the page
+ % break. The two columns and the broken-off section both fit on the
+ % page, because the two columns now take up only half of the page
+ % goal. When TeX sees \eject from below which follows the final
+ % section, it invokes the new output routine that we've set after
+ % \balancecolumns below; \onepageout will try to fit the two columns
+ % and the final section into the vbox of \pageheight (see
+ % \pagebody), causing an overfull box.
+ %
+ % Note that glue won't work here, because glue does not exercise the
+ % page builder, unlike penalties (see The TeXbook, pp. 280-281).
+ \penalty0
+ %
+ \output = {%
+ % Split the last of the double-column material.
+ \savemarks
+ \balancecolumns
+ %
+ % Having called \balancecolumns once, we do not
+ % want to call it again. Therefore, reset \output to its normal
+ % definition right away.
+ \global\output = {\onepageout{\pagecontents\PAGE}}%
+ }%
+ \eject
+ \endgroup % started in \begindoublecolumns
+ \restoremarks
+ % Leave the double-column material on the current page, no automatic
+ % page break.
+ \box\balancedcolumns
+ %
+ % \pagegoal was set to the doubled \vsize above, since we restarted
+ % the current page. We're now back to normal single-column
+ % typesetting, so reset \pagegoal to the normal \vsize (after the
+ % \endgroup where \vsize got restored).
+ \pagegoal = \vsize
+}
+\newbox\balancedcolumns
+\setbox\balancedcolumns=\vbox{shouldnt see this}%
+%
+% Only called for the last of the double column material. \doublecolumnout
+% does the others.
+\def\balancecolumns{%
+ \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+ \dimen@ = \ht0
+ \advance\dimen@ by \topskip
+ \advance\dimen@ by-\baselineskip
+ \ifdim\dimen@<14\baselineskip
+ % Don't split a short final column in two.
+ \setbox2=\vbox{}%
+ \else
+ \divide\dimen@ by 2 % target to split to
+ \dimen@ii = \dimen@
+ \splittopskip = \topskip
+ % Loop until the second column is no higher than the first
+ {%
+ \vbadness = 10000
+ \loop
+ \global\setbox3 = \copy0
+ \global\setbox1 = \vsplit3 to \dimen@
+ % Remove glue from bottom of first column to
+ % make sure it is higher than the second.
+ \global\setbox1 = \vbox{\unvbox1\unpenalty\unskip}%
+ \ifdim\ht3>\ht1
+ \global\advance\dimen@ by 1pt
+ \repeat
+ }%
+ \multiply\dimen@ii by 4
+ \divide\dimen@ii by 5
+ \ifdim\ht3<\dimen@ii
+ % Column heights are too different, so don't make their bottoms
+ % flush with each other. The glue at the end of the second column
+ % allows a second column to stretch, reducing the difference in
+ % height between the two.
+ \setbox0=\vbox to\dimen@{\unvbox1\vfill}%
+ \setbox2=\vbox to\dimen@{\unvbox3\vskip 0pt plus 0.3\ht0}%
+ \else
+ \setbox0=\vbox to\dimen@{\unvbox1}%
+ \setbox2=\vbox to\dimen@{\unvbox3}%
+ \fi
+ \fi
+ %
+ \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% Let's start with @part.
+\outer\parseargdef\part{\partzzz{#1}}
+\def\partzzz#1{%
+ \chapoddpage
+ \null
+ \vskip.3\vsize % move it down on the page a bit
+ \begingroup
+ \noindent \titlefonts\rmisbold #1\par % the text
+ \let\lastnode=\empty % no node to associate with
+ \writetocentry{part}{#1}{}% but put it in the toc
+ \headingsoff % no headline or footline on the part page
+ % This outputs a mark at the end of the page that clears \thischapter
+ % and \thissection, as is done in \startcontents.
+ \let\pchapsepmacro\relax
+ \chapmacro{}{Yomitfromtoc}{}%
+ \chapoddpage
+ \endgroup
+}
+
+% \unnumberedno is an oxymoron. But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number". We avoid collisions with chapter
+% numbers by starting them at 10000. (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno \secno=0
+\newcount\subsecno \subsecno=0
+\newcount\subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+ \ifnum\appendixno=`A A%
+ \else\ifnum\appendixno=`B B%
+ \else\ifnum\appendixno=`C C%
+ \else\ifnum\appendixno=`D D%
+ \else\ifnum\appendixno=`E E%
+ \else\ifnum\appendixno=`F F%
+ \else\ifnum\appendixno=`G G%
+ \else\ifnum\appendixno=`H H%
+ \else\ifnum\appendixno=`I I%
+ \else\ifnum\appendixno=`J J%
+ \else\ifnum\appendixno=`K K%
+ \else\ifnum\appendixno=`L L%
+ \else\ifnum\appendixno=`M M%
+ \else\ifnum\appendixno=`N N%
+ \else\ifnum\appendixno=`O O%
+ \else\ifnum\appendixno=`P P%
+ \else\ifnum\appendixno=`Q Q%
+ \else\ifnum\appendixno=`R R%
+ \else\ifnum\appendixno=`S S%
+ \else\ifnum\appendixno=`T T%
+ \else\ifnum\appendixno=`U U%
+ \else\ifnum\appendixno=`V V%
+ \else\ifnum\appendixno=`W W%
+ \else\ifnum\appendixno=`X X%
+ \else\ifnum\appendixno=`Y Y%
+ \else\ifnum\appendixno=`Z Z%
+ % The \the is necessary, despite appearances, because \appendixletter is
+ % expanded while writing the .toc file. \char\appendixno is not
+ % expandable, thus it is written literally, thus all appendixes come out
+ % with the same letter (or @) in the toc without it.
+ \else\char\the\appendixno
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines these (using marks) as the number+name, number
+% and name of the chapter. Page headings and footings can use
+% these. @section does likewise.
+\def\thischapter{}
+\def\thischapternum{}
+\def\thischaptername{}
+\def\thissection{}
+\def\thissectionnum{}
+\def\thissectionname{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achieve this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unnlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+ % Compute the abs. sec. level:
+ \absseclevel=#2
+ \advance\absseclevel by \secbase
+ % Make sure \absseclevel doesn't fall outside the range:
+ \ifnum \absseclevel < 0
+ \absseclevel = 0
+ \else
+ \ifnum \absseclevel > 3
+ \absseclevel = 3
+ \fi
+ \fi
+ % The heading type:
+ \def\headtype{#1}%
+ \if \headtype U%
+ \ifnum \absseclevel < \unnlevel
+ \chardef\unnlevel = \absseclevel
+ \fi
+ \else
+ % Check for appendix sections:
+ \ifnum \absseclevel = 0
+ \edef\chapheadtype{\headtype}%
+ \else
+ \if \headtype A\if \chapheadtype N%
+ \errmessage{@appendix... within a non-appendix chapter}%
+ \fi\fi
+ \fi
+ % Check for numbered within unnumbered:
+ \ifnum \absseclevel > \unnlevel
+ \def\headtype{U}%
+ \else
+ \chardef\unnlevel = 3
+ \fi
+ \fi
+ % Now print the heading:
+ \if \headtype U%
+ \ifcase\absseclevel
+ \unnumberedzzz{#3}%
+ \or \unnumberedseczzz{#3}%
+ \or \unnumberedsubseczzz{#3}%
+ \or \unnumberedsubsubseczzz{#3}%
+ \fi
+ \else
+ \if \headtype A%
+ \ifcase\absseclevel
+ \appendixzzz{#3}%
+ \or \appendixsectionzzz{#3}%
+ \or \appendixsubseczzz{#3}%
+ \or \appendixsubsubseczzz{#3}%
+ \fi
+ \else
+ \ifcase\absseclevel
+ \chapterzzz{#3}%
+ \or \seczzz{#3}%
+ \or \numberedsubseczzz{#3}%
+ \or \numberedsubsubseczzz{#3}%
+ \fi
+ \fi
+ \fi
+ \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered. Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v. By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+ % section resetting is \global in case the chapter is in a group, such
+ % as an @include file.
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\chapno by 1
+ %
+ % Used for \float.
+ \gdef\chaplevelprefix{\the\chapno.}%
+ \resetallfloatnos
+ %
+ % \putwordChapter can contain complex things in translations.
+ \toks0=\expandafter{\putwordChapter}%
+ \message{\the\toks0 \space \the\chapno}%
+ %
+ % Write the actual heading.
+ \chapmacro{#1}{Ynumbered}{\the\chapno}%
+ %
+ % So @section and the like are numbered underneath this chapter.
+ \global\let\section = \numberedsec
+ \global\let\subsection = \numberedsubsec
+ \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz
+%
+\def\appendixzzz#1{%
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\appendixno by 1
+ \gdef\chaplevelprefix{\appendixletter.}%
+ \resetallfloatnos
+ %
+ % \putwordAppendix can contain complex things in translations.
+ \toks0=\expandafter{\putwordAppendix}%
+ \message{\the\toks0 \space \appendixletter}%
+ %
+ \chapmacro{#1}{Yappendix}{\appendixletter}%
+ %
+ \global\let\section = \appendixsec
+ \global\let\subsection = \appendixsubsec
+ \global\let\subsubsection = \appendixsubsubsec
+}
+
+% normally unnmhead0 calls unnumberedzzz:
+\outer\parseargdef\unnumbered{\unnmhead0{#1}}
+\def\unnumberedzzz#1{%
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\unnumberedno by 1
+ %
+ % Since an unnumbered has no number, no prefix for figures.
+ \global\let\chaplevelprefix = \empty
+ \resetallfloatnos
+ %
+ % This used to be simply \message{#1}, but TeX fully expands the
+ % argument to \message. Therefore, if #1 contained @-commands, TeX
+ % expanded them. For example, in `@unnumbered The @cite{Book}', TeX
+ % expanded @cite (which turns out to cause errors because \cite is meant
+ % to be executed, not expanded).
+ %
+ % Anyway, we don't want the fully-expanded definition of @cite to appear
+ % as a result of the \message, we just want `@cite' itself. We use
+ % \the<toks register> to achieve this: TeX expands \the<toks> only once,
+ % simply yielding the contents of <toks register>. (We also do this for
+ % the toc entries.)
+ \toks0 = {#1}%
+ \message{(\the\toks0)}%
+ %
+ \chapmacro{#1}{Ynothing}{\the\unnumberedno}%
+ %
+ \global\let\section = \unnumberedsec
+ \global\let\subsection = \unnumberedsubsec
+ \global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\parseargdef\centerchap{%
+ \let\centerparametersmaybe = \centerparameters
+ \unnmhead0{#1}%
+ \let\centerparametersmaybe = \relax
+}
+
+% @top is like @unnumbered.
+\let\top\unnumbered
+
+% Sections.
+%
+\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz
+\def\seczzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%
+}
+
+% normally calls appendixsectionzzz:
+\outer\parseargdef\appendixsection{\apphead1{#1}}
+\def\appendixsectionzzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+% normally calls unnumberedseczzz:
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}}
+\def\unnumberedseczzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+%
+% normally calls numberedsubseczzz:
+\outer\parseargdef\numberedsubsec{\numhead2{#1}}
+\def\numberedsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+% normally calls appendixsubseczzz:
+\outer\parseargdef\appendixsubsec{\apphead2{#1}}
+\def\appendixsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Yappendix}%
+ {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+% normally calls unnumberedsubseczzz:
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}}
+\def\unnumberedsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Ynothing}%
+ {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+%
+% normally numberedsubsubseczzz:
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}}
+\def\numberedsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Ynumbered}%
+ {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally appendixsubsubseczzz:
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}}
+\def\appendixsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Yappendix}%
+ {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally unnumberedsubsubseczzz:
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}}
+\def\unnumberedsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Ynothing}%
+ {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading{%
+ {\advance\chapheadingskip by 10pt \chapbreak }%
+ \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+ \vbox{\chapfonts \raggedtitlesettings #1\par}%
+ \nobreak\bigskip \nobreak
+ \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+% Parameter controlling skip before chapter headings (if needed)
+\newskip\chapheadingskip
+
+% Define plain chapter starts, and page on/off switching for it.
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+
+% Start a new page
+\def\chappager{\par\vfill\supereject}
+
+% \chapoddpage - start on an odd page for a new chapter
+% Because \domark is called before \chapoddpage, the filler page will
+% get the headings for the next chapter, which is wrong. But we don't
+% care -- we just disable all headings on the filler page.
+\def\chapoddpage{%
+ \chappager
+ \ifodd\pageno \else
+ \begingroup
+ \headingsoff
+ \null
+ \chappager
+ \endgroup
+ \fi
+}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% \chapmacro - Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+% Not used for @heading series.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yappendixkeyword{Yappendix}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+%
+\def\chapmacro#1#2#3{%
+ \expandafter\ifx\thisenv\titlepage\else
+ \checkenv{}% chapters, etc., should not start inside an environment.
+ \fi
+ % FIXME: \chapmacro is currently called from inside \titlepage when
+ % \setcontentsaftertitlepage to print the "Table of Contents" heading, but
+ % this should probably be done by \sectionheading with an option to print
+ % in chapter size.
+ %
+ % Insert the first mark before the heading break (see notes for \domark).
+ \let\prevchapterdefs=\lastchapterdefs
+ \let\prevsectiondefs=\lastsectiondefs
+ \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}%
+ \gdef\thissection{}}%
+ %
+ \def\temptype{#2}%
+ \ifx\temptype\Ynothingkeyword
+ \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+ \gdef\thischapter{\thischaptername}}%
+ \else\ifx\temptype\Yomitfromtockeyword
+ \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+ \gdef\thischapter{}}%
+ \else\ifx\temptype\Yappendixkeyword
+ \toks0={#1}%
+ \xdef\lastchapterdefs{%
+ \gdef\noexpand\thischaptername{\the\toks0}%
+ \gdef\noexpand\thischapternum{\appendixletter}%
+ % \noexpand\putwordAppendix avoids expanding indigestible
+ % commands in some of the translations.
+ \gdef\noexpand\thischapter{\noexpand\putwordAppendix{}
+ \noexpand\thischapternum:
+ \noexpand\thischaptername}%
+ }%
+ \else
+ \toks0={#1}%
+ \xdef\lastchapterdefs{%
+ \gdef\noexpand\thischaptername{\the\toks0}%
+ \gdef\noexpand\thischapternum{\the\chapno}%
+ % \noexpand\putwordChapter avoids expanding indigestible
+ % commands in some of the translations.
+ \gdef\noexpand\thischapter{\noexpand\putwordChapter{}
+ \noexpand\thischapternum:
+ \noexpand\thischaptername}%
+ }%
+ \fi\fi\fi
+ %
+ % Output the mark. Pass it through \safewhatsit, to take care of
+ % the preceding space.
+ \safewhatsit\domark
+ %
+ % Insert the chapter heading break.
+ \pchapsepmacro
+ %
+ % Now the second mark, after the heading break. No break points
+ % between here and the heading.
+ \let\prevchapterdefs=\lastchapterdefs
+ \let\prevsectiondefs=\lastsectiondefs
+ \domark
+ %
+ {%
+ \chapfonts \rmisbold
+ \let\footnote=\errfootnoteheading % give better error message
+ %
+ % Have to define \lastsection before calling \donoderef, because the
+ % xref code eventually uses it. On the other hand, it has to be called
+ % after \pchapsepmacro, or the headline will change too soon.
+ \gdef\lastsection{#1}%
+ %
+ % Only insert the separating space if we have a chapter/appendix
+ % number, and don't print the unnumbered ``number''.
+ \ifx\temptype\Ynothingkeyword
+ \setbox0 = \hbox{}%
+ \def\toctype{unnchap}%
+ \else\ifx\temptype\Yomitfromtockeyword
+ \setbox0 = \hbox{}% contents like unnumbered, but no toc entry
+ \def\toctype{omit}%
+ \else\ifx\temptype\Yappendixkeyword
+ \setbox0 = \hbox{\putwordAppendix{} #3\enspace}%
+ \def\toctype{app}%
+ \else
+ \setbox0 = \hbox{#3\enspace}%
+ \def\toctype{numchap}%
+ \fi\fi\fi
+ %
+ % Write the toc entry for this chapter. Must come before the
+ % \donoderef, because we include the current node name in the toc
+ % entry, and \donoderef resets it to empty.
+ \writetocentry{\toctype}{#1}{#3}%
+ %
+ % For pdftex, we have to write out the node definition (aka, make
+ % the pdfdest) after any page break, but before the actual text has
+ % been typeset. If the destination for the pdf outline is after the
+ % text, then jumping from the outline may wind up with the text not
+ % being visible, for instance under high magnification.
+ \donoderef{#2}%
+ %
+ % Typeset the actual heading.
+ \nobreak % Avoid page breaks at the interline glue.
+ \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe
+ \unhbox0 #1\par}%
+ }%
+ \nobreak\bigskip % no page break after a chapter title
+ \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+ \advance\rightskip by 3\rightskip
+ \leftskip = \rightskip
+ \parfillskip = 0pt
+}
+
+
+% I don't think this chapter style is supported any more, so I'm not
+% updating it with the new noderef stuff. We'll see. --karl, 11aug03.
+%
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+%
+\def\unnchfopen #1{%
+ \chapoddpage
+ \vbox{\chapfonts \raggedtitlesettings #1\par}%
+ \nobreak\bigskip\nobreak
+}
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+\def\centerchfopen #1{%
+ \chapoddpage
+ \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}%
+ \nobreak\bigskip \nobreak
+}
+\def\CHAPFopen{%
+ \global\let\chapmacro=\chfopen
+ \global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles. These macros combine the section number parts and
+% call the generic \sectionheading to do the printing.
+%
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip{-1000}}
+
+% Subsection titles.
+\newskip\subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}}
+
+% Subsubsection titles.
+\def\subsubsecheadingskip{\subsecheadingskip}
+\def\subsubsecheadingbreak{\subsecheadingbreak}
+
+
+% Print any size, any type, section title.
+%
+% #1 is the text of the title,
+% #2 is the section level (sec/subsec/subsubsec),
+% #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc),
+% #4 is the section number.
+%
+\def\seckeyword{sec}
+%
+\def\sectionheading#1#2#3#4{%
+ {%
+ \def\sectionlevel{#2}%
+ \def\temptype{#3}%
+ %
+ % It is ok for the @heading series commands to appear inside an
+ % environment (it's been historically allowed, though the logic is
+ % dubious), but not the others.
+ \ifx\temptype\Yomitfromtockeyword\else
+ \checkenv{}% non-@*heading should not be in an environment.
+ \fi
+ \let\footnote=\errfootnoteheading
+ %
+ % Switch to the right set of fonts.
+ \csname #2fonts\endcsname \rmisbold
+ %
+ % Insert first mark before the heading break (see notes for \domark).
+ \let\prevsectiondefs=\lastsectiondefs
+ \ifx\temptype\Ynothingkeyword
+ \ifx\sectionlevel\seckeyword
+ \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}%
+ \gdef\thissection{\thissectionname}}%
+ \fi
+ \else\ifx\temptype\Yomitfromtockeyword
+ % Don't redefine \thissection.
+ \else\ifx\temptype\Yappendixkeyword
+ \ifx\sectionlevel\seckeyword
+ \toks0={#1}%
+ \xdef\lastsectiondefs{%
+ \gdef\noexpand\thissectionname{\the\toks0}%
+ \gdef\noexpand\thissectionnum{#4}%
+ % \noexpand\putwordSection avoids expanding indigestible
+ % commands in some of the translations.
+ \gdef\noexpand\thissection{\noexpand\putwordSection{}
+ \noexpand\thissectionnum:
+ \noexpand\thissectionname}%
+ }%
+ \fi
+ \else
+ \ifx\sectionlevel\seckeyword
+ \toks0={#1}%
+ \xdef\lastsectiondefs{%
+ \gdef\noexpand\thissectionname{\the\toks0}%
+ \gdef\noexpand\thissectionnum{#4}%
+ % \noexpand\putwordSection avoids expanding indigestible
+ % commands in some of the translations.
+ \gdef\noexpand\thissection{\noexpand\putwordSection{}
+ \noexpand\thissectionnum:
+ \noexpand\thissectionname}%
+ }%
+ \fi
+ \fi\fi\fi
+ %
+ % Go into vertical mode. Usually we'll already be there, but we
+ % don't want the following whatsit to end up in a preceding paragraph
+ % if the document didn't happen to have a blank line.
+ \par
+ %
+ % Output the mark. Pass it through \safewhatsit, to take care of
+ % the preceding space.
+ \safewhatsit\domark
+ %
+ % Insert space above the heading.
+ \csname #2headingbreak\endcsname
+ %
+ % Now the second mark, after the heading break. No break points
+ % between here and the heading.
+ \global\let\prevsectiondefs=\lastsectiondefs
+ \domark
+ %
+ % Only insert the space after the number if we have a section number.
+ \ifx\temptype\Ynothingkeyword
+ \setbox0 = \hbox{}%
+ \def\toctype{unn}%
+ \gdef\lastsection{#1}%
+ \else\ifx\temptype\Yomitfromtockeyword
+ % for @headings -- no section number, don't include in toc,
+ % and don't redefine \lastsection.
+ \setbox0 = \hbox{}%
+ \def\toctype{omit}%
+ \let\sectionlevel=\empty
+ \else\ifx\temptype\Yappendixkeyword
+ \setbox0 = \hbox{#4\enspace}%
+ \def\toctype{app}%
+ \gdef\lastsection{#1}%
+ \else
+ \setbox0 = \hbox{#4\enspace}%
+ \def\toctype{num}%
+ \gdef\lastsection{#1}%
+ \fi\fi\fi
+ %
+ % Write the toc entry (before \donoderef). See comments in \chapmacro.
+ \writetocentry{\toctype\sectionlevel}{#1}{#4}%
+ %
+ % Write the node reference (= pdf destination for pdftex).
+ % Again, see comments in \chapmacro.
+ \donoderef{#3}%
+ %
+ % Interline glue will be inserted when the vbox is completed.
+ % That glue will be a valid breakpoint for the page, since it'll be
+ % preceded by a whatsit (usually from the \donoderef, or from the
+ % \writetocentry if there was no node). We don't want to allow that
+ % break, since then the whatsits could end up on page n while the
+ % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000.
+ \nobreak
+ %
+ % Output the actual section heading.
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright
+ \hangindent=\wd0 % zero if no section number
+ \unhbox0 #1}%
+ }%
+ % Add extra space after the heading -- half of whatever came above it.
+ % Don't allow stretch, though.
+ \kern .5 \csname #2headingskip\endcsname
+ %
+ % Do not let the kern be a potential breakpoint, as it would be if it
+ % was followed by glue.
+ \nobreak
+ %
+ % We'll almost certainly start a paragraph next, so don't let that
+ % glue accumulate. (Not a breakpoint because it's preceded by a
+ % discardable item.) However, when a paragraph is not started next
+ % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out
+ % or the negative glue will cause weirdly wrong output, typically
+ % obscuring the section heading with something else.
+ \vskip-\parskip
+ %
+ % This is so the last item on the main vertical list is a known
+ % \penalty > 10000, so \startdefun, etc., can recognize the situation
+ % and do the needful.
+ \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this. The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything. This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+ \edef\writetoctype{#1}%
+ \ifx\writetoctype\omitkeyword \else
+ \iftocfileopened\else
+ \immediate\openout\tocfile = \jobname.toc
+ \global\tocfileopenedtrue
+ \fi
+ %
+ \iflinks
+ {\atdummies
+ \edef\temp{%
+ \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}%
+ \temp
+ }%
+ \fi
+ \fi
+ %
+ % Tell \shipout to create a pdf destination on each page, if we're
+ % writing pdf. These are used in the table of contents. We can't
+ % just write one on every page because the title pages are numbered
+ % 1 and 2 (the page numbers aren't printed), and so are the first
+ % two pages of the document. Thus, we'd have two destinations named
+ % `1', and two named `2'.
+ \ifpdf \global\pdfmakepagedesttrue \fi
+}
+
+
+% These characters do not print properly in the Computer Modern roman
+% fonts, so we must take special care. This is more or less redundant
+% with the Texinfo input format setup at the end of this file.
+%
+\def\activecatcodes{%
+ \catcode`\"=\active
+ \catcode`\$=\active
+ \catcode`\<=\active
+ \catcode`\>=\active
+ \catcode`\\=\active
+ \catcode`\^=\active
+ \catcode`\_=\active
+ \catcode`\|=\active
+ \catcode`\~=\active
+}
+
+
+% Read the toc file, which is essentially Texinfo input.
+\def\readtocfile{%
+ \setupdatafile
+ \activecatcodes
+ \input \tocreadfilename
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Prepare to read what we've written to \tocfile.
+%
+\def\startcontents#1{%
+ % If @setchapternewpage on, and @headings double, the contents should
+ % start on an odd page, unlike chapters. Thus, we maintain
+ % \contentsalignmacro in parallel with \pagealignmacro.
+ % From: Torbjorn Granlund <tege@matematik.su.se>
+ \contentsalignmacro
+ \immediate\closeout\tocfile
+ %
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \chapmacro{#1}{Yomitfromtoc}{}%
+ %
+ \savepageno = \pageno
+ \begingroup % Set up to handle contents files properly.
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \entryrightmargin=\contentsrightmargin % Don't use the full line length.
+ %
+ % Roman numerals for page numbers.
+ \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+}
+
+% redefined for the two-volume lispref. We always output on
+% \jobname.toc even if this is redefined.
+%
+\def\tocreadfilename{\jobname.toc}
+
+% Normal (long) toc.
+%
+\def\contents{%
+ \startcontents{\putwordTOC}%
+ \openin 1 \tocreadfilename\space
+ \ifeof 1 \else
+ \readtocfile
+ \fi
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \ifeof 1 \else
+ \pdfmakeoutlines
+ \fi
+ \closein 1
+ \endgroup
+ \lastnegativepageno = \pageno
+ \global\pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+ \startcontents{\putwordShortTOC}%
+ %
+ \let\partentry = \shortpartentry
+ \let\numchapentry = \shortchapentry
+ \let\appentry = \shortchapentry
+ \let\unnchapentry = \shortunnchapentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf
+ \let\sl=\shortcontsl \let\tt=\shortconttt
+ \rm
+ \hyphenpenalty = 10000
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\numsecentry##1##2##3##4{}
+ \let\appsecentry = \numsecentry
+ \let\unnsecentry = \numsecentry
+ \let\numsubsecentry = \numsecentry
+ \let\appsubsecentry = \numsecentry
+ \let\unnsubsecentry = \numsecentry
+ \let\numsubsubsecentry = \numsecentry
+ \let\appsubsubsecentry = \numsecentry
+ \let\unnsubsubsecentry = \numsecentry
+ \openin 1 \tocreadfilename\space
+ \ifeof 1 \else
+ \readtocfile
+ \fi
+ \closein 1
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \lastnegativepageno = \pageno
+ \global\pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g., `A' for an appendix, or `3' for a chapter.
+%
+\def\shortchaplabel#1{%
+ % This space should be enough, since a single number is .5em, and the
+ % widest letter (M) is 1em, at least in the Computer Modern fonts.
+ % But use \hss just in case.
+ % (This space doesn't include the extra space that gets added after
+ % the label; that gets put in by \shortchapentry above.)
+ %
+ % We'd like to right-justify chapter numbers, but that looks strange
+ % with appendix letters. And right-justifying numbers and
+ % left-justifying letters looks strange when there is less than 10
+ % chapters. Have to read the whole toc once to know how many chapters
+ % there are before deciding ...
+ \hbox to 1em{#1\hss}%
+}
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Parts, in the main contents. Replace the part number, which doesn't
+% exist, with an empty box. Let's hope all the numbers have the same width.
+% Also ignore the page number, which is conventionally not printed.
+\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}}
+\def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}}
+%
+% Parts, in the short toc.
+\def\shortpartentry#1#2#3#4{%
+ \penalty-300
+ \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip
+ \shortchapentry{{\bf #1}}{\numeralbox}{}{}%
+}
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+ % We use M since it's probably the widest letter.
+ \setbox0 = \hbox{\putwordAppendix{} M}%
+ \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\hskip.7em#1}{#4}}
+
+% Unnumbered chapters.
+\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}}
+\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}}
+
+% Sections.
+\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}}
+\let\appsecentry=\numsecentry
+\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}}
+
+% Subsections.
+\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsecentry=\numsubsecentry
+\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}}
+
+% And subsubsections.
+\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsubsecentry=\numsubsubsecentry
+\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}}
+
+% This parameter controls the indentation of the various levels.
+% Same as \defaultparindent.
+\newdimen\tocindent \tocindent = 15pt
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+ \begingroup
+ % Move the page numbers slightly to the right
+ \advance\entryrightmargin by -0.05em
+ \chapentryfonts
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+ \endgroup
+ \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+ \secentryfonts \leftskip=\tocindent
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+ \subsecentryfonts \leftskip=2\tocindent
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+ \subsubsecentryfonts \leftskip=3\tocindent
+ \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+% We use the same \entry macro as for the index entries.
+\let\tocentry = \entry
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\def\subsecentryfonts{\textfonts}
+\def\subsubsecentryfonts{\textfonts}
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% @tex ... @end tex escapes into raw TeX temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain @ character.
+
+\envdef\tex{%
+ \setupmarkupstyle{tex}%
+ \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+ \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+ \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie
+ \catcode `\%=14
+ \catcode `\+=\other
+ \catcode `\"=\other
+ \catcode `\|=\other
+ \catcode `\<=\other
+ \catcode `\>=\other
+ \catcode `\`=\other
+ \catcode `\'=\other
+ \escapechar=`\\
+ %
+ % ' is active in math mode (mathcode"8000). So reset it, and all our
+ % other math active characters (just in case), to plain's definitions.
+ \mathactive
+ %
+ % Inverse of the list at the beginning of the file.
+ \let\b=\ptexb
+ \let\bullet=\ptexbullet
+ \let\c=\ptexc
+ \let\,=\ptexcomma
+ \let\.=\ptexdot
+ \let\dots=\ptexdots
+ \let\equiv=\ptexequiv
+ \let\!=\ptexexclam
+ \let\i=\ptexi
+ \let\indent=\ptexindent
+ \let\noindent=\ptexnoindent
+ \let\{=\ptexlbrace
+ \let\+=\tabalign
+ \let\}=\ptexrbrace
+ \let\/=\ptexslash
+ \let\sp=\ptexsp
+ \let\*=\ptexstar
+ %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode
+ \let\t=\ptext
+ \expandafter \let\csname top\endcsname=\ptextop % we've made it outer
+ \let\frenchspacing=\plainfrenchspacing
+ %
+ \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+ \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+ \def\@{@}%
+}
+% There is no need to define \Etex.
+
+% Define @lisp ... @end lisp.
+% @lisp environment forms a group so it can rebind things,
+% including the definition of @end lisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments. \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical. We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip.
+%
+\def\aboveenvbreak{{%
+ % =10000 instead of <10000 because of a special case in \itemzzz and
+ % \sectionheading, q.v.
+ \ifnum \lastpenalty=10000 \else
+ \advance\envskipamount by \parskip
+ \endgraf
+ \ifdim\lastskip<\envskipamount
+ \removelastskip
+ \ifnum\lastpenalty<10000
+ % Penalize breaking before the environment, because preceding text
+ % often leads into it.
+ \penalty100
+ \fi
+ \vskip\envskipamount
+ \fi
+ \fi
+}}
+
+\def\afterenvbreak{{%
+ % =10000 instead of <10000 because of a special case in \itemzzz and
+ % \sectionheading, q.v.
+ \ifnum \lastpenalty=10000 \else
+ \advance\envskipamount by \parskip
+ \endgraf
+ \ifdim\lastskip<\envskipamount
+ \removelastskip
+ % it's not a good place to break if the last penalty was \nobreak
+ % or better ...
+ \ifnum\lastpenalty<10000 \penalty-50 \fi
+ \vskip\envskipamount
+ \fi
+ \fi
+}}
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will
+% also clear it, so that its embedded environments do the narrowing again.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+ \ctl\leaders\hrule height\circthick\hfil\ctr
+ \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+ \cbl\leaders\hrule height\circthick\hfil\cbr
+ \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\envdef\cartouche{%
+ \ifhmode\par\fi % can't be in the midst of a paragraph.
+ \startsavinginserts
+ \lskip=\leftskip \rskip=\rightskip
+ \leftskip=0pt\rightskip=0pt % we want these *outside*.
+ \cartinner=\hsize \advance\cartinner by-\lskip
+ \advance\cartinner by-\rskip
+ \cartouter=\hsize
+ \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+ % side, and for 6pt waste from
+ % each corner char, and rule thickness
+ \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+ %
+ % If this cartouche directly follows a sectioning command, we need the
+ % \parskip glue (backspaced over by default) or the cartouche can
+ % collide with the section heading.
+ \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi
+ %
+ \setbox\groupbox=\vbox\bgroup
+ \baselineskip=0pt\parskip=0pt\lineskip=0pt
+ \carttop
+ \hbox\bgroup
+ \hskip\lskip
+ \vrule\kern3pt
+ \vbox\bgroup
+ \kern3pt
+ \hsize=\cartinner
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+ \comment % For explanation, see the end of def\group.
+}
+\def\Ecartouche{%
+ \ifhmode\par\fi
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+ \addgroupbox
+ \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\newdimen\nonfillparindent
+\def\nonfillstart{%
+ \aboveenvbreak
+ \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % Don't be fussy
+ \sepspaces % Make spaces be word-separators rather than space tokens.
+ \let\par = \lisppar % don't ignore blank lines
+ \obeylines % each line of input is a line of output
+ \parskip = 0pt
+ % Turn off paragraph indentation but redefine \indent to emulate
+ % the normal \indent.
+ \nonfillparindent=\parindent
+ \parindent = 0pt
+ \let\indent\nonfillindent
+ %
+ \emergencystretch = 0pt % don't try to avoid overfull boxes
+ \ifx\nonarrowing\relax
+ \advance \leftskip by \lispnarrowing
+ \exdentamount=\lispnarrowing
+ \else
+ \let\nonarrowing = \relax
+ \fi
+ \let\exdent=\nofillexdent
+}
+
+\begingroup
+\obeyspaces
+% We want to swallow spaces (but not other tokens) after the fake
+% @indent in our nonfill-environments, where spaces are normally
+% active and set to @tie, resulting in them not being ignored after
+% @indent.
+\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}%
+\gdef\nonfillindentcheck{%
+\ifx\temp %
+\expandafter\nonfillindentgobble%
+\else%
+\leavevmode\nonfillindentbox%
+\fi%
+}%
+\endgroup
+\def\nonfillindentgobble#1{\nonfillindent}
+\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}}
+
+% If you want all examples etc. small: @set dispenvsize small.
+% If you want even small examples the full size: @set dispenvsize nosmall.
+% This affects the following displayed environments:
+% @example, @display, @format, @lisp
+%
+\def\smallword{small}
+\def\nosmallword{nosmall}
+\let\SETdispenvsize\relax
+\def\setnormaldispenv{%
+ \ifx\SETdispenvsize\smallword
+ % end paragraph for sake of leading, in case document has no blank
+ % line. This is redundant with what happens in \aboveenvbreak, but
+ % we need to do it before changing the fonts, and it's inconvenient
+ % to change the fonts afterward.
+ \ifnum \lastpenalty=10000 \else \endgraf \fi
+ \smallexamplefonts \rm
+ \fi
+}
+\def\setsmalldispenv{%
+ \ifx\SETdispenvsize\nosmallword
+ \else
+ \ifnum \lastpenalty=10000 \else \endgraf \fi
+ \smallexamplefonts \rm
+ \fi
+}
+
+% We often define two environments, @foo and @smallfoo.
+% Let's do it in one command. #1 is the env name, #2 the definition.
+\def\makedispenvdef#1#2{%
+ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}%
+ \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}%
+ \expandafter\let\csname E#1\endcsname \afterenvbreak
+ \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two environment synonyms (#1 and #2) for an environment.
+\def\maketwodispenvdef#1#2#3{%
+ \makedispenvdef{#1}{#3}%
+ \makedispenvdef{#2}{#3}%
+}
+%
+% @lisp: indented, narrowed, typewriter font;
+% @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvdef{lisp}{example}{%
+ \nonfillstart
+ \tt\setupmarkupstyle{example}%
+ \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+ \gobble % eat return
+}
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenvdef{display}{%
+ \nonfillstart
+ \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenvdef{format}{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \advance\leftskip by 0pt plus 1fill\relax
+ \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification. From plain.tex. Don't stretch around special
+% characters in urls in this environment, since the stretch at the right
+% should be enough.
+\envdef\raggedright{%
+ \rightskip0pt plus2.4em \spaceskip.3333em \xspaceskip.5em\relax
+ \def\urefprestretchamount{0pt}%
+ \def\urefpoststretchamount{0pt}%
+}
+\let\Eraggedright\par
+
+\envdef\raggedleft{%
+ \parindent=0pt \leftskip0pt plus2em
+ \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+ \hbadness=10000 % Last line will usually be underfull, so turn off
+ % badness reporting.
+}
+\let\Eraggedleft\par
+
+\envdef\raggedcenter{%
+ \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em
+ \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+ \hbadness=10000 % Last line will usually be underfull, so turn off
+ % badness reporting.
+}
+\let\Eraggedcenter\par
+
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins. We keep \parskip nonzero in general, since
+% we're doing normal filling. So, when using \aboveenvbreak and
+% \afterenvbreak, temporarily make \parskip 0.
+%
+\makedispenvdef{quotation}{\quotationstart}
+%
+\def\quotationstart{%
+ \indentedblockstart % same as \indentedblock, but increase right margin too.
+ \ifx\nonarrowing\relax
+ \advance\rightskip by \lispnarrowing
+ \fi
+ \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+ \par
+ \ifx\quotationauthor\thisisundefined\else
+ % indent a bit.
+ \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+ \fi
+ {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallquotation{\Equotation}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+ \def\temp{#1}%
+ \ifx\temp\empty \else
+ {\bf #1: }%
+ \fi
+}
+
+% @indentedblock is like @quotation, but indents only on the left and
+% has no optional argument.
+%
+\makedispenvdef{indentedblock}{\indentedblockstart}
+%
+\def\indentedblockstart{%
+ {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+ \parindent=0pt
+ %
+ % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+ \ifx\nonarrowing\relax
+ \advance\leftskip by \lispnarrowing
+ \exdentamount = \lispnarrowing
+ \else
+ \let\nonarrowing = \relax
+ \fi
+}
+
+% Keep a nonzero parskip for the environment, since we're doing normal filling.
+%
+\def\Eindentedblock{%
+ \par
+ {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallindentedblock{\Eindentedblock}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> as delimiter,
+% we need the curly braces so that makeinfo sees the @verb command, eg:
+% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org
+%
+% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook.
+%
+% [Knuth] p.344; only we need to do the other characters Texinfo sets
+% active too. Otherwise, they get lost as the first character on a
+% verbatim line.
+\def\dospecials{%
+ \do\ \do\\\do\{\do\}\do\$\do\&%
+ \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~%
+ \do\<\do\>\do\|\do\@\do+\do\"%
+ % Don't do the quotes -- if we do, @set txicodequoteundirected and
+ % @set txicodequotebacktick will not have effect on @verb and
+ % @verbatim, and ?` and !` ligatures won't get disabled.
+ %\do\`\do\'%
+}
+%
+% [Knuth] p. 380
+\def\uncatcodespecials{%
+ \def\do##1{\catcode`##1=\other}\dospecials}
+%
+% Setup for the @verb command.
+%
+% Eight spaces for a tab
+\begingroup
+ \catcode`\^^I=\active
+ \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }}
+\endgroup
+%
+\def\setupverb{%
+ \tt % easiest (and conventionally used) font for verbatim
+ \def\par{\leavevmode\endgraf}%
+ \setupmarkupstyle{verb}%
+ \tabeightspaces
+ % Respect line breaks,
+ % print special symbols as themselves, and
+ % make each space count
+ % must do in this order:
+ \obeylines \uncatcodespecials \sepspaces
+}
+
+% Setup for the @verbatim environment
+%
+% Real tab expansion.
+\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount
+%
+% We typeset each line of the verbatim in an \hbox, so we can handle
+% tabs. The \global is in case the verbatim line starts with an accent,
+% or some other command that starts with a begin-group. Otherwise, the
+% entire \verbbox would disappear at the corresponding end-group, before
+% it is typeset. Meanwhile, we can't have nested verbatim commands
+% (can we?), so the \global won't be overwriting itself.
+\newbox\verbbox
+\def\starttabbox{\global\setbox\verbbox=\hbox\bgroup}
+%
+\begingroup
+ \catcode`\^^I=\active
+ \gdef\tabexpand{%
+ \catcode`\^^I=\active
+ \def^^I{\leavevmode\egroup
+ \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab
+ \divide\dimen\verbbox by\tabw
+ \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw
+ \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw
+ \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox
+ }%
+ }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \tt % easiest (and conventionally used) font for verbatim
+ % The \leavevmode here is for blank lines. Otherwise, we would
+ % never \starttabox and the \egroup would end verbatim mode.
+ \def\par{\leavevmode\egroup\box\verbbox\endgraf}%
+ \tabexpand
+ \setupmarkupstyle{verbatim}%
+ % Respect line breaks,
+ % print special symbols as themselves, and
+ % make each space count.
+ % Must do in this order:
+ \obeylines \uncatcodespecials \sepspaces
+ \everypar{\starttabbox}%
+}
+
+% Do the @verb magic: verbatim text is quoted by unique
+% delimiter characters. Before first delimiter expect a
+% right brace, after last delimiter expect closing brace:
+%
+% \def\doverb'{'<char>#1<char>'}'{#1}
+%
+% [Knuth] p. 382; only eat outer {}
+\begingroup
+ \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other
+ \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next]
+\endgroup
+%
+\def\verb{\begingroup\setupverb\doverb}
+%
+%
+% Do the @verbatim magic: define the macro \doverbatim so that
+% the (first) argument ends when '@end verbatim' is reached, ie:
+%
+% \def\doverbatim#1@end verbatim{#1}
+%
+% For Texinfo it's a lot easier than for LaTeX,
+% because texinfo's \verbatim doesn't stop at '\end{verbatim}':
+% we need not redefine '\', '{' and '}'.
+%
+% Inspired by LaTeX's verbatim command set [latex.ltx]
+%
+\begingroup
+ \catcode`\ =\active
+ \obeylines %
+ % ignore everything up to the first ^^M, that's the newline at the end
+ % of the @verbatim input line itself. Otherwise we get an extra blank
+ % line in the output.
+ \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}%
+ % We really want {...\end verbatim} in the body of the macro, but
+ % without the active space; thus we have to use \xdef and \gobble.
+\endgroup
+%
+\envdef\verbatim{%
+ \setupverbatim\doverbatim
+}
+\let\Everbatim = \afterenvbreak
+
+
+% @verbatiminclude FILE - insert text of file in verbatim environment.
+%
+\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude}
+%
+\def\doverbatiminclude#1{%
+ {%
+ \makevalueexpandable
+ \setupverbatim
+ \indexnofonts % Allow `@@' and other weird things in file names.
+ \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}%
+ \input #1
+ \afterenvbreak
+ }%
+}
+
+% @copying ... @end copying.
+% Save the text away for @insertcopying later.
+%
+% We save the uninterpreted tokens, rather than creating a box.
+% Saving the text in a box would be much easier, but then all the
+% typesetting commands (@smallbook, font changes, etc.) have to be done
+% beforehand -- and a) we want @copying to be done first in the source
+% file; b) letting users define the frontmatter in as flexible order as
+% possible is desirable.
+%
+\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
+\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+%
+\def\insertcopying{%
+ \begingroup
+ \parindent = 0pt % paragraph indentation looks wrong on title page
+ \scanexp\copyingtext
+ \endgroup
+}
+
+
+\message{defuns,}
+% @defun etc.
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+\newcount\defunpenalty
+
+% Start the processing of @deffn:
+\def\startdefun{%
+ \ifnum\lastpenalty<10000
+ \medbreak
+ \defunpenalty=10003 % Will keep this @deffn together with the
+ % following @def command, see below.
+ \else
+ % If there are two @def commands in a row, we'll have a \nobreak,
+ % which is there to keep the function description together with its
+ % header. But if there's nothing but headers, we need to allow a
+ % break somewhere. Check specifically for penalty 10002, inserted
+ % by \printdefunline, instead of 10000, since the sectioning
+ % commands also insert a nobreak penalty, and we don't want to allow
+ % a break between a section heading and a defun.
+ %
+ % As a further refinement, we avoid "club" headers by signalling
+ % with penalty of 10003 after the very first @deffn in the
+ % sequence (see above), and penalty of 10002 after any following
+ % @def command.
+ \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi
+ %
+ % Similarly, after a section heading, do not allow a break.
+ % But do insert the glue.
+ \medskip % preceded by discardable penalty, so not a breakpoint
+ \fi
+ %
+ \parindent=0in
+ \advance\leftskip by \defbodyindent
+ \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+ % First, check whether we are in the right environment:
+ \checkenv#1%
+ %
+ % As above, allow line break if we have multiple x headers in a row.
+ % It's not a great place, though.
+ \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi
+ %
+ % And now, it's time to reuse the body of the original defun:
+ \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+ \begingroup
+ % call \deffnheader:
+ #1#2 \endheader
+ % common ending:
+ \interlinepenalty = 10000
+ \advance\rightskip by 0pt plus 1fil\relax
+ \endgraf
+ \nobreak\vskip -\parskip
+ \penalty\defunpenalty % signal to \startdefun and \dodefunx
+ % Some of the @defun-type tags do not enable magic parentheses,
+ % rendering the following check redundant. But we don't optimize.
+ \checkparencounts
+ \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remaining is to define \deffnheader.
+%
+\def\makedefun#1{%
+ \expandafter\let\csname E#1\endcsname = \Edefun
+ \edef\temp{\noexpand\domakedefun
+ \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+ \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) }
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+ \envdef#1{%
+ \startdefun
+ \doingtypefnfalse % distinguish typed functions from all else
+ \parseargusing\activeparens{\printdefunline#3}%
+ }%
+ \def#2{\dodefunx#1}%
+ \def#3%
+}
+
+\newif\ifdoingtypefn % doing typed function?
+\newif\ifrettypeownline % typeset return type on its own line?
+
+% @deftypefnnewline on|off says whether the return type of typed functions
+% are printed on their own line. This affects @deftypefn, @deftypefun,
+% @deftypeop, and @deftypemethod.
+%
+\parseargdef\deftypefnnewline{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETtxideftypefnnl\endcsname
+ = \empty
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETtxideftypefnnl\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @txideftypefnnl value `\temp',
+ must be on|off}%
+ \fi\fi
+}
+
+% Untyped functions:
+
+% @deffn category name args
+\makedefun{deffn}{\deffngeneral{}}
+
+% @deffn category class name args
+\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
+
+% \defopon {category on}class name args
+\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deffngeneral {subind}category name args
+%
+\def\deffngeneral#1#2 #3 #4\endheader{%
+ % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}.
+ \dosubind{fn}{\code{#3}}{#1}%
+ \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+}
+
+% Typed functions:
+
+% @deftypefn category type name args
+\makedefun{deftypefn}{\deftypefngeneral{}}
+
+% @deftypeop category class type name args
+\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
+
+% \deftypeopon {category on}class type name args
+\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypefngeneral {subind}category type name args
+%
+\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
+ \dosubind{fn}{\code{#4}}{#1}%
+ \doingtypefntrue
+ \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+ \dosubind{vr}{\code{#4}}{#1}%
+ \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+% Types:
+
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+ \doind{tp}{\code{#2}}%
+ \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+ \par
+ % Get the values of \leftskip and \rightskip as they were outside the @def...
+ \advance\leftskip by -\defbodyindent
+ %
+ % Determine if we are typesetting the return type of a typed function
+ % on a line by itself.
+ \rettypeownlinefalse
+ \ifdoingtypefn % doing a typed function specifically?
+ % then check user option for putting return type on its own line:
+ \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
+ \rettypeownlinetrue
+ \fi
+ \fi
+ %
+ % How we'll format the category name. Putting it in brackets helps
+ % distinguish it from the body text that may end up on the next line
+ % just below it.
+ \def\temp{#1}%
+ \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+ %
+ % Figure out line sizes for the paragraph shape. We'll always have at
+ % least two.
+ \tempnum = 2
+ %
+ % The first line needs space for \box0; but if \rightskip is nonzero,
+ % we need only space for the part of \box0 which exceeds it:
+ \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip
+ %
+ % If doing a return type on its own line, we'll have another line.
+ \ifrettypeownline
+ \advance\tempnum by 1
+ \def\maybeshapeline{0in \hsize}%
+ \else
+ \def\maybeshapeline{}%
+ \fi
+ %
+ % The continuations:
+ \dimen2=\hsize \advance\dimen2 by -\defargsindent
+ %
+ % The final paragraph shape:
+ \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2
+ %
+ % Put the category name at the right margin.
+ \noindent
+ \hbox to 0pt{%
+ \hfil\box0 \kern-\hsize
+ % \hsize has to be shortened this way:
+ \kern\leftskip
+ % Intentionally do not respect \rightskip, since we need the space.
+ }%
+ %
+ % Allow all lines to be underfull without complaint:
+ \tolerance=10000 \hbadness=10000
+ \exdentamount=\defbodyindent
+ {%
+ % defun fonts. We use typewriter by default (used to be bold) because:
+ % . we're printing identifiers, they should be in tt in principle.
+ % . in languages with many accents, such as Czech or French, it's
+ % common to leave accents off identifiers. The result looks ok in
+ % tt, but exceedingly strange in rm.
+ % . we don't want -- and --- to be treated as ligatures.
+ % . this still does not fix the ?` and !` ligatures, but so far no
+ % one has made identifiers using them :).
+ \df \tt
+ \def\temp{#2}% text of the return type
+ \ifx\temp\empty\else
+ \tclose{\temp}% typeset the return type
+ \ifrettypeownline
+ % put return type on its own line; prohibit line break following:
+ \hfil\vadjust{\nobreak}\break
+ \else
+ \space % type on same line, so just followed by a space
+ \fi
+ \fi % no return type
+ #3% output function name
+ }%
+ {\rm\enskip}% hskip 0.5 em of \tenrm
+ %
+ \boldbrax
+ % arguments will be output next, if any.
+}
+
+% Print arguments in slanted roman (not ttsl), inconsistently with using
+% tt for the name. This is because literal text is sometimes needed in
+% the argument list (groff manual), and ttsl and tt are not very
+% distinguishable. Prevent hyphenation at `-' chars.
+%
+\def\defunargs#1{%
+ % use sl by default (not ttsl),
+ % tt for the names.
+ \df \sl \hyphenchar\font=0
+ %
+ % On the other hand, if an argument has two dashes (for instance), we
+ % want a way to get ttsl. We used to recommend @var for that, so
+ % leave the code in, but it's strange for @var to lead to typewriter.
+ % Nowadays we recommend @code, since the difference between a ttsl hyphen
+ % and a tt hyphen is pretty tiny. @code also disables ?` !`.
+ \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}%
+ #1%
+ \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+ \catcode`\(=\active \catcode`\)=\active
+ \catcode`\[=\active \catcode`\]=\active
+ \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc. For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+ \activeparens
+ \global\let(=\lparen \global\let)=\rparen
+ \global\let[=\lbrack \global\let]=\rbrack
+ \global\let& = \&
+
+ \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+ \gdef\magicamp{\let&=\amprm}
+}
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\def\parenfont{%
+ \ifampseen
+ % At the first level, print parens in roman,
+ % otherwise use the default font.
+ \ifnum \parencount=1 \rm \fi
+ \else
+ % The \sf parens (in \boldbrax) actually are a little bolder than
+ % the contained text. This is especially needed for [ and ] .
+ \sf
+ \fi
+}
+\def\infirstlevel#1{%
+ \ifampseen
+ \ifnum\parencount=1
+ #1%
+ \fi
+ \fi
+}
+\def\bfafterword#1 {#1 \bf}
+
+\def\opnr{%
+ \global\advance\parencount by 1
+ {\parenfont(}%
+ \infirstlevel \bfafterword
+}
+\def\clnr{%
+ {\parenfont)}%
+ \infirstlevel \sl
+ \global\advance\parencount by -1
+}
+
+\newcount\brackcount
+\def\lbrb{%
+ \global\advance\brackcount by 1
+ {\bf[}%
+}
+\def\rbrb{%
+ {\bf]}%
+ \global\advance\brackcount by -1
+}
+
+\def\checkparencounts{%
+ \ifnum\parencount=0 \else \badparencount \fi
+ \ifnum\brackcount=0 \else \badbrackcount \fi
+}
+% these should not use \errmessage; the glibc manual, at least, actually
+% has such constructs (when documenting function pointers).
+\def\badparencount{%
+ \message{Warning: unbalanced parentheses in @def...}%
+ \global\parencount=0
+}
+\def\badbrackcount{%
+ \message{Warning: unbalanced square brackets in @def...}%
+ \global\brackcount=0
+}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\thisisundefined
+ \newwrite\macscribble
+ \def\scantokens#1{%
+ \toks0={#1}%
+ \immediate\openout\macscribble=\jobname.tmp
+ \immediate\write\macscribble{\the\toks0}%
+ \immediate\closeout\macscribble
+ \input \jobname.tmp
+ }
+\fi
+
+\let\aftermacroxxx\relax
+\def\aftermacro{\aftermacroxxx}
+
+% alias because \c means cedilla in @tex or @math
+\let\texinfoc=\c
+
+% Used at the time of macro expansion.
+% Argument is macro body with arguments substituted
+\def\scanmacro#1{%
+ \newlinechar`\^^M
+ \def\xprocessmacroarg{\eatspaces}%
+ %
+ % Process the macro body under the current catcode regime.
+ \scantokens{#1\texinfoc}\aftermacro%
+ %
+ % The \c is to remove the \newlinechar added by \scantokens, and
+ % can be noticed by \parsearg.
+ % The \aftermacro allows a \comment at the end of the macro definition
+ % to duplicate itself past the final \newlinechar added by \scantokens:
+ % this is used in the definition of \group to comment out a newline. We
+ % don't do the same for \c to support Texinfo files with macros that ended
+ % with a @c, which should no longer be necessary.
+ % We avoid surrounding the call to \scantokens with \bgroup and \egroup
+ % to allow macros to open or close groups themselves.
+}
+
+% Used for copying and captions
+\def\scanexp#1{%
+ \bgroup
+ % Undo catcode changes of \startcontents and \printindex
+ % When called from @insertcopying or (short)caption, we need active
+ % backslash to get it printed correctly.
+ % FIXME: This may not be needed.
+ %\catcode`\@=0 \catcode`\\=\active \escapechar=`\@
+ \edef\temp{\noexpand\scanmacro{#1}}%
+ \temp
+ \egroup
+}
+
+\newcount\paramno % Count of parameters
+\newtoks\macname % Macro name
+\newif\ifrecursive % Is it recursive?
+
+% List of all defined macros in the form
+% \definedummyword\macro1\definedummyword\macro2...
+% Currently is also contains all @aliases; the list can be split
+% if there is a need.
+\def\macrolist{}
+
+% Add the macro to \macrolist
+\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname}
+\def\addtomacrolistxxx#1{%
+ \toks0 = \expandafter{\macrolist\definedummyword#1}%
+ \xdef\macrolist{\the\toks0}%
+}
+
+% Utility routines.
+% This does \let #1 = #2, with \csnames; that is,
+% \let \csname#1\endcsname = \csname#2\endcsname
+% (except of course we have to play expansion games).
+%
+\def\cslet#1#2{%
+ \expandafter\let
+ \csname#1\expandafter\endcsname
+ \csname#2\endcsname
+}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=\other \catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \
+% to recognize macro arguments; this is the job of \mbodybackslash.
+%
+% Non-ASCII encodings make 8-bit characters active, so un-activate
+% them to avoid their expansion. Must do this non-globally, to
+% confine the change to the current group.
+%
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+%
+\def\scanctxt{% used as subroutine
+ \catcode`\"=\other
+ \catcode`\+=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\^=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\~=\other
+ \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi
+}
+
+\def\scanargctxt{% used for copying and captions, not macros.
+ \scanctxt
+ \catcode`\@=\other
+ \catcode`\\=\other
+ \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{% used for @macro definitions
+ \scanctxt
+ \catcode`\ =\other
+ \catcode`\@=\other
+ \catcode`\{=\other
+ \catcode`\}=\other
+ \catcode`\^^M=\other
+ \usembodybackslash
+}
+
+% Used when scanning braced macro arguments. Note, however, that catcode
+% changes here are ineffectual if the macro invocation was nested inside
+% an argument to another Texinfo command.
+\def\macroargctxt{%
+ \scanctxt
+ \catcode`\ =\active
+ \catcode`\^^M=\other
+ \catcode`\\=\active
+}
+
+\def\macrolineargctxt{% used for whole-line arguments without braces
+ \scanctxt
+ \catcode`\{=\other
+ \catcode`\}=\other
+}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+%
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\margbackslash#1{\char`\#1 }
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+ \getargs{#1}% now \macname is the macname and \argl the arglist
+ \ifx\argl\empty % no arguments
+ \paramno=0\relax
+ \else
+ \expandafter\parsemargdef \argl;%
+ \if\paramno>256\relax
+ \ifx\eTeXversion\thisisundefined
+ \errhelp = \EMsimple
+ \errmessage{You need eTeX to compile a file with macros with more than 256 arguments}
+ \fi
+ \fi
+ \fi
+ \if1\csname ismacro.\the\macname\endcsname
+ \message{Warning: redefining \the\macname}%
+ \else
+ \expandafter\ifx\csname \the\macname\endcsname \relax
+ \else \errmessage{Macro name \the\macname\space already defined}\fi
+ \global\cslet{macsave.\the\macname}{\the\macname}%
+ \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+ \addtomacrolist{\the\macname}%
+ \fi
+ \begingroup \macrobodyctxt
+ \ifrecursive \expandafter\parsermacbody
+ \else \expandafter\parsemacbody
+ \fi}
+
+\parseargdef\unmacro{%
+ \if1\csname ismacro.#1\endcsname
+ \global\cslet{#1}{macsave.#1}%
+ \global\expandafter\let \csname ismacro.#1\endcsname=0%
+ % Remove the macro name from \macrolist:
+ \begingroup
+ \expandafter\let\csname#1\endcsname \relax
+ \let\definedummyword\unmacrodo
+ \xdef\macrolist{\macrolist}%
+ \endgroup
+ \else
+ \errmessage{Macro #1 not defined}%
+ \fi
+}
+
+% Called by \do from \dounmacro on each macro. The idea is to omit any
+% macro definitions that have been changed to \relax.
+%
+\def\unmacrodo#1{%
+ \ifx #1\relax
+ % remove this
+ \else
+ \noexpand\definedummyword \noexpand#1%
+ \fi
+}
+
+% \getargs -- Parse the arguments to a @macro line. Set \macname to
+% the name of the macro, and \argl to the braced argument list.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname#1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+% This made use of the feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+
+% Parse the optional {params} list to @macro or @rmacro.
+% Set \paramno to the number of arguments,
+% and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a
+% three-param macro.) Define \macarg.BLAH for each BLAH in the params
+% list to some hook where the argument is to be expanded. If there are
+% less than 10 arguments that hook is to be replaced by ##N where N
+% is the position in that list, that is to say the macro arguments are to be
+% defined `a la TeX in the macro body.
+%
+% That gets used by \mbodybackslash (above).
+%
+% If there are 10 or more arguments, a different technique is used: see
+% \parsemmanyargdef.
+%
+\def\parsemargdef#1;{%
+ \paramno=0\def\paramlist{}%
+ \let\hash\relax
+ % \hash is redefined to `#' later to get it into definitions
+ \let\processmacroarg\relax
+ \parsemargdefxxx#1,;,%
+ \ifnum\paramno<10\relax\else
+ \paramno0\relax
+ \parsemmanyargdef@@#1,;,% 10 or more arguments
+ \fi
+}
+\def\parsemargdefxxx#1,{%
+ \if#1;\let\next=\relax
+ \else \let\next=\parsemargdefxxx
+ \advance\paramno by 1
+ \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+ {\processmacroarg{\hash\the\paramno}}%
+ \edef\paramlist{\paramlist\hash\the\paramno,}%
+ \fi\next}
+
+% \parsemacbody, \parsermacbody
+%
+% Read recursive and nonrecursive macro bodies. (They're different since
+% rec and nonrec macros end differently.)
+%
+% We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro
+% body to be transformed.
+% Set \macrobody to the body of the macro, and call \defmacro.
+%
+{\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+{\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+
+% Make @ a letter, so that we can make private-to-Texinfo macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
+%%%%%%%%%%%%%% Code for > 10 arguments only %%%%%%%%%%%%%%%%%%
+
+% If there are 10 or more arguments, a different technique is used, where the
+% hook remains in the body, and when macro is to be expanded the body is
+% processed again to replace the arguments.
+%
+% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the
+% argument N value and then \edef the body (nothing else will expand because of
+% the catcode regime under which the body was input).
+%
+% If you compile with TeX (not eTeX), and you have macros with 10 or more
+% arguments, no macro can have more than 256 arguments (else error).
+%
+% In case that there are 10 or more arguments we parse again the arguments
+% list to set new definitions for the \macarg.BLAH macros corresponding to
+% each BLAH argument. It was anyhow needed to parse already once this list
+% in order to count the arguments, and as macros with at most 9 arguments
+% are by far more frequent than macro with 10 or more arguments, defining
+% twice the \macarg.BLAH macros does not cost too much processing power.
+\def\parsemmanyargdef@@#1,{%
+ \if#1;\let\next=\relax
+ \else
+ \let\next=\parsemmanyargdef@@
+ \edef\tempb{\eatspaces{#1}}%
+ \expandafter\def\expandafter\tempa
+ \expandafter{\csname macarg.\tempb\endcsname}%
+ % Note that we need some extra \noexpand\noexpand, this is because we
+ % don't want \the to be expanded in the \parsermacbody as it uses an
+ % \xdef .
+ \expandafter\edef\tempa
+ {\noexpand\noexpand\noexpand\the\toks\the\paramno}%
+ \advance\paramno by 1\relax
+ \fi\next}
+
+
+\let\endargs@\relax
+\let\nil@\relax
+\def\nilm@{\nil@}%
+\long\def\nillm@{\nil@}%
+
+% This macro is expanded during the Texinfo macro expansion, not during its
+% definition. It gets all the arguments' values and assigns them to macros
+% macarg.ARGNAME
+%
+% #1 is the macro name
+% #2 is the list of argument names
+% #3 is the list of argument values
+\def\getargvals@#1#2#3{%
+ \def\macargdeflist@{}%
+ \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion.
+ \def\paramlist{#2,\nil@}%
+ \def\macroname{#1}%
+ \begingroup
+ \macroargctxt
+ \def\argvaluelist{#3,\nil@}%
+ \def\@tempa{#3}%
+ \ifx\@tempa\empty
+ \setemptyargvalues@
+ \else
+ \getargvals@@
+ \fi
+}
+\def\getargvals@@{%
+ \ifx\paramlist\nilm@
+ % Some sanity check needed here that \argvaluelist is also empty.
+ \ifx\argvaluelist\nillm@
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Too many arguments in macro `\macroname'!}%
+ \fi
+ \let\next\macargexpandinbody@
+ \else
+ \ifx\argvaluelist\nillm@
+ % No more arguments values passed to macro. Set remaining named-arg
+ % macros to empty.
+ \let\next\setemptyargvalues@
+ \else
+ % pop current arg name into \@tempb
+ \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}%
+ \expandafter\@tempa\expandafter{\paramlist}%
+ % pop current argument value into \@tempc
+ \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}%
+ \expandafter\@tempa\expandafter{\argvaluelist}%
+ % Here \@tempb is the current arg name and \@tempc is the current arg value.
+ % First place the new argument macro definition into \@tempd
+ \expandafter\macname\expandafter{\@tempc}%
+ \expandafter\let\csname macarg.\@tempb\endcsname\relax
+ \expandafter\def\expandafter\@tempe\expandafter{%
+ \csname macarg.\@tempb\endcsname}%
+ \edef\@tempd{\long\def\@tempe{\the\macname}}%
+ \push@\@tempd\macargdeflist@
+ \let\next\getargvals@@
+ \fi
+ \fi
+ \next
+}
+
+\def\push@#1#2{%
+ \expandafter\expandafter\expandafter\def
+ \expandafter\expandafter\expandafter#2%
+ \expandafter\expandafter\expandafter{%
+ \expandafter#1#2}%
+}
+
+% Replace arguments by their values in the macro body, and place the result
+% in macro \@tempa.
+%
+\def\macvalstoargs@{%
+ % To do this we use the property that token registers that are \the'ed
+ % within an \edef expand only once. So we are going to place all argument
+ % values into respective token registers.
+ %
+ % First we save the token context, and initialize argument numbering.
+ \begingroup
+ \paramno0\relax
+ % Then, for each argument number #N, we place the corresponding argument
+ % value into a new token list register \toks#N
+ \expandafter\putargsintokens@\saveparamlist@,;,%
+ % Then, we expand the body so that argument are replaced by their
+ % values. The trick for values not to be expanded themselves is that they
+ % are within tokens and that tokens expand only once in an \edef .
+ \edef\@tempc{\csname mac.\macroname .body\endcsname}%
+ % Now we restore the token stack pointer to free the token list registers
+ % which we have used, but we make sure that expanded body is saved after
+ % group.
+ \expandafter
+ \endgroup
+ \expandafter\def\expandafter\@tempa\expandafter{\@tempc}%
+ }
+
+% Define the named-macro outside of this group and then close this group.
+%
+\def\macargexpandinbody@{%
+ \expandafter
+ \endgroup
+ \macargdeflist@
+ % First the replace in body the macro arguments by their values, the result
+ % is in \@tempa .
+ \macvalstoargs@
+ % Then we point at the \norecurse or \gobble (for recursive) macro value
+ % with \@tempb .
+ \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname
+ % Depending on whether it is recursive or not, we need some tailing
+ % \egroup .
+ \ifx\@tempb\gobble
+ \let\@tempc\relax
+ \else
+ \let\@tempc\egroup
+ \fi
+ % And now we do the real job:
+ \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}%
+ \@tempd
+}
+
+\def\putargsintokens@#1,{%
+ \if#1;\let\next\relax
+ \else
+ \let\next\putargsintokens@
+ % First we allocate the new token list register, and give it a temporary
+ % alias \@tempb .
+ \toksdef\@tempb\the\paramno
+ % Then we place the argument value into that token list register.
+ \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname
+ \expandafter\@tempb\expandafter{\@tempa}%
+ \advance\paramno by 1\relax
+ \fi
+ \next
+}
+
+% Trailing missing arguments are set to empty.
+%
+\def\setemptyargvalues@{%
+ \ifx\paramlist\nilm@
+ \let\next\macargexpandinbody@
+ \else
+ \expandafter\setemptyargvaluesparser@\paramlist\endargs@
+ \let\next\setemptyargvalues@
+ \fi
+ \next
+}
+
+\def\setemptyargvaluesparser@#1,#2\endargs@{%
+ \expandafter\def\expandafter\@tempa\expandafter{%
+ \expandafter\def\csname macarg.#1\endcsname{}}%
+ \push@\@tempa\macargdeflist@
+ \def\paramlist{#2}%
+}
+
+% #1 is the element target macro
+% #2 is the list macro
+% #3,#4\endargs@ is the list value
+\def\pop@#1#2#3,#4\endargs@{%
+ \def#1{#3}%
+ \def#2{#4}%
+}
+\long\def\longpop@#1#2#3,#4\endargs@{%
+ \long\def#1{#3}%
+ \long\def#2{#4}%
+}
+
+
+%%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%%
+
+
+
+% Remove following spaces at the expansion stage.
+% This works because spaces are discarded before each argument when TeX is
+% getting the arguments for a macro.
+% This must not be immediately followed by a }.
+\long\def\gobblespaces#1{#1}
+
+% This defines a Texinfo @macro or @rmacro, called by \parsemacbody.
+% \macrobody has the body of the macro in it, with placeholders for
+% its parameters, looking like "\processmacroarg{\hash 1}".
+% \paramno is the number of parameters
+% \paramlist is a TeX parameter text, e.g. "#1,#2,#3,"
+% There are eight cases: recursive and nonrecursive macros of zero, one,
+% up to nine, and many arguments.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in: @include reads the file inside a group.
+%
+\def\defmacro{%
+ \let\hash=##% convert placeholders to macro parameter chars
+ \ifnum\paramno=1
+ \def\processmacroarg{\gobblespaces}%
+ % This removes the pair of braces around the argument. We don't
+ % use \eatspaces, because this can cause ends of lines to be lost
+ % when the argument to \eatspaces is read, leading to line-based
+ % commands like "@itemize" not being read correctly.
+ \else
+ \def\processmacroarg{\xprocessmacroarg}%
+ \let\xprocessmacroarg\relax
+ \fi
+ \ifrecursive %%%%%%%%%%%%%% Recursive %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\scanmacro{\macrobody}}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname @@@@\endcsname{%
+ \noexpand\gobblespaces##1\empty}%
+ % The \empty is for \gobblespaces in case #1 is empty
+ }%
+ \expandafter\xdef\csname\the\macname @@@@\endcsname##1{%
+ \egroup\noexpand\scanmacro{\macrobody}}%
+ \else
+ \ifnum\paramno<10\relax % at most 9
+ % See non-recursive section below for comments
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup
+ \noexpand\expandafter
+ \noexpand\macroargctxt
+ \noexpand\expandafter
+ \expandafter\noexpand\csname\the\macname @@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@\endcsname##1{%
+ \noexpand\passargtomacro
+ \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
+ \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname @@@@\endcsname\paramlist{%
+ \egroup\noexpand\scanmacro{\macrobody}}%
+ \else % 10 or more
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\getargvals@{\the\macname}{\argl}%
+ }%
+ \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
+ \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
+ \fi
+ \fi
+ \else %%%%%%%%%%%%%%%%%%%%%% Non-recursive %%%%%%%%%%%%%%%%%%%%%%%%%%
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\scanmacro{\macrobody}}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname @@@@\endcsname{%
+ \noexpand\gobblespaces##1\empty}%
+ % The \empty is for \gobblespaces in case #1 is empty
+ }%
+ \expandafter\xdef\csname\the\macname @@@@\endcsname##1{%
+ \egroup
+ \noexpand\scanmacro{\macrobody}%
+ }%
+ \else % at most 9
+ \ifnum\paramno<10\relax
+ % @MACNAME sets the context for reading the macro argument
+ % @MACNAME@@ gets the argument, processes backslashes and appends a
+ % comma.
+ % @MACNAME@@@ removes braces surrounding the argument list.
+ % @MACNAME@@@@ scans the macro body with arguments substituted.
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup
+ \noexpand\expandafter % This \expandafter skip any spaces after the
+ \noexpand\macroargctxt % macro before we change the catcode of space.
+ \noexpand\expandafter
+ \expandafter\noexpand\csname\the\macname @@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@\endcsname##1{%
+ \noexpand\passargtomacro
+ \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
+ \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname @@@@\endcsname\paramlist{%
+ \egroup\noexpand\scanmacro{\macrobody}}%
+ \else % 10 or more:
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\getargvals@{\the\macname}{\argl}%
+ }%
+ \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
+ \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse
+ \fi
+ \fi
+ \fi}
+
+\catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+{\catcode`\@=0 \catcode`\\=13 % We need to manipulate \ so use @ as escape
+@catcode`@_=11 % private names
+@catcode`@!=11 % used as argument separator
+
+% \passargtomacro#1#2 -
+% Call #1 with a list of tokens #2, with any doubled backslashes in #2
+% compressed to one.
+%
+% This implementation works by expansion, and not execution (so we cannot use
+% \def or similar). This reduces the risk of this failing in contexts where
+% complete expansion is done with no execution (for example, in writing out to
+% an auxiliary file for an index entry).
+%
+% State is kept in the input stream: the argument passed to
+% @look_ahead, @gobble_and_check_finish and @add_segment is
+%
+% THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN (... rest of input)
+%
+% where:
+% THE_MACRO - name of the macro we want to call
+% ARG_RESULT - argument list we build to pass to that macro
+% PENDING_BS - either a backslash or nothing
+% NEXT_TOKEN - used to look ahead in the input stream to see what's coming next
+
+@gdef@passargtomacro#1#2{%
+ @add_segment #1!{}@relax#2\@_finish\%
+}
+@gdef@_finish{@_finishx} @global@let@_finishx@relax
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 used to look ahead
+%
+% If the next token is not a backslash, process the rest of the argument;
+% otherwise, remove the next token.
+@gdef@look_ahead#1!#2#3#4{%
+ @ifx#4\%
+ @expandafter@gobble_and_check_finish
+ @else
+ @expandafter@add_segment
+ @fi#1!{#2}#4#4%
+}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 should be a backslash, which is gobbled.
+% #5 looks ahead
+%
+% Double backslash found. Add a single backslash, and look ahead.
+@gdef@gobble_and_check_finish#1!#2#3#4#5{%
+ @add_segment#1\!{}#5#5%
+}
+
+@gdef@is_fi{@fi}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 is input stream until next backslash
+%
+% Input stream is either at the start of the argument, or just after a
+% backslash sequence, either a lone backslash, or a doubled backslash.
+% NEXT_TOKEN contains the first token in the input stream: if it is \finish,
+% finish; otherwise, append to ARG_RESULT the segment of the argument up until
+% the next backslash. PENDING_BACKSLASH contains a backslash to represent
+% a backslash just before the start of the input stream that has not been
+% added to ARG_RESULT.
+@gdef@add_segment#1!#2#3#4\{%
+@ifx#3@_finish
+ @call_the_macro#1!%
+@else
+ % append the pending backslash to the result, followed by the next segment
+ @expandafter@is_fi@look_ahead#1#2#4!{\}@fi
+ % this @fi is discarded by @look_ahead.
+ % we can't get rid of it with \expandafter because we don't know how
+ % long #4 is.
+}
+
+% #1 - THE_MACRO
+% #2 - ARG_RESULT
+% #3 discards the res of the conditional in @add_segment, and @is_fi ends the
+% conditional.
+@gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}}
+
+}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% \braceorline MAC is used for a one-argument macro MAC. It checks
+% whether the next non-whitespace character is a {. It sets the context
+% for reading the argument (slightly different in the two cases). Then,
+% to read the argument, in the whole-line case, it then calls the regular
+% \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC.
+%
+\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+ \ifx\nchar\bgroup
+ \macroargctxt
+ \expandafter\passargtomacro
+ \else
+ \macrolineargctxt\expandafter\parsearg
+ \fi \macnamexxx}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign. Make them active and then expand them all to nothing.
+%
+\def\alias{\parseargusing\obeyspaces\aliasxxx}
+\def\aliasxxx #1{\aliasyyy#1\relax}
+\def\aliasyyy #1=#2\relax{%
+ {%
+ \expandafter\let\obeyedspace=\empty
+ \addtomacrolist{#1}%
+ \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}%
+ }%
+ \next
+}
+
+
+\message{cross references,}
+
+\newwrite\auxfile
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{%
+ \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+ node \samp{\ignorespaces#1{}}}
+
+% @node's only job in TeX is to define \lastnode, which is used in
+% cross-references. The @node line might or might not have commas, and
+% might or might not have spaces before the first comma, like:
+% @node foo , bar , ...
+% We don't want such trailing spaces in the node name.
+%
+\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse}
+%
+% also remove a trailing comma, in case of something like this:
+% @node Help-Cross, , , Cross-refs
+\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse}
+\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}}
+
+\let\nwnode=\node
+\let\lastnode=\empty
+
+% Write a cross-reference definition for the current node. #1 is the
+% type (Ynumbered, Yappendix, Ynothing).
+%
+\def\donoderef#1{%
+ \ifx\lastnode\empty\else
+ \setref{\lastnode}{#1}%
+ \global\let\lastnode=\empty
+ \fi
+}
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\newcount\savesfregister
+%
+\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
+\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
+\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
+% anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name taken from \lastsection,
+% or the anchor name.
+% 2) NAME-snt - section number and type, passed as the SNT arg, or
+% empty for anchors.
+% 3) NAME-pg - the page number.
+%
+% This is called from \donoderef, \anchor, and \dofloat. In the case of
+% floats, there is an additional part, which is not written here:
+% 4) NAME-lof - the text as it should appear in a @listoffloats.
+%
+\def\setref#1#2{%
+ \pdfmkdest{#1}%
+ \iflinks
+ {%
+ \requireauxfile
+ \atdummies % preserve commands, but don't expand them
+ \edef\writexrdef##1##2{%
+ \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+ ##1}{##2}}% these are parameters of \writexrdef
+ }%
+ \toks0 = \expandafter{\lastsection}%
+ \immediate \writexrdef{title}{\the\toks0 }%
+ \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+ \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout
+ }%
+ \fi
+}
+
+% @xrefautosectiontitle on|off says whether @section(ing) names are used
+% automatically in xrefs, if the third arg is not explicitly specified.
+% This was provided as a "secret" @set xref-automatic-section-title
+% variable, now it's official.
+%
+\parseargdef\xrefautomaticsectiontitle{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETxref-automatic-section-title\endcsname
+ = \empty
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETxref-automatic-section-title\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @xrefautomaticsectiontitle value `\temp',
+ must be on|off}%
+ \fi\fi
+}
+
+%
+% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual. All but the node name can be omitted.
+%
+\def\pxref{\putwordsee{} \xrefXX}
+\def\xref{\putwordSee{} \xrefXX}
+\def\ref{\xrefXX}
+
+\def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX}
+\def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]}
+%
+\newbox\toprefbox
+\newbox\printedrefnamebox
+\newbox\infofilenamebox
+\newbox\printedmanualbox
+%
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+ \unsepspaces
+ %
+ % Get args without leading/trailing spaces.
+ \def\printedrefname{\ignorespaces #3}%
+ \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}%
+ %
+ \def\infofilename{\ignorespaces #4}%
+ \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
+ %
+ \def\printedmanual{\ignorespaces #5}%
+ \setbox\printedmanualbox = \hbox{\printedmanual\unskip}%
+ %
+ % If the printed reference name (arg #3) was not explicitly given in
+ % the @xref, figure out what we want to use.
+ \ifdim \wd\printedrefnamebox = 0pt
+ % No printed node name was explicitly given.
+ \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax
+ % Not auto section-title: use node name inside the square brackets.
+ \def\printedrefname{\ignorespaces #1}%
+ \else
+ % Auto section-title: use chapter/section title inside
+ % the square brackets if we have it.
+ \ifdim \wd\printedmanualbox > 0pt
+ % It is in another manual, so we don't have it; use node name.
+ \def\printedrefname{\ignorespaces #1}%
+ \else
+ \ifhavexrefs
+ % We (should) know the real title if we have the xref values.
+ \def\printedrefname{\refx{#1-title}{}}%
+ \else
+ % Otherwise just copy the Info node name.
+ \def\printedrefname{\ignorespaces #1}%
+ \fi%
+ \fi
+ \fi
+ \fi
+ %
+ % Make link in pdf output.
+ \ifpdf
+ {\indexnofonts
+ \turnoffactive
+ \makevalueexpandable
+ % This expands tokens, so do it after making catcode changes, so _
+ % etc. don't get their TeX definitions. This ignores all spaces in
+ % #4, including (wrongly) those in the middle of the filename.
+ \getfilename{#4}%
+ %
+ % This (wrongly) does not take account of leading or trailing
+ % spaces in #1, which should be ignored.
+ \edef\pdfxrefdest{#1}%
+ \ifx\pdfxrefdest\empty
+ \def\pdfxrefdest{Top}% no empty targets
+ \else
+ \txiescapepdf\pdfxrefdest % escape PDF special chars
+ \fi
+ %
+ \leavevmode
+ \startlink attr{/Border [0 0 0]}%
+ \ifnum\filenamelength>0
+ goto file{\the\filename.pdf} name{\pdfxrefdest}%
+ \else
+ goto name{\pdfmkpgn{\pdfxrefdest}}%
+ \fi
+ }%
+ \setcolor{\linkcolor}%
+ \fi
+ {%
+ % Have to otherify everything special to allow the \csname to
+ % include an _ in the xref name, etc.
+ \indexnofonts
+ \turnoffactive
+ \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+ \csname XR#1-title\endcsname
+ }%
+ %
+ % Float references are printed completely differently: "Figure 1.2"
+ % instead of "[somenode], p.3". \iffloat distinguishes them by
+ % \Xthisreftitle being set to a magic string.
+ \iffloat\Xthisreftitle
+ % If the user specified the print name (third arg) to the ref,
+ % print it instead of our usual "Figure 1.2".
+ \ifdim\wd\printedrefnamebox = 0pt
+ \refx{#1-snt}{}%
+ \else
+ \printedrefname
+ \fi
+ %
+ % If the user also gave the printed manual name (fifth arg), append
+ % "in MANUALNAME".
+ \ifdim \wd\printedmanualbox > 0pt
+ \space \putwordin{} \cite{\printedmanual}%
+ \fi
+ \else
+ % node/anchor (non-float) references.
+ %
+ % If we use \unhbox to print the node names, TeX does not insert
+ % empty discretionaries after hyphens, which means that it will not
+ % find a line break at a hyphen in a node names. Since some manuals
+ % are best written with fairly long node names, containing hyphens,
+ % this is a loss. Therefore, we give the text of the node name
+ % again, so it is as if TeX is seeing it for the first time.
+ %
+ \ifdim \wd\printedmanualbox > 0pt
+ % Cross-manual reference with a printed manual name.
+ %
+ \crossmanualxref{\cite{\printedmanual\unskip}}%
+ %
+ \else\ifdim \wd\infofilenamebox > 0pt
+ % Cross-manual reference with only an info filename (arg 4), no
+ % printed manual name (arg 5). This is essentially the same as
+ % the case above; we output the filename, since we have nothing else.
+ %
+ \crossmanualxref{\code{\infofilename\unskip}}%
+ %
+ \else
+ % Reference within this manual.
+ %
+ % _ (for example) has to be the character _ for the purposes of the
+ % control sequence corresponding to the node, but it has to expand
+ % into the usual \leavevmode...\vrule stuff for purposes of
+ % printing. So we \turnoffactive for the \refx-snt, back on for the
+ % printing, back off for the \refx-pg.
+ {\turnoffactive
+ % Only output a following space if the -snt ref is nonempty; for
+ % @unnumbered and @anchor, it won't be.
+ \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+ \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+ }%
+ % output the `[mynode]' via the macro below so it can be overridden.
+ \xrefprintnodename\printedrefname
+ %
+ % But we always want a comma and a space:
+ ,\space
+ %
+ % output the `page 3'.
+ \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+ % Add a , if xref followed by a space
+ \if\space\noexpand\tokenafterxref ,%
+ \else\ifx\ \tokenafterxref ,% @TAB
+ \else\ifx\*\tokenafterxref ,% @*
+ \else\ifx\ \tokenafterxref ,% @SPACE
+ \else\ifx\
+ \tokenafterxref ,% @NL
+ \else\ifx\tie\tokenafterxref ,% @tie
+ \fi\fi\fi\fi\fi\fi
+ \fi\fi
+ \fi
+ \endlink
+\endgroup}
+
+% Output a cross-manual xref to #1. Used just above (twice).
+%
+% Only include the text "Section ``foo'' in" if the foo is neither
+% missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply
+% "see The Foo Manual", the idea being to refer to the whole manual.
+%
+% But, this being TeX, we can't easily compare our node name against the
+% string "Top" while ignoring the possible spaces before and after in
+% the input. By adding the arbitrary 7sp below, we make it much less
+% likely that a real node name would have the same width as "Top" (e.g.,
+% in a monospaced font). Hopefully it will never happen in practice.
+%
+% For the same basic reason, we retypeset the "Top" at every
+% reference, since the current font is indeterminate.
+%
+\def\crossmanualxref#1{%
+ \setbox\toprefbox = \hbox{Top\kern7sp}%
+ \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}%
+ \ifdim \wd2 > 7sp % nonempty?
+ \ifdim \wd2 = \wd\toprefbox \else % same as Top?
+ \putwordSection{} ``\printedrefname'' \putwordin{}\space
+ \fi
+ \fi
+ #1%
+}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output. It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents. Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+ \ifnum\secno=0
+ \putwordChapter@tie \the\chapno
+ \else \ifnum\subsecno=0
+ \putwordSection@tie \the\chapno.\the\secno
+ \else \ifnum\subsubsecno=0
+ \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+ \else
+ \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+ \fi\fi\fi
+}
+\def\Yappendix{%
+ \ifnum\secno=0
+ \putwordAppendix@tie @char\the\appendixno{}%
+ \else \ifnum\subsecno=0
+ \putwordSection@tie @char\the\appendixno.\the\secno
+ \else \ifnum\subsubsecno=0
+ \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+ \else
+ \putwordSection@tie
+ @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+ \fi\fi\fi
+}
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+%
+\def\refx#1#2{%
+ \requireauxfile
+ {%
+ \indexnofonts
+ \otherbackslash
+ \expandafter\global\expandafter\let\expandafter\thisrefX
+ \csname XR#1\endcsname
+ }%
+ \ifx\thisrefX\relax
+ % If not defined, say something at least.
+ \angleleft un\-de\-fined\angleright
+ \iflinks
+ \ifhavexrefs
+ {\toks0 = {#1}% avoid expansion of possibly-complex value
+ \message{\linenumber Undefined cross reference `\the\toks0'.}}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \thisrefX
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file. Usually it's
+% just a \def (we prepend XR to the control sequence name to avoid
+% collisions). But if this is a float type, we have more work to do.
+%
+\def\xrdef#1#2{%
+ {% The node name might contain 8-bit characters, which in our current
+ % implementation are changed to commands like @'e. Don't let these
+ % mess up the control sequence name.
+ \indexnofonts
+ \turnoffactive
+ \xdef\safexrefname{#1}%
+ }%
+ %
+ \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref
+ %
+ % Was that xref control sequence that we just defined for a float?
+ \expandafter\iffloat\csname XR\safexrefname\endcsname
+ % it was a float, and we have the (safe) float type in \iffloattype.
+ \expandafter\let\expandafter\floatlist
+ \csname floatlist\iffloattype\endcsname
+ %
+ % Is this the first time we've seen this float type?
+ \expandafter\ifx\floatlist\relax
+ \toks0 = {\do}% yes, so just \do
+ \else
+ % had it before, so preserve previous elements in list.
+ \toks0 = \expandafter{\floatlist\do}%
+ \fi
+ %
+ % Remember this xref in the control sequence \floatlistFLOATTYPE,
+ % for later use in \listoffloats.
+ \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0
+ {\safexrefname}}%
+ \fi
+}
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate at the beginning of the file.
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% Used when writing to the aux file, or when using data from it.
+\def\requireauxfile{%
+ \iflinks
+ \tryauxfile
+ % Open the new aux file. TeX will close it automatically at exit.
+ \immediate\openout\auxfile=\jobname.aux
+ \fi
+ \global\let\requireauxfile=\relax % Only do this once.
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+%
+\def\tryauxfile{%
+ \openin 1 \jobname.aux
+ \ifeof 1 \else
+ \readdatafile{aux}%
+ \global\havexrefstrue
+ \fi
+ \closein 1
+}
+
+\def\setupdatafile{%
+ \catcode`\^^@=\other
+ \catcode`\^^A=\other
+ \catcode`\^^B=\other
+ \catcode`\^^C=\other
+ \catcode`\^^D=\other
+ \catcode`\^^E=\other
+ \catcode`\^^F=\other
+ \catcode`\^^G=\other
+ \catcode`\^^H=\other
+ \catcode`\^^K=\other
+ \catcode`\^^L=\other
+ \catcode`\^^N=\other
+ \catcode`\^^P=\other
+ \catcode`\^^Q=\other
+ \catcode`\^^R=\other
+ \catcode`\^^S=\other
+ \catcode`\^^T=\other
+ \catcode`\^^U=\other
+ \catcode`\^^V=\other
+ \catcode`\^^W=\other
+ \catcode`\^^X=\other
+ \catcode`\^^Z=\other
+ \catcode`\^^[=\other
+ \catcode`\^^\=\other
+ \catcode`\^^]=\other
+ \catcode`\^^^=\other
+ \catcode`\^^_=\other
+ % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc.
+ % in xref tags, i.e., node names. But since ^^e4 notation isn't
+ % supported in the main text, it doesn't seem desirable. Furthermore,
+ % that is not enough: for node names that actually contain a ^
+ % character, we would end up writing a line like this: 'xrdef {'hat
+ % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+ % argument, and \hat is not an expandable control sequence. It could
+ % all be worked out, but why? Either we support ^^ or we don't.
+ %
+ % The other change necessary for this was to define \auxhat:
+ % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+ % and then to call \auxhat in \setq.
+ %
+ \catcode`\^=\other
+ %
+ % Special characters. Should be turned off anyway, but...
+ \catcode`\~=\other
+ \catcode`\[=\other
+ \catcode`\]=\other
+ \catcode`\"=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\$=\other
+ \catcode`\#=\other
+ \catcode`\&=\other
+ \catcode`\%=\other
+ \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+ %
+ % This is to support \ in node names and titles, since the \
+ % characters end up in a \csname. It's easier than
+ % leaving it active and making its active definition an actual \
+ % character. What I don't understand is why it works in the *value*
+ % of the xrdef. Seems like it should be a catcode12 \, and that
+ % should not typeset properly. But it works, so I'm moving on for
+ % now. --karl, 15jan04.
+ \catcode`\\=\other
+ %
+ % Make the characters 128-255 be printing characters.
+ {\setnonasciicharscatcodenonglobal\other}%
+ %
+ % @ is our escape character in .aux files, and we need braces.
+ \catcode`\{=1
+ \catcode`\}=2
+ \catcode`\@=0
+}
+
+\def\readdatafile#1{%
+\begingroup
+ \setupdatafile
+ \input\jobname.#1
+\endgroup}
+
+
+\message{insertions,}
+% including footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for Info output only.
+\let\footnotestyle=\comment
+
+{\catcode `\@=11
+%
+% Auto-number footnotes. Otherwise like plain.
+\gdef\footnote{%
+ \global\advance\footnoteno by \@ne
+ \edef\thisfootno{$^{\the\footnoteno}$}%
+ %
+ % In case the footnote comes at the end of a sentence, preserve the
+ % extra spacing after we do the footnote number.
+ \let\@sf\empty
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi
+ %
+ % Remove inadvertent blank space before typesetting the footnote number.
+ \unskip
+ \thisfootno\@sf
+ \dofootnote
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter. Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset (and anything else that uses
+% \parseargline) fails inside footnotes because the tokens are fixed when
+% the footnote is read. --karl, 16nov96.
+%
+\gdef\dofootnote{%
+ \insert\footins\bgroup
+ %
+ % Nested footnotes are not supported in TeX, that would take a lot
+ % more work. (\startsavinginserts does not suffice.)
+ \let\footnote=\errfootnotenest
+ %
+ % We want to typeset this text as a normal paragraph, even if the
+ % footnote reference occurs in (for example) a display environment.
+ % So reset some parameters.
+ \hsize=\pagewidth
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox
+ \floatingpenalty\@MM
+ \leftskip\z@skip
+ \rightskip\z@skip
+ \spaceskip\z@skip
+ \xspaceskip\z@skip
+ \parindent\defaultparindent
+ %
+ \smallfonts \rm
+ %
+ % Because we use hanging indentation in footnotes, a @noindent appears
+ % to exdent this text, so make it be a no-op. makeinfo does not use
+ % hanging indentation so @noindent can still be needed within footnote
+ % text after an @example or the like (not that this is good style).
+ \let\noindent = \relax
+ %
+ % Hang the footnote text off the number. Use \everypar in case the
+ % footnote extends for more than one paragraph.
+ \everypar = {\hang}%
+ \textindent{\thisfootno}%
+ %
+ % Don't crash into the line above the footnote text. Since this
+ % expands into a box, it must come within the paragraph, lest it
+ % provide a place where TeX can split the footnote.
+ \footstrut
+ %
+ % Invoke rest of plain TeX footnote routine.
+ \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+\def\errfootnotenest{%
+ \errhelp=\EMsimple
+ \errmessage{Nested footnotes not supported in texinfo.tex,
+ even though they work in makeinfo; sorry}
+}
+
+\def\errfootnoteheading{%
+ \errhelp=\EMsimple
+ \errmessage{Footnotes in chapters, sections, etc., are not supported}
+}
+
+% In case a @footnote appears in a vbox, save the footnote text and create
+% the real \insert just after the vbox finished. Otherwise, the insertion
+% would be lost.
+% Similarly, if a @footnote appears inside an alignment, save the footnote
+% text to a box and make the \insert when a row of the table is finished.
+% And the same can be done for other insert classes. --kasal, 16nov03.
+%
+% Replace the \insert primitive by a cheating macro.
+% Deeper inside, just make sure that the saved insertions are not spilled
+% out prematurely.
+%
+\def\startsavinginserts{%
+ \ifx \insert\ptexinsert
+ \let\insert\saveinsert
+ \else
+ \let\checkinserts\relax
+ \fi
+}
+
+% This \insert replacement works for both \insert\footins{foo} and
+% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}.
+%
+\def\saveinsert#1{%
+ \edef\next{\noexpand\savetobox \makeSAVEname#1}%
+ \afterassignment\next
+ % swallow the left brace
+ \let\temp =
+}
+\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}}
+\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1}
+
+\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi}
+
+\def\placesaveins#1{%
+ \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname
+ {\box#1}%
+}
+
+% eat @SAVE -- beware, all of them have catcode \other:
+{
+ \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-)
+ \gdef\gobblesave @SAVE{}
+}
+
+% initialization:
+\def\newsaveins #1{%
+ \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}%
+ \next
+}
+\def\newsaveinsX #1{%
+ \csname newbox\endcsname #1%
+ \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts
+ \checksaveins #1}%
+}
+
+% initialize:
+\let\checkinserts\empty
+\newsaveins\footins
+\newsaveins\margin
+
+
+% @image. We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front. If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+ % Do not bother showing banner with epsf.tex v2.7k (available in
+ % doc/epsf.tex and on ctan).
+ \def\epsfannounce{\toks0 = }%
+ \input epsf.tex
+\fi
+\closein 1
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+ work. It is also included in the Texinfo distribution, or you can get
+ it from ftp://tug.org/tex/epsf.tex.}
+%
+\def\image#1{%
+ \ifx\epsfbox\thisisundefined
+ \ifwarnednoepsf \else
+ \errhelp = \noepsfhelp
+ \errmessage{epsf.tex not found, images will be ignored}%
+ \global\warnednoepsftrue
+ \fi
+ \else
+ \imagexxx #1,,,,,\finish
+ \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+ \catcode`\^^M = 5 % in case we're inside an example
+ \normalturnoffactive % allow _ et al. in names
+ \def\xprocessmacroarg{\eatspaces}% in case we are being used via a macro
+ % If the image is by itself, center it.
+ \ifvmode
+ \imagevmodetrue
+ \else \ifx\centersub\centerV
+ % for @center @image, we need a vbox so we can have our vertical space
+ \imagevmodetrue
+ \vbox\bgroup % vbox has better behavior than vtop herev
+ \fi\fi
+ %
+ \ifimagevmode
+ \nobreak\medskip
+ % Usually we'll have text after the image which will insert
+ % \parskip glue, so insert it here too to equalize the space
+ % above and below.
+ \nobreak\vskip\parskip
+ \nobreak
+ \fi
+ %
+ % Leave vertical mode so that indentation from an enclosing
+ % environment such as @quotation is respected.
+ % However, if we're at the top level, we don't want the
+ % normal paragraph indentation.
+ % On the other hand, if we are in the case of @center @image, we don't
+ % want to start a paragraph, which will create a hsize-width box and
+ % eradicate the centering.
+ \ifx\centersub\centerV\else \noindent \fi
+ %
+ % Output the image.
+ \ifpdf
+ % For pdfTeX and LuaTeX <= 0.80
+ \dopdfimage{#1}{#2}{#3}%
+ \else
+ \ifx\XeTeXrevision\thisisundefined
+ % For epsf.tex
+ % \epsfbox itself resets \epsf?size at each figure.
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+ \setbox0 = \hbox{\ignorespaces #3}%
+ \ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+ \epsfbox{#1.eps}%
+ \else
+ % For XeTeX
+ \doxeteximage{#1}{#2}{#3}%
+ \fi
+ \fi
+ %
+ \ifimagevmode
+ \medskip % space after a standalone image
+ \fi
+ \ifx\centersub\centerV \egroup \fi
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc. We don't actually implement floating yet, we always include the
+% float "here". But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc. Can't contain commas. If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label. Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored. It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+ \let\thiscaption=\empty
+ \let\thisshortcaption=\empty
+ %
+ % don't lose footnotes inside @float.
+ %
+ % BEWARE: when the floats start float, we have to issue warning whenever an
+ % insert appears inside a float which could possibly float. --kasal, 26may04
+ %
+ \startsavinginserts
+ %
+ % We can't be used inside a paragraph.
+ \par
+ %
+ \vtop\bgroup
+ \def\floattype{#1}%
+ \def\floatlabel{#2}%
+ \def\floatloc{#3}% we do nothing with this yet.
+ %
+ \ifx\floattype\empty
+ \let\safefloattype=\empty
+ \else
+ {%
+ % the floattype might have accents or other special characters,
+ % but we need to use it in a control sequence name.
+ \indexnofonts
+ \turnoffactive
+ \xdef\safefloattype{\floattype}%
+ }%
+ \fi
+ %
+ % If label is given but no type, we handle that as the empty type.
+ \ifx\floatlabel\empty \else
+ % We want each FLOATTYPE to be numbered separately (Figure 1,
+ % Table 1, Figure 2, ...). (And if no label, no number.)
+ %
+ \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+ \global\advance\floatno by 1
+ %
+ {%
+ % This magic value for \lastsection is output by \setref as the
+ % XREFLABEL-title value. \xrefX uses it to distinguish float
+ % labels (which have a completely different output format) from
+ % node and anchor labels. And \xrdef uses it to construct the
+ % lists of floats.
+ %
+ \edef\lastsection{\floatmagic=\safefloattype}%
+ \setref{\floatlabel}{Yfloat}%
+ }%
+ \fi
+ %
+ % start with \parskip glue, I guess.
+ \vskip\parskip
+ %
+ % Don't suppress indentation if a float happens to start a section.
+ \restorefirstparagraphindent
+}
+
+% we have these possibilities:
+% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap
+% @float Foo,lbl & no caption: Foo 1.1
+% @float Foo & @caption{Cap}: Foo: Cap
+% @float Foo & no caption: Foo
+% @float ,lbl & Caption{Cap}: 1.1: Cap
+% @float ,lbl & no caption: 1.1
+% @float & @caption{Cap}: Cap
+% @float & no caption:
+%
+\def\Efloat{%
+ \let\floatident = \empty
+ %
+ % In all cases, if we have a float type, it comes first.
+ \ifx\floattype\empty \else \def\floatident{\floattype}\fi
+ %
+ % If we have an xref label, the number comes next.
+ \ifx\floatlabel\empty \else
+ \ifx\floattype\empty \else % if also had float type, need tie first.
+ \appendtomacro\floatident{\tie}%
+ \fi
+ % the number.
+ \appendtomacro\floatident{\chaplevelprefix\the\floatno}%
+ \fi
+ %
+ % Start the printed caption with what we've constructed in
+ % \floatident, but keep it separate; we need \floatident again.
+ \let\captionline = \floatident
+ %
+ \ifx\thiscaption\empty \else
+ \ifx\floatident\empty \else
+ \appendtomacro\captionline{: }% had ident, so need a colon between
+ \fi
+ %
+ % caption text.
+ \appendtomacro\captionline{\scanexp\thiscaption}%
+ \fi
+ %
+ % If we have anything to print, print it, with space before.
+ % Eventually this needs to become an \insert.
+ \ifx\captionline\empty \else
+ \vskip.5\parskip
+ \captionline
+ %
+ % Space below caption.
+ \vskip\parskip
+ \fi
+ %
+ % If have an xref label, write the list of floats info. Do this
+ % after the caption, to avoid chance of it being a breakpoint.
+ \ifx\floatlabel\empty \else
+ % Write the text that goes in the lof to the aux file as
+ % \floatlabel-lof. Besides \floatident, we include the short
+ % caption if specified, else the full caption if specified, else nothing.
+ {%
+ \requireauxfile
+ \atdummies
+ %
+ % since we read the caption text in the macro world, where ^^M
+ % is turned into a normal character, we have to scan it back, so
+ % we don't write the literal three characters "^^M" into the aux file.
+ \scanexp{%
+ \xdef\noexpand\gtemp{%
+ \ifx\thisshortcaption\empty
+ \thiscaption
+ \else
+ \thisshortcaption
+ \fi
+ }%
+ }%
+ \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+ \ifx\gtemp\empty \else : \gtemp \fi}}%
+ }%
+ \fi
+ \egroup % end of \vtop
+ %
+ % place the captured inserts
+ %
+ % BEWARE: when the floats start floating, we have to issue warning
+ % whenever an insert appears inside a float which could possibly
+ % float. --kasal, 26may04
+ %
+ \checkinserts
+}
+
+% Append the tokens #2 to the definition of macro #1, not expanding either.
+%
+\def\appendtomacro#1#2{%
+ \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+
+% @caption, @shortcaption
+%
+\def\caption{\docaption\thiscaption}
+\def\shortcaption{\docaption\thisshortcaption}
+\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\defcaption#1#2{\egroup \def#1{#2}}
+
+% The parameter is the control sequence identifying the counter we are
+% going to use. Create it if it doesn't exist and assign it to \floatno.
+\def\getfloatno#1{%
+ \ifx#1\relax
+ % Haven't seen this figure type before.
+ \csname newcount\endcsname #1%
+ %
+ % Remember to reset this floatno at the next chap.
+ \expandafter\gdef\expandafter\resetallfloatnos
+ \expandafter{\resetallfloatnos #1=0 }%
+ \fi
+ \let\floatno#1%
+}
+
+% \setref calls this to get the XREFLABEL-snt value. We want an @xref
+% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we
+% first read the @float command.
+%
+\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}%
+
+% Magic string used for the XREFLABEL-title value, so \xrefX can
+% distinguish floats from other xref types.
+\def\floatmagic{!!float!!}
+
+% #1 is the control sequence we are passed; we expand into a conditional
+% which is true if #1 represents a float ref. That is, the magic
+% \lastsection value which we \setref above.
+%
+\def\iffloat#1{\expandafter\doiffloat#1==\finish}
+%
+% #1 is (maybe) the \floatmagic string. If so, #2 will be the
+% (safe) float type for this float. We set \iffloattype to #2.
+%
+\def\doiffloat#1=#2=#3\finish{%
+ \def\temp{#1}%
+ \def\iffloattype{#2}%
+ \ifx\temp\floatmagic
+}
+
+% @listoffloats FLOATTYPE - print a list of floats like a table of contents.
+%
+\parseargdef\listoffloats{%
+ \def\floattype{#1}% floattype
+ {%
+ % the floattype might have accents or other special characters,
+ % but we need to use it in a control sequence name.
+ \indexnofonts
+ \turnoffactive
+ \xdef\safefloattype{\floattype}%
+ }%
+ %
+ % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE.
+ \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax
+ \ifhavexrefs
+ % if the user said @listoffloats foo but never @float foo.
+ \message{\linenumber No `\safefloattype' floats to list.}%
+ \fi
+ \else
+ \begingroup
+ \leftskip=\tocindent % indent these entries like a toc
+ \let\do=\listoffloatsdo
+ \csname floatlist\safefloattype\endcsname
+ \endgroup
+ \fi
+}
+
+% This is called on each entry in a list of floats. We're passed the
+% xref label, in the form LABEL-title, which is how we save it in the
+% aux file. We strip off the -title and look up \XRLABEL-lof, which
+% has the text we're supposed to typeset here.
+%
+% Figures without xref labels will not be included in the list (since
+% they won't appear in the aux file).
+%
+\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish}
+\def\listoffloatsdoentry#1-title\finish{{%
+ % Can't fully expand XR#1-lof because it can contain anything. Just
+ % pass the control sequence. On the other hand, XR#1-pg is just the
+ % page number, and we want to fully expand that so we can get a link
+ % in pdf output.
+ \toksA = \expandafter{\csname XR#1-lof\endcsname}%
+ %
+ % use the same \entry macro we use to generate the TOC and index.
+ \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
+ \writeentry
+}}
+
+
+\message{localization,}
+
+% For single-language documents, @documentlanguage is usually given very
+% early, just after @documentencoding. Single argument is the language
+% (de) or locale (de_DE) abbreviation.
+%
+{
+ \catcode`\_ = \active
+ \globaldefs=1
+\parseargdef\documentlanguage{%
+ \tex % read txi-??.tex file in plain TeX.
+ % Read the file by the name they passed if it exists.
+ \let_ = \normalunderscore % normal _ character for filename test
+ \openin 1 txi-#1.tex
+ \ifeof 1
+ \documentlanguagetrywithoutunderscore #1_\finish
+ \else
+ \globaldefs = 1 % everything in the txi-LL files needs to persist
+ \input txi-#1.tex
+ \fi
+ \closein 1
+ \endgroup % end raw TeX
+}
+%
+% If they passed de_DE, and txi-de_DE.tex doesn't exist,
+% try txi-de.tex.
+%
+\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{%
+ \openin 1 txi-#1.tex
+ \ifeof 1
+ \errhelp = \nolanghelp
+ \errmessage{Cannot read language file txi-#1.tex}%
+ \else
+ \globaldefs = 1 % everything in the txi-LL files needs to persist
+ \input txi-#1.tex
+ \fi
+ \closein 1
+}
+}% end of special _ catcode
+%
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty. Maybe you need to install it? Putting it in the current
+directory should work if nowhere else does.}
+
+% This macro is called from txi-??.tex files; the first argument is the
+% \language name to set (without the "\lang@" prefix), the second and
+% third args are \{left,right}hyphenmin.
+%
+% The language names to pass are determined when the format is built.
+% See the etex.log file created at that time, e.g.,
+% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log.
+%
+% With TeX Live 2008, etex now includes hyphenation patterns for all
+% available languages. This means we can support hyphenation in
+% Texinfo, at least to some extent. (This still doesn't solve the
+% accented characters problem.)
+%
+\catcode`@=11
+\def\txisetlanguage#1#2#3{%
+ % do not set the language if the name is undefined in the current TeX.
+ \expandafter\ifx\csname lang@#1\endcsname \relax
+ \message{no patterns for #1}%
+ \else
+ \global\language = \csname lang@#1\endcsname
+ \fi
+ % but there is no harm in adjusting the hyphenmin values regardless.
+ \global\lefthyphenmin = #2\relax
+ \global\righthyphenmin = #3\relax
+}
+
+% Get input by bytes instead of by UTF-8 codepoints for XeTeX and LuaTeX,
+% otherwise the encoding support is completely broken.
+\ifx\XeTeXrevision\thisisundefined
+\else
+\XeTeXdefaultencoding "bytes" % For subsequent files to be read
+\XeTeXinputencoding "bytes" % Effective in texinfo.tex only
+% Unfortunately, there seems to be no corresponding XeTeX command for
+% output encoding. This is a problem for auxiliary index and TOC files.
+% The only solution would be perhaps to write out @U{...} sequences in
+% place of UTF-8 characters.
+\fi
+
+\ifx\luatexversion\thisisundefined
+\else
+\directlua{
+local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub
+local function convert_char (char)
+ return utf8_char(byte(char))
+end
+
+local function convert_line (line)
+ return gsub(line, ".", convert_char)
+end
+
+callback.register("process_input_buffer", convert_line)
+
+local function convert_line_out (line)
+ local line_out = ""
+ for c in string.utfvalues(line) do
+ line_out = line_out .. string.char(c)
+ end
+ return line_out
+end
+
+callback.register("process_output_buffer", convert_line_out)
+}
+\fi
+
+
+% Helpers for encodings.
+% Set the catcode of characters 128 through 255 to the specified number.
+%
+\def\setnonasciicharscatcode#1{%
+ \count255=128
+ \loop\ifnum\count255<256
+ \global\catcode\count255=#1\relax
+ \advance\count255 by 1
+ \repeat
+}
+
+\def\setnonasciicharscatcodenonglobal#1{%
+ \count255=128
+ \loop\ifnum\count255<256
+ \catcode\count255=#1\relax
+ \advance\count255 by 1
+ \repeat
+}
+
+% @documentencoding sets the definition of non-ASCII characters
+% according to the specified encoding.
+%
+\def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz}
+\def\documentencodingzzz#1{%
+ % Get input by bytes instead of by UTF-8 codepoints for XeTeX,
+ % otherwise the encoding support is completely broken.
+ % This settings is for the document root file.
+ \ifx\XeTeXrevision\thisisundefined
+ \else
+ \XeTeXinputencoding "bytes"
+ \fi
+ %
+ % Encoding being declared for the document.
+ \def\declaredencoding{\csname #1.enc\endcsname}%
+ %
+ % Supported encodings: names converted to tokens in order to be able
+ % to compare them with \ifx.
+ \def\ascii{\csname US-ASCII.enc\endcsname}%
+ \def\latnine{\csname ISO-8859-15.enc\endcsname}%
+ \def\latone{\csname ISO-8859-1.enc\endcsname}%
+ \def\lattwo{\csname ISO-8859-2.enc\endcsname}%
+ \def\utfeight{\csname UTF-8.enc\endcsname}%
+ %
+ \ifx \declaredencoding \ascii
+ \asciichardefs
+ %
+ \else \ifx \declaredencoding \lattwo
+ \setnonasciicharscatcode\active
+ \lattwochardefs
+ %
+ \else \ifx \declaredencoding \latone
+ \setnonasciicharscatcode\active
+ \latonechardefs
+ %
+ \else \ifx \declaredencoding \latnine
+ \setnonasciicharscatcode\active
+ \latninechardefs
+ %
+ \else \ifx \declaredencoding \utfeight
+ \setnonasciicharscatcode\active
+ % since we already invoked \utfeightchardefs at the top level
+ % (below), do not re-invoke it, then our check for duplicated
+ % definitions triggers. Making non-ascii chars active is enough.
+ %
+ \else
+ \message{Ignoring unknown document encoding: #1.}%
+ %
+ \fi % utfeight
+ \fi % latnine
+ \fi % latone
+ \fi % lattwo
+ \fi % ascii
+}
+
+% emacs-page
+% A message to be logged when using a character that isn't available
+% the default font encoding (OT1).
+%
+\def\missingcharmsg#1{\message{Character missing, sorry: #1.}}
+
+% Take account of \c (plain) vs. \, (Texinfo) difference.
+\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi}
+
+% First, make active non-ASCII characters in order for them to be
+% correctly categorized when TeX reads the replacement text of
+% macros containing the character definitions.
+\setnonasciicharscatcode\active
+%
+% Latin1 (ISO-8859-1) character definitions.
+\def\latonechardefs{%
+ \gdef^^a0{\tie}
+ \gdef^^a1{\exclamdown}
+ \gdef^^a2{{\tcfont \char162}} % cent
+ \gdef^^a3{\pounds}
+ \gdef^^a4{{\tcfont \char164}} % currency
+ \gdef^^a5{{\tcfont \char165}} % yen
+ \gdef^^a6{{\tcfont \char166}} % broken bar
+ \gdef^^a7{\S}
+ \gdef^^a8{\"{}}
+ \gdef^^a9{\copyright}
+ \gdef^^aa{\ordf}
+ \gdef^^ab{\guillemetleft}
+ \gdef^^ac{\ensuremath\lnot}
+ \gdef^^ad{\-}
+ \gdef^^ae{\registeredsymbol}
+ \gdef^^af{\={}}
+ %
+ \gdef^^b0{\textdegree}
+ \gdef^^b1{$\pm$}
+ \gdef^^b2{$^2$}
+ \gdef^^b3{$^3$}
+ \gdef^^b4{\'{}}
+ \gdef^^b5{$\mu$}
+ \gdef^^b6{\P}
+ \gdef^^b7{\ensuremath\cdot}
+ \gdef^^b8{\cedilla\ }
+ \gdef^^b9{$^1$}
+ \gdef^^ba{\ordm}
+ \gdef^^bb{\guillemetright}
+ \gdef^^bc{$1\over4$}
+ \gdef^^bd{$1\over2$}
+ \gdef^^be{$3\over4$}
+ \gdef^^bf{\questiondown}
+ %
+ \gdef^^c0{\`A}
+ \gdef^^c1{\'A}
+ \gdef^^c2{\^A}
+ \gdef^^c3{\~A}
+ \gdef^^c4{\"A}
+ \gdef^^c5{\ringaccent A}
+ \gdef^^c6{\AE}
+ \gdef^^c7{\cedilla C}
+ \gdef^^c8{\`E}
+ \gdef^^c9{\'E}
+ \gdef^^ca{\^E}
+ \gdef^^cb{\"E}
+ \gdef^^cc{\`I}
+ \gdef^^cd{\'I}
+ \gdef^^ce{\^I}
+ \gdef^^cf{\"I}
+ %
+ \gdef^^d0{\DH}
+ \gdef^^d1{\~N}
+ \gdef^^d2{\`O}
+ \gdef^^d3{\'O}
+ \gdef^^d4{\^O}
+ \gdef^^d5{\~O}
+ \gdef^^d6{\"O}
+ \gdef^^d7{$\times$}
+ \gdef^^d8{\O}
+ \gdef^^d9{\`U}
+ \gdef^^da{\'U}
+ \gdef^^db{\^U}
+ \gdef^^dc{\"U}
+ \gdef^^dd{\'Y}
+ \gdef^^de{\TH}
+ \gdef^^df{\ss}
+ %
+ \gdef^^e0{\`a}
+ \gdef^^e1{\'a}
+ \gdef^^e2{\^a}
+ \gdef^^e3{\~a}
+ \gdef^^e4{\"a}
+ \gdef^^e5{\ringaccent a}
+ \gdef^^e6{\ae}
+ \gdef^^e7{\cedilla c}
+ \gdef^^e8{\`e}
+ \gdef^^e9{\'e}
+ \gdef^^ea{\^e}
+ \gdef^^eb{\"e}
+ \gdef^^ec{\`{\dotless i}}
+ \gdef^^ed{\'{\dotless i}}
+ \gdef^^ee{\^{\dotless i}}
+ \gdef^^ef{\"{\dotless i}}
+ %
+ \gdef^^f0{\dh}
+ \gdef^^f1{\~n}
+ \gdef^^f2{\`o}
+ \gdef^^f3{\'o}
+ \gdef^^f4{\^o}
+ \gdef^^f5{\~o}
+ \gdef^^f6{\"o}
+ \gdef^^f7{$\div$}
+ \gdef^^f8{\o}
+ \gdef^^f9{\`u}
+ \gdef^^fa{\'u}
+ \gdef^^fb{\^u}
+ \gdef^^fc{\"u}
+ \gdef^^fd{\'y}
+ \gdef^^fe{\th}
+ \gdef^^ff{\"y}
+}
+
+% Latin9 (ISO-8859-15) encoding character definitions.
+\def\latninechardefs{%
+ % Encoding is almost identical to Latin1.
+ \latonechardefs
+ %
+ \gdef^^a4{\euro}
+ \gdef^^a6{\v S}
+ \gdef^^a8{\v s}
+ \gdef^^b4{\v Z}
+ \gdef^^b8{\v z}
+ \gdef^^bc{\OE}
+ \gdef^^bd{\oe}
+ \gdef^^be{\"Y}
+}
+
+% Latin2 (ISO-8859-2) character definitions.
+\def\lattwochardefs{%
+ \gdef^^a0{\tie}
+ \gdef^^a1{\ogonek{A}}
+ \gdef^^a2{\u{}}
+ \gdef^^a3{\L}
+ \gdef^^a4{\missingcharmsg{CURRENCY SIGN}}
+ \gdef^^a5{\v L}
+ \gdef^^a6{\'S}
+ \gdef^^a7{\S}
+ \gdef^^a8{\"{}}
+ \gdef^^a9{\v S}
+ \gdef^^aa{\cedilla S}
+ \gdef^^ab{\v T}
+ \gdef^^ac{\'Z}
+ \gdef^^ad{\-}
+ \gdef^^ae{\v Z}
+ \gdef^^af{\dotaccent Z}
+ %
+ \gdef^^b0{\textdegree}
+ \gdef^^b1{\ogonek{a}}
+ \gdef^^b2{\ogonek{ }}
+ \gdef^^b3{\l}
+ \gdef^^b4{\'{}}
+ \gdef^^b5{\v l}
+ \gdef^^b6{\'s}
+ \gdef^^b7{\v{}}
+ \gdef^^b8{\cedilla\ }
+ \gdef^^b9{\v s}
+ \gdef^^ba{\cedilla s}
+ \gdef^^bb{\v t}
+ \gdef^^bc{\'z}
+ \gdef^^bd{\H{}}
+ \gdef^^be{\v z}
+ \gdef^^bf{\dotaccent z}
+ %
+ \gdef^^c0{\'R}
+ \gdef^^c1{\'A}
+ \gdef^^c2{\^A}
+ \gdef^^c3{\u A}
+ \gdef^^c4{\"A}
+ \gdef^^c5{\'L}
+ \gdef^^c6{\'C}
+ \gdef^^c7{\cedilla C}
+ \gdef^^c8{\v C}
+ \gdef^^c9{\'E}
+ \gdef^^ca{\ogonek{E}}
+ \gdef^^cb{\"E}
+ \gdef^^cc{\v E}
+ \gdef^^cd{\'I}
+ \gdef^^ce{\^I}
+ \gdef^^cf{\v D}
+ %
+ \gdef^^d0{\DH}
+ \gdef^^d1{\'N}
+ \gdef^^d2{\v N}
+ \gdef^^d3{\'O}
+ \gdef^^d4{\^O}
+ \gdef^^d5{\H O}
+ \gdef^^d6{\"O}
+ \gdef^^d7{$\times$}
+ \gdef^^d8{\v R}
+ \gdef^^d9{\ringaccent U}
+ \gdef^^da{\'U}
+ \gdef^^db{\H U}
+ \gdef^^dc{\"U}
+ \gdef^^dd{\'Y}
+ \gdef^^de{\cedilla T}
+ \gdef^^df{\ss}
+ %
+ \gdef^^e0{\'r}
+ \gdef^^e1{\'a}
+ \gdef^^e2{\^a}
+ \gdef^^e3{\u a}
+ \gdef^^e4{\"a}
+ \gdef^^e5{\'l}
+ \gdef^^e6{\'c}
+ \gdef^^e7{\cedilla c}
+ \gdef^^e8{\v c}
+ \gdef^^e9{\'e}
+ \gdef^^ea{\ogonek{e}}
+ \gdef^^eb{\"e}
+ \gdef^^ec{\v e}
+ \gdef^^ed{\'{\dotless{i}}}
+ \gdef^^ee{\^{\dotless{i}}}
+ \gdef^^ef{\v d}
+ %
+ \gdef^^f0{\dh}
+ \gdef^^f1{\'n}
+ \gdef^^f2{\v n}
+ \gdef^^f3{\'o}
+ \gdef^^f4{\^o}
+ \gdef^^f5{\H o}
+ \gdef^^f6{\"o}
+ \gdef^^f7{$\div$}
+ \gdef^^f8{\v r}
+ \gdef^^f9{\ringaccent u}
+ \gdef^^fa{\'u}
+ \gdef^^fb{\H u}
+ \gdef^^fc{\"u}
+ \gdef^^fd{\'y}
+ \gdef^^fe{\cedilla t}
+ \gdef^^ff{\dotaccent{}}
+}
+
+% UTF-8 character definitions.
+%
+% This code to support UTF-8 is based on LaTeX's utf8.def, with some
+% changes for Texinfo conventions. It is included here under the GPL by
+% permission from Frank Mittelbach and the LaTeX team.
+%
+\newcount\countUTFx
+\newcount\countUTFy
+\newcount\countUTFz
+
+\gdef\UTFviiiTwoOctets#1#2{\expandafter
+ \UTFviiiDefined\csname u8:#1\string #2\endcsname}
+%
+\gdef\UTFviiiThreeOctets#1#2#3{\expandafter
+ \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname}
+%
+\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter
+ \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname}
+
+\gdef\UTFviiiDefined#1{%
+ \ifx #1\relax
+ \message{\linenumber Unicode char \string #1 not defined for Texinfo}%
+ \else
+ \expandafter #1%
+ \fi
+}
+
+\begingroup
+ \catcode`\~13
+ \catcode`\"12
+
+ \def\UTFviiiLoop{%
+ \global\catcode\countUTFx\active
+ \uccode`\~\countUTFx
+ \uppercase\expandafter{\UTFviiiTmp}%
+ \advance\countUTFx by 1
+ \ifnum\countUTFx < \countUTFy
+ \expandafter\UTFviiiLoop
+ \fi}
+
+ \countUTFx = "C2
+ \countUTFy = "E0
+ \def\UTFviiiTmp{%
+ \xdef~{\noexpand\UTFviiiTwoOctets\string~}}
+ \UTFviiiLoop
+
+ \countUTFx = "E0
+ \countUTFy = "F0
+ \def\UTFviiiTmp{%
+ \xdef~{\noexpand\UTFviiiThreeOctets\string~}}
+ \UTFviiiLoop
+
+ \countUTFx = "F0
+ \countUTFy = "F4
+ \def\UTFviiiTmp{%
+ \xdef~{\noexpand\UTFviiiFourOctets\string~}}
+ \UTFviiiLoop
+\endgroup
+
+\def\globallet{\global\let} % save some \expandafter's below
+
+% @U{xxxx} to produce U+xxxx, if we support it.
+\def\U#1{%
+ \expandafter\ifx\csname uni:#1\endcsname \relax
+ \errhelp = \EMsimple
+ \errmessage{Unicode character U+#1 not supported, sorry}%
+ \else
+ \csname uni:#1\endcsname
+ \fi
+}
+
+\begingroup
+ \catcode`\"=12
+ \catcode`\<=12
+ \catcode`\.=12
+ \catcode`\,=12
+ \catcode`\;=12
+ \catcode`\!=12
+ \catcode`\~=13
+ \gdef\DeclareUnicodeCharacter#1#2{%
+ \countUTFz = "#1\relax
+ %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}%
+ \begingroup
+ \parseXMLCharref
+ \def\UTFviiiTwoOctets##1##2{%
+ \csname u8:##1\string ##2\endcsname}%
+ \def\UTFviiiThreeOctets##1##2##3{%
+ \csname u8:##1\string ##2\string ##3\endcsname}%
+ \def\UTFviiiFourOctets##1##2##3##4{%
+ \csname u8:##1\string ##2\string ##3\string ##4\endcsname}%
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter
+ \gdef\UTFviiiTmp{#2}%
+ %
+ \expandafter\ifx\csname uni:#1\endcsname \relax \else
+ \message{Internal error, already defined: #1}%
+ \fi
+ %
+ % define an additional control sequence for this code point.
+ \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp
+ \endgroup}
+
+ \gdef\parseXMLCharref{%
+ \ifnum\countUTFz < "A0\relax
+ \errhelp = \EMsimple
+ \errmessage{Cannot define Unicode char value < 00A0}%
+ \else\ifnum\countUTFz < "800\relax
+ \parseUTFviiiA,%
+ \parseUTFviiiB C\UTFviiiTwoOctets.,%
+ \else\ifnum\countUTFz < "10000\relax
+ \parseUTFviiiA;%
+ \parseUTFviiiA,%
+ \parseUTFviiiB E\UTFviiiThreeOctets.{,;}%
+ \else
+ \parseUTFviiiA;%
+ \parseUTFviiiA,%
+ \parseUTFviiiA!%
+ \parseUTFviiiB F\UTFviiiFourOctets.{!,;}%
+ \fi\fi\fi
+ }
+
+ \gdef\parseUTFviiiA#1{%
+ \countUTFx = \countUTFz
+ \divide\countUTFz by 64
+ \countUTFy = \countUTFz
+ \multiply\countUTFz by 64
+ \advance\countUTFx by -\countUTFz
+ \advance\countUTFx by 128
+ \uccode `#1\countUTFx
+ \countUTFz = \countUTFy}
+
+ \gdef\parseUTFviiiB#1#2#3#4{%
+ \advance\countUTFz by "#10\relax
+ \uccode `#3\countUTFz
+ \uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
+\endgroup
+
+% https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M
+% U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
+% U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)
+% U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A
+% U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B
+%
+% Many of our renditions are less than wonderful, and all the missing
+% characters are available somewhere. Loading the necessary fonts
+% awaits user request. We can't truly support Unicode without
+% reimplementing everything that's been done in LaTeX for many years,
+% plus probably using luatex or xetex, and who knows what else.
+% We won't be doing that here in this simple file. But we can try to at
+% least make most of the characters not bomb out.
+%
+\def\utfeightchardefs{%
+ \DeclareUnicodeCharacter{00A0}{\tie}
+ \DeclareUnicodeCharacter{00A1}{\exclamdown}
+ \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent
+ \DeclareUnicodeCharacter{00A3}{\pounds}
+ \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency
+ \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen
+ \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar
+ \DeclareUnicodeCharacter{00A7}{\S}
+ \DeclareUnicodeCharacter{00A8}{\"{ }}
+ \DeclareUnicodeCharacter{00A9}{\copyright}
+ \DeclareUnicodeCharacter{00AA}{\ordf}
+ \DeclareUnicodeCharacter{00AB}{\guillemetleft}
+ \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}
+ \DeclareUnicodeCharacter{00AD}{\-}
+ \DeclareUnicodeCharacter{00AE}{\registeredsymbol}
+ \DeclareUnicodeCharacter{00AF}{\={ }}
+ %
+ \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}
+ \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}
+ \DeclareUnicodeCharacter{00B2}{$^2$}
+ \DeclareUnicodeCharacter{00B3}{$^3$}
+ \DeclareUnicodeCharacter{00B4}{\'{ }}
+ \DeclareUnicodeCharacter{00B5}{$\mu$}
+ \DeclareUnicodeCharacter{00B6}{\P}
+ \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}
+ \DeclareUnicodeCharacter{00B8}{\cedilla{ }}
+ \DeclareUnicodeCharacter{00B9}{$^1$}
+ \DeclareUnicodeCharacter{00BA}{\ordm}
+ \DeclareUnicodeCharacter{00BB}{\guillemetright}
+ \DeclareUnicodeCharacter{00BC}{$1\over4$}
+ \DeclareUnicodeCharacter{00BD}{$1\over2$}
+ \DeclareUnicodeCharacter{00BE}{$3\over4$}
+ \DeclareUnicodeCharacter{00BF}{\questiondown}
+ %
+ \DeclareUnicodeCharacter{00C0}{\`A}
+ \DeclareUnicodeCharacter{00C1}{\'A}
+ \DeclareUnicodeCharacter{00C2}{\^A}
+ \DeclareUnicodeCharacter{00C3}{\~A}
+ \DeclareUnicodeCharacter{00C4}{\"A}
+ \DeclareUnicodeCharacter{00C5}{\AA}
+ \DeclareUnicodeCharacter{00C6}{\AE}
+ \DeclareUnicodeCharacter{00C7}{\cedilla{C}}
+ \DeclareUnicodeCharacter{00C8}{\`E}
+ \DeclareUnicodeCharacter{00C9}{\'E}
+ \DeclareUnicodeCharacter{00CA}{\^E}
+ \DeclareUnicodeCharacter{00CB}{\"E}
+ \DeclareUnicodeCharacter{00CC}{\`I}
+ \DeclareUnicodeCharacter{00CD}{\'I}
+ \DeclareUnicodeCharacter{00CE}{\^I}
+ \DeclareUnicodeCharacter{00CF}{\"I}
+ %
+ \DeclareUnicodeCharacter{00D0}{\DH}
+ \DeclareUnicodeCharacter{00D1}{\~N}
+ \DeclareUnicodeCharacter{00D2}{\`O}
+ \DeclareUnicodeCharacter{00D3}{\'O}
+ \DeclareUnicodeCharacter{00D4}{\^O}
+ \DeclareUnicodeCharacter{00D5}{\~O}
+ \DeclareUnicodeCharacter{00D6}{\"O}
+ \DeclareUnicodeCharacter{00D7}{\ensuremath\times}
+ \DeclareUnicodeCharacter{00D8}{\O}
+ \DeclareUnicodeCharacter{00D9}{\`U}
+ \DeclareUnicodeCharacter{00DA}{\'U}
+ \DeclareUnicodeCharacter{00DB}{\^U}
+ \DeclareUnicodeCharacter{00DC}{\"U}
+ \DeclareUnicodeCharacter{00DD}{\'Y}
+ \DeclareUnicodeCharacter{00DE}{\TH}
+ \DeclareUnicodeCharacter{00DF}{\ss}
+ %
+ \DeclareUnicodeCharacter{00E0}{\`a}
+ \DeclareUnicodeCharacter{00E1}{\'a}
+ \DeclareUnicodeCharacter{00E2}{\^a}
+ \DeclareUnicodeCharacter{00E3}{\~a}
+ \DeclareUnicodeCharacter{00E4}{\"a}
+ \DeclareUnicodeCharacter{00E5}{\aa}
+ \DeclareUnicodeCharacter{00E6}{\ae}
+ \DeclareUnicodeCharacter{00E7}{\cedilla{c}}
+ \DeclareUnicodeCharacter{00E8}{\`e}
+ \DeclareUnicodeCharacter{00E9}{\'e}
+ \DeclareUnicodeCharacter{00EA}{\^e}
+ \DeclareUnicodeCharacter{00EB}{\"e}
+ \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}
+ \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}
+ \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}
+ \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}
+ %
+ \DeclareUnicodeCharacter{00F0}{\dh}
+ \DeclareUnicodeCharacter{00F1}{\~n}
+ \DeclareUnicodeCharacter{00F2}{\`o}
+ \DeclareUnicodeCharacter{00F3}{\'o}
+ \DeclareUnicodeCharacter{00F4}{\^o}
+ \DeclareUnicodeCharacter{00F5}{\~o}
+ \DeclareUnicodeCharacter{00F6}{\"o}
+ \DeclareUnicodeCharacter{00F7}{\ensuremath\div}
+ \DeclareUnicodeCharacter{00F8}{\o}
+ \DeclareUnicodeCharacter{00F9}{\`u}
+ \DeclareUnicodeCharacter{00FA}{\'u}
+ \DeclareUnicodeCharacter{00FB}{\^u}
+ \DeclareUnicodeCharacter{00FC}{\"u}
+ \DeclareUnicodeCharacter{00FD}{\'y}
+ \DeclareUnicodeCharacter{00FE}{\th}
+ \DeclareUnicodeCharacter{00FF}{\"y}
+ %
+ \DeclareUnicodeCharacter{0100}{\=A}
+ \DeclareUnicodeCharacter{0101}{\=a}
+ \DeclareUnicodeCharacter{0102}{\u{A}}
+ \DeclareUnicodeCharacter{0103}{\u{a}}
+ \DeclareUnicodeCharacter{0104}{\ogonek{A}}
+ \DeclareUnicodeCharacter{0105}{\ogonek{a}}
+ \DeclareUnicodeCharacter{0106}{\'C}
+ \DeclareUnicodeCharacter{0107}{\'c}
+ \DeclareUnicodeCharacter{0108}{\^C}
+ \DeclareUnicodeCharacter{0109}{\^c}
+ \DeclareUnicodeCharacter{010A}{\dotaccent{C}}
+ \DeclareUnicodeCharacter{010B}{\dotaccent{c}}
+ \DeclareUnicodeCharacter{010C}{\v{C}}
+ \DeclareUnicodeCharacter{010D}{\v{c}}
+ \DeclareUnicodeCharacter{010E}{\v{D}}
+ \DeclareUnicodeCharacter{010F}{d'}
+ %
+ \DeclareUnicodeCharacter{0110}{\DH}
+ \DeclareUnicodeCharacter{0111}{\dh}
+ \DeclareUnicodeCharacter{0112}{\=E}
+ \DeclareUnicodeCharacter{0113}{\=e}
+ \DeclareUnicodeCharacter{0114}{\u{E}}
+ \DeclareUnicodeCharacter{0115}{\u{e}}
+ \DeclareUnicodeCharacter{0116}{\dotaccent{E}}
+ \DeclareUnicodeCharacter{0117}{\dotaccent{e}}
+ \DeclareUnicodeCharacter{0118}{\ogonek{E}}
+ \DeclareUnicodeCharacter{0119}{\ogonek{e}}
+ \DeclareUnicodeCharacter{011A}{\v{E}}
+ \DeclareUnicodeCharacter{011B}{\v{e}}
+ \DeclareUnicodeCharacter{011C}{\^G}
+ \DeclareUnicodeCharacter{011D}{\^g}
+ \DeclareUnicodeCharacter{011E}{\u{G}}
+ \DeclareUnicodeCharacter{011F}{\u{g}}
+ %
+ \DeclareUnicodeCharacter{0120}{\dotaccent{G}}
+ \DeclareUnicodeCharacter{0121}{\dotaccent{g}}
+ \DeclareUnicodeCharacter{0122}{\cedilla{G}}
+ \DeclareUnicodeCharacter{0123}{\cedilla{g}}
+ \DeclareUnicodeCharacter{0124}{\^H}
+ \DeclareUnicodeCharacter{0125}{\^h}
+ \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}
+ \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}
+ \DeclareUnicodeCharacter{0128}{\~I}
+ \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}
+ \DeclareUnicodeCharacter{012A}{\=I}
+ \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}
+ \DeclareUnicodeCharacter{012C}{\u{I}}
+ \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}
+ \DeclareUnicodeCharacter{012E}{\ogonek{I}}
+ \DeclareUnicodeCharacter{012F}{\ogonek{i}}
+ %
+ \DeclareUnicodeCharacter{0130}{\dotaccent{I}}
+ \DeclareUnicodeCharacter{0131}{\dotless{i}}
+ \DeclareUnicodeCharacter{0132}{IJ}
+ \DeclareUnicodeCharacter{0133}{ij}
+ \DeclareUnicodeCharacter{0134}{\^J}
+ \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}
+ \DeclareUnicodeCharacter{0136}{\cedilla{K}}
+ \DeclareUnicodeCharacter{0137}{\cedilla{k}}
+ \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}
+ \DeclareUnicodeCharacter{0139}{\'L}
+ \DeclareUnicodeCharacter{013A}{\'l}
+ \DeclareUnicodeCharacter{013B}{\cedilla{L}}
+ \DeclareUnicodeCharacter{013C}{\cedilla{l}}
+ \DeclareUnicodeCharacter{013D}{L'}% should kern
+ \DeclareUnicodeCharacter{013E}{l'}% should kern
+ \DeclareUnicodeCharacter{013F}{L\U{00B7}}
+ %
+ \DeclareUnicodeCharacter{0140}{l\U{00B7}}
+ \DeclareUnicodeCharacter{0141}{\L}
+ \DeclareUnicodeCharacter{0142}{\l}
+ \DeclareUnicodeCharacter{0143}{\'N}
+ \DeclareUnicodeCharacter{0144}{\'n}
+ \DeclareUnicodeCharacter{0145}{\cedilla{N}}
+ \DeclareUnicodeCharacter{0146}{\cedilla{n}}
+ \DeclareUnicodeCharacter{0147}{\v{N}}
+ \DeclareUnicodeCharacter{0148}{\v{n}}
+ \DeclareUnicodeCharacter{0149}{'n}
+ \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}
+ \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}
+ \DeclareUnicodeCharacter{014C}{\=O}
+ \DeclareUnicodeCharacter{014D}{\=o}
+ \DeclareUnicodeCharacter{014E}{\u{O}}
+ \DeclareUnicodeCharacter{014F}{\u{o}}
+ %
+ \DeclareUnicodeCharacter{0150}{\H{O}}
+ \DeclareUnicodeCharacter{0151}{\H{o}}
+ \DeclareUnicodeCharacter{0152}{\OE}
+ \DeclareUnicodeCharacter{0153}{\oe}
+ \DeclareUnicodeCharacter{0154}{\'R}
+ \DeclareUnicodeCharacter{0155}{\'r}
+ \DeclareUnicodeCharacter{0156}{\cedilla{R}}
+ \DeclareUnicodeCharacter{0157}{\cedilla{r}}
+ \DeclareUnicodeCharacter{0158}{\v{R}}
+ \DeclareUnicodeCharacter{0159}{\v{r}}
+ \DeclareUnicodeCharacter{015A}{\'S}
+ \DeclareUnicodeCharacter{015B}{\'s}
+ \DeclareUnicodeCharacter{015C}{\^S}
+ \DeclareUnicodeCharacter{015D}{\^s}
+ \DeclareUnicodeCharacter{015E}{\cedilla{S}}
+ \DeclareUnicodeCharacter{015F}{\cedilla{s}}
+ %
+ \DeclareUnicodeCharacter{0160}{\v{S}}
+ \DeclareUnicodeCharacter{0161}{\v{s}}
+ \DeclareUnicodeCharacter{0162}{\cedilla{T}}
+ \DeclareUnicodeCharacter{0163}{\cedilla{t}}
+ \DeclareUnicodeCharacter{0164}{\v{T}}
+ \DeclareUnicodeCharacter{0165}{\v{t}}
+ \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}
+ \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}
+ \DeclareUnicodeCharacter{0168}{\~U}
+ \DeclareUnicodeCharacter{0169}{\~u}
+ \DeclareUnicodeCharacter{016A}{\=U}
+ \DeclareUnicodeCharacter{016B}{\=u}
+ \DeclareUnicodeCharacter{016C}{\u{U}}
+ \DeclareUnicodeCharacter{016D}{\u{u}}
+ \DeclareUnicodeCharacter{016E}{\ringaccent{U}}
+ \DeclareUnicodeCharacter{016F}{\ringaccent{u}}
+ %
+ \DeclareUnicodeCharacter{0170}{\H{U}}
+ \DeclareUnicodeCharacter{0171}{\H{u}}
+ \DeclareUnicodeCharacter{0172}{\ogonek{U}}
+ \DeclareUnicodeCharacter{0173}{\ogonek{u}}
+ \DeclareUnicodeCharacter{0174}{\^W}
+ \DeclareUnicodeCharacter{0175}{\^w}
+ \DeclareUnicodeCharacter{0176}{\^Y}
+ \DeclareUnicodeCharacter{0177}{\^y}
+ \DeclareUnicodeCharacter{0178}{\"Y}
+ \DeclareUnicodeCharacter{0179}{\'Z}
+ \DeclareUnicodeCharacter{017A}{\'z}
+ \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}
+ \DeclareUnicodeCharacter{017C}{\dotaccent{z}}
+ \DeclareUnicodeCharacter{017D}{\v{Z}}
+ \DeclareUnicodeCharacter{017E}{\v{z}}
+ \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}
+ %
+ \DeclareUnicodeCharacter{01C4}{D\v{Z}}
+ \DeclareUnicodeCharacter{01C5}{D\v{z}}
+ \DeclareUnicodeCharacter{01C6}{d\v{z}}
+ \DeclareUnicodeCharacter{01C7}{LJ}
+ \DeclareUnicodeCharacter{01C8}{Lj}
+ \DeclareUnicodeCharacter{01C9}{lj}
+ \DeclareUnicodeCharacter{01CA}{NJ}
+ \DeclareUnicodeCharacter{01CB}{Nj}
+ \DeclareUnicodeCharacter{01CC}{nj}
+ \DeclareUnicodeCharacter{01CD}{\v{A}}
+ \DeclareUnicodeCharacter{01CE}{\v{a}}
+ \DeclareUnicodeCharacter{01CF}{\v{I}}
+ %
+ \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}
+ \DeclareUnicodeCharacter{01D1}{\v{O}}
+ \DeclareUnicodeCharacter{01D2}{\v{o}}
+ \DeclareUnicodeCharacter{01D3}{\v{U}}
+ \DeclareUnicodeCharacter{01D4}{\v{u}}
+ %
+ \DeclareUnicodeCharacter{01E2}{\={\AE}}
+ \DeclareUnicodeCharacter{01E3}{\={\ae}}
+ \DeclareUnicodeCharacter{01E6}{\v{G}}
+ \DeclareUnicodeCharacter{01E7}{\v{g}}
+ \DeclareUnicodeCharacter{01E8}{\v{K}}
+ \DeclareUnicodeCharacter{01E9}{\v{k}}
+ %
+ \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}
+ \DeclareUnicodeCharacter{01F1}{DZ}
+ \DeclareUnicodeCharacter{01F2}{Dz}
+ \DeclareUnicodeCharacter{01F3}{dz}
+ \DeclareUnicodeCharacter{01F4}{\'G}
+ \DeclareUnicodeCharacter{01F5}{\'g}
+ \DeclareUnicodeCharacter{01F8}{\`N}
+ \DeclareUnicodeCharacter{01F9}{\`n}
+ \DeclareUnicodeCharacter{01FC}{\'{\AE}}
+ \DeclareUnicodeCharacter{01FD}{\'{\ae}}
+ \DeclareUnicodeCharacter{01FE}{\'{\O}}
+ \DeclareUnicodeCharacter{01FF}{\'{\o}}
+ %
+ \DeclareUnicodeCharacter{021E}{\v{H}}
+ \DeclareUnicodeCharacter{021F}{\v{h}}
+ %
+ \DeclareUnicodeCharacter{0226}{\dotaccent{A}}
+ \DeclareUnicodeCharacter{0227}{\dotaccent{a}}
+ \DeclareUnicodeCharacter{0228}{\cedilla{E}}
+ \DeclareUnicodeCharacter{0229}{\cedilla{e}}
+ \DeclareUnicodeCharacter{022E}{\dotaccent{O}}
+ \DeclareUnicodeCharacter{022F}{\dotaccent{o}}
+ %
+ \DeclareUnicodeCharacter{0232}{\=Y}
+ \DeclareUnicodeCharacter{0233}{\=y}
+ \DeclareUnicodeCharacter{0237}{\dotless{j}}
+ %
+ \DeclareUnicodeCharacter{02DB}{\ogonek{ }}
+ %
+ % Greek letters upper case
+ \DeclareUnicodeCharacter{0391}{{\it A}}
+ \DeclareUnicodeCharacter{0392}{{\it B}}
+ \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}
+ \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}
+ \DeclareUnicodeCharacter{0395}{{\it E}}
+ \DeclareUnicodeCharacter{0396}{{\it Z}}
+ \DeclareUnicodeCharacter{0397}{{\it H}}
+ \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}
+ \DeclareUnicodeCharacter{0399}{{\it I}}
+ \DeclareUnicodeCharacter{039A}{{\it K}}
+ \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}
+ \DeclareUnicodeCharacter{039C}{{\it M}}
+ \DeclareUnicodeCharacter{039D}{{\it N}}
+ \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}
+ \DeclareUnicodeCharacter{039F}{{\it O}}
+ \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}
+ \DeclareUnicodeCharacter{03A1}{{\it P}}
+ %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma
+ \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}
+ \DeclareUnicodeCharacter{03A4}{{\it T}}
+ \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}
+ \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}
+ \DeclareUnicodeCharacter{03A7}{{\it X}}
+ \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}
+ \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}
+ %
+ % Vowels with accents
+ \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}
+ \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}
+ \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}
+ \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}
+ \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}
+ \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}
+ %
+ % Standalone accent
+ \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}
+ %
+ % Greek letters lower case
+ \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}
+ \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}
+ \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}
+ \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}
+ \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}
+ \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}
+ \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}
+ \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}
+ \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}
+ \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}
+ \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}
+ \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}
+ \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}
+ \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}
+ \DeclareUnicodeCharacter{03BF}{{\it o}} % omicron
+ \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}
+ \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}
+ \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}
+ \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}
+ \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}
+ \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}
+ \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}
+ \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}
+ \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}
+ \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}
+ %
+ % More Greek vowels with accents
+ \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}
+ \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}
+ \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}
+ \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}
+ \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}
+ %
+ % Variant Greek letters
+ \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}
+ \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}
+ \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}
+ %
+ \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}
+ \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}
+ \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}
+ \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}
+ \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}
+ \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}
+ \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}
+ \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}
+ \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}
+ \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}
+ \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}
+ \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}
+ %
+ \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}
+ \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}
+ %
+ \DeclareUnicodeCharacter{1E20}{\=G}
+ \DeclareUnicodeCharacter{1E21}{\=g}
+ \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}
+ \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}
+ \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}
+ \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}
+ \DeclareUnicodeCharacter{1E26}{\"H}
+ \DeclareUnicodeCharacter{1E27}{\"h}
+ %
+ \DeclareUnicodeCharacter{1E30}{\'K}
+ \DeclareUnicodeCharacter{1E31}{\'k}
+ \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}
+ \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}
+ \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}
+ \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}
+ \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}
+ \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}
+ \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}
+ \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}
+ \DeclareUnicodeCharacter{1E3E}{\'M}
+ \DeclareUnicodeCharacter{1E3F}{\'m}
+ %
+ \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}
+ \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}
+ \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}
+ \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}
+ \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}
+ \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}
+ \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}
+ \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}
+ \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}
+ \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}
+ %
+ \DeclareUnicodeCharacter{1E54}{\'P}
+ \DeclareUnicodeCharacter{1E55}{\'p}
+ \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}
+ \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}
+ \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}
+ \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}
+ \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}
+ \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}
+ \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}
+ \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}
+ %
+ \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}
+ \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}
+ \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}
+ \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}
+ \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}
+ \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}
+ \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}
+ \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}
+ \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}
+ \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}
+ %
+ \DeclareUnicodeCharacter{1E7C}{\~V}
+ \DeclareUnicodeCharacter{1E7D}{\~v}
+ \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}
+ \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}
+ %
+ \DeclareUnicodeCharacter{1E80}{\`W}
+ \DeclareUnicodeCharacter{1E81}{\`w}
+ \DeclareUnicodeCharacter{1E82}{\'W}
+ \DeclareUnicodeCharacter{1E83}{\'w}
+ \DeclareUnicodeCharacter{1E84}{\"W}
+ \DeclareUnicodeCharacter{1E85}{\"w}
+ \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}
+ \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}
+ \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}
+ \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}
+ \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}
+ \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}
+ \DeclareUnicodeCharacter{1E8C}{\"X}
+ \DeclareUnicodeCharacter{1E8D}{\"x}
+ \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}
+ \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}
+ %
+ \DeclareUnicodeCharacter{1E90}{\^Z}
+ \DeclareUnicodeCharacter{1E91}{\^z}
+ \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}
+ \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}
+ \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}
+ \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}
+ \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}
+ \DeclareUnicodeCharacter{1E97}{\"t}
+ \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}
+ \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}
+ %
+ \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}
+ \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}
+ %
+ \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}
+ \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}
+ \DeclareUnicodeCharacter{1EBC}{\~E}
+ \DeclareUnicodeCharacter{1EBD}{\~e}
+ %
+ \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}
+ \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}
+ \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}
+ \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}
+ %
+ \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}
+ \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}
+ %
+ \DeclareUnicodeCharacter{1EF2}{\`Y}
+ \DeclareUnicodeCharacter{1EF3}{\`y}
+ \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}
+ %
+ \DeclareUnicodeCharacter{1EF8}{\~Y}
+ \DeclareUnicodeCharacter{1EF9}{\~y}
+ %
+ % Punctuation
+ \DeclareUnicodeCharacter{2013}{--}
+ \DeclareUnicodeCharacter{2014}{---}
+ \DeclareUnicodeCharacter{2018}{\quoteleft}
+ \DeclareUnicodeCharacter{2019}{\quoteright}
+ \DeclareUnicodeCharacter{201A}{\quotesinglbase}
+ \DeclareUnicodeCharacter{201C}{\quotedblleft}
+ \DeclareUnicodeCharacter{201D}{\quotedblright}
+ \DeclareUnicodeCharacter{201E}{\quotedblbase}
+ \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}
+ \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}
+ \DeclareUnicodeCharacter{2022}{\bullet}
+ \DeclareUnicodeCharacter{202F}{\thinspace}
+ \DeclareUnicodeCharacter{2026}{\dots}
+ \DeclareUnicodeCharacter{2039}{\guilsinglleft}
+ \DeclareUnicodeCharacter{203A}{\guilsinglright}
+ %
+ \DeclareUnicodeCharacter{20AC}{\euro}
+ %
+ \DeclareUnicodeCharacter{2192}{\expansion}
+ \DeclareUnicodeCharacter{21D2}{\result}
+ %
+ % Mathematical symbols
+ \DeclareUnicodeCharacter{2200}{\ensuremath\forall}
+ \DeclareUnicodeCharacter{2203}{\ensuremath\exists}
+ \DeclareUnicodeCharacter{2208}{\ensuremath\in}
+ \DeclareUnicodeCharacter{2212}{\minus}
+ \DeclareUnicodeCharacter{2217}{\ast}
+ \DeclareUnicodeCharacter{221E}{\ensuremath\infty}
+ \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}
+ \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}
+ \DeclareUnicodeCharacter{2229}{\ensuremath\cap}
+ \DeclareUnicodeCharacter{2261}{\equiv}
+ \DeclareUnicodeCharacter{2264}{\ensuremath\leq}
+ \DeclareUnicodeCharacter{2265}{\ensuremath\geq}
+ \DeclareUnicodeCharacter{2282}{\ensuremath\subset}
+ \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}
+ %
+ \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}
+ \DeclareUnicodeCharacter{2032}{\ensuremath\prime}
+ \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}
+ \DeclareUnicodeCharacter{2111}{\ensuremath\Im}
+ \DeclareUnicodeCharacter{2113}{\ensuremath\ell}
+ \DeclareUnicodeCharacter{2118}{\ensuremath\wp}
+ \DeclareUnicodeCharacter{211C}{\ensuremath\Re}
+ \DeclareUnicodeCharacter{2127}{\ensuremath\mho}
+ \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}
+ \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}
+ \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}
+ \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}
+ \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}
+ \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}
+ \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}
+ \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}
+ \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}
+ \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}
+ \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}
+ \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}
+ \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}
+ \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}
+ \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}
+ \DeclareUnicodeCharacter{21BE}{\ensuremath\upharpoonright}
+ \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}
+ \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}
+ \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}
+ \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}
+ \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}
+ \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}
+ \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}
+ \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}
+ \DeclareUnicodeCharacter{21DD}{\ensuremath\leadsto}
+ \DeclareUnicodeCharacter{2201}{\ensuremath\complement}
+ \DeclareUnicodeCharacter{2202}{\ensuremath\partial}
+ \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}
+ \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}
+ \DeclareUnicodeCharacter{2209}{\ensuremath\notin}
+ \DeclareUnicodeCharacter{220B}{\ensuremath\owns}
+ \DeclareUnicodeCharacter{220F}{\ensuremath\prod}
+ \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}
+ \DeclareUnicodeCharacter{2211}{\ensuremath\sum}
+ \DeclareUnicodeCharacter{2213}{\ensuremath\mp}
+ \DeclareUnicodeCharacter{2218}{\ensuremath\circ}
+ \DeclareUnicodeCharacter{221A}{\ensuremath\surd}
+ \DeclareUnicodeCharacter{221D}{\ensuremath\propto}
+ \DeclareUnicodeCharacter{2220}{\ensuremath\angle}
+ \DeclareUnicodeCharacter{2223}{\ensuremath\mid}
+ \DeclareUnicodeCharacter{2228}{\ensuremath\vee}
+ \DeclareUnicodeCharacter{222A}{\ensuremath\cup}
+ \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}
+ \DeclareUnicodeCharacter{222E}{\ensuremath\oint}
+ \DeclareUnicodeCharacter{223C}{\ensuremath\sim}
+ \DeclareUnicodeCharacter{2240}{\ensuremath\wr}
+ \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}
+ \DeclareUnicodeCharacter{2245}{\ensuremath\cong}
+ \DeclareUnicodeCharacter{2248}{\ensuremath\approx}
+ \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}
+ \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}
+ \DeclareUnicodeCharacter{2260}{\ensuremath\neq}
+ \DeclareUnicodeCharacter{226A}{\ensuremath\ll}
+ \DeclareUnicodeCharacter{226B}{\ensuremath\gg}
+ \DeclareUnicodeCharacter{227A}{\ensuremath\prec}
+ \DeclareUnicodeCharacter{227B}{\ensuremath\succ}
+ \DeclareUnicodeCharacter{2283}{\ensuremath\supset}
+ \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}
+ \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}
+ \DeclareUnicodeCharacter{228F}{\ensuremath\sqsubset}
+ \DeclareUnicodeCharacter{2290}{\ensuremath\sqsupset}
+ \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}
+ \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}
+ \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}
+ \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}
+ \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}
+ \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}
+ \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}
+ \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}
+ \DeclareUnicodeCharacter{2299}{\ensuremath\odot}
+ \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}
+ \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}
+ \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}
+ \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}
+ \DeclareUnicodeCharacter{22A8}{\ensuremath\models}
+ \DeclareUnicodeCharacter{22B4}{\ensuremath\unlhd}
+ \DeclareUnicodeCharacter{22B5}{\ensuremath\unrhd}
+ \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}
+ \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}
+ \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}
+ \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}
+ \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}
+ \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}
+ \DeclareUnicodeCharacter{22C6}{\ensuremath\star}
+ \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}
+ \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}
+ \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}
+ \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}
+ \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}
+ \DeclareUnicodeCharacter{2322}{\ensuremath\frown}
+ \DeclareUnicodeCharacter{2323}{\ensuremath\smile}
+ %
+ \DeclareUnicodeCharacter{25A1}{\ensuremath\Box}
+ \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}
+ \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}
+ \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}
+ \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}
+ \DeclareUnicodeCharacter{25C7}{\ensuremath\Diamond}
+ \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}
+ \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}
+ \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}
+ \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}
+ \DeclareUnicodeCharacter{266D}{\ensuremath\flat}
+ \DeclareUnicodeCharacter{266E}{\ensuremath\natural}
+ \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}
+ \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}
+ \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}
+ \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}
+ \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}
+ \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}
+ \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}
+ \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}
+ \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}
+ \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}
+ \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}
+ \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}
+ \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}
+ \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}
+ \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}
+ \DeclareUnicodeCharacter{2A1D}{\ensuremath\Join}
+ \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}
+ \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}
+ \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}
+ %
+ \global\mathchardef\checkmark="1370 % actually the square root sign
+ \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}
+}% end of \utfeightchardefs
+
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+ \relax
+}
+
+% Latin1 (ISO-8859-1) character definitions.
+\def\nonasciistringdefs{%
+ \setnonasciicharscatcode\active
+ \def\defstringchar##1{\def##1{\string##1}}%
+ %
+ \defstringchar^^80\defstringchar^^81\defstringchar^^82\defstringchar^^83%
+ \defstringchar^^84\defstringchar^^85\defstringchar^^86\defstringchar^^87%
+ \defstringchar^^88\defstringchar^^89\defstringchar^^8a\defstringchar^^8b%
+ \defstringchar^^8c\defstringchar^^8d\defstringchar^^8e\defstringchar^^8f%
+ %
+ \defstringchar^^90\defstringchar^^91\defstringchar^^92\defstringchar^^93%
+ \defstringchar^^94\defstringchar^^95\defstringchar^^96\defstringchar^^97%
+ \defstringchar^^98\defstringchar^^99\defstringchar^^9a\defstringchar^^9b%
+ \defstringchar^^9c\defstringchar^^9d\defstringchar^^9e\defstringchar^^9f%
+ %
+ \defstringchar^^a0\defstringchar^^a1\defstringchar^^a2\defstringchar^^a3%
+ \defstringchar^^a4\defstringchar^^a5\defstringchar^^a6\defstringchar^^a7%
+ \defstringchar^^a8\defstringchar^^a9\defstringchar^^aa\defstringchar^^ab%
+ \defstringchar^^ac\defstringchar^^ad\defstringchar^^ae\defstringchar^^af%
+ %
+ \defstringchar^^b0\defstringchar^^b1\defstringchar^^b2\defstringchar^^b3%
+ \defstringchar^^b4\defstringchar^^b5\defstringchar^^b6\defstringchar^^b7%
+ \defstringchar^^b8\defstringchar^^b9\defstringchar^^ba\defstringchar^^bb%
+ \defstringchar^^bc\defstringchar^^bd\defstringchar^^be\defstringchar^^bf%
+ %
+ \defstringchar^^c0\defstringchar^^c1\defstringchar^^c2\defstringchar^^c3%
+ \defstringchar^^c4\defstringchar^^c5\defstringchar^^c6\defstringchar^^c7%
+ \defstringchar^^c8\defstringchar^^c9\defstringchar^^ca\defstringchar^^cb%
+ \defstringchar^^cc\defstringchar^^cd\defstringchar^^ce\defstringchar^^cf%
+ %
+ \defstringchar^^d0\defstringchar^^d1\defstringchar^^d2\defstringchar^^d3%
+ \defstringchar^^d4\defstringchar^^d5\defstringchar^^d6\defstringchar^^d7%
+ \defstringchar^^d8\defstringchar^^d9\defstringchar^^da\defstringchar^^db%
+ \defstringchar^^dc\defstringchar^^dd\defstringchar^^de\defstringchar^^df%
+ %
+ \defstringchar^^e0\defstringchar^^e1\defstringchar^^e2\defstringchar^^e3%
+ \defstringchar^^e4\defstringchar^^e5\defstringchar^^e6\defstringchar^^e7%
+ \defstringchar^^e8\defstringchar^^e9\defstringchar^^ea\defstringchar^^eb%
+ \defstringchar^^ec\defstringchar^^ed\defstringchar^^ee\defstringchar^^ef%
+ %
+ \defstringchar^^f0\defstringchar^^f1\defstringchar^^f2\defstringchar^^f3%
+ \defstringchar^^f4\defstringchar^^f5\defstringchar^^f6\defstringchar^^f7%
+ \defstringchar^^f8\defstringchar^^f9\defstringchar^^fa\defstringchar^^fb%
+ \defstringchar^^fc\defstringchar^^fd\defstringchar^^fe\defstringchar^^ff%
+}
+
+
+% define all the unicode characters we know about, for the sake of @U.
+\utfeightchardefs
+
+
+% Make non-ASCII characters printable again for compatibility with
+% existing Texinfo documents that may use them, even without declaring a
+% document encoding.
+%
+\setnonasciicharscatcode \other
+
+
+\message{formatting,}
+
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be very finicky about underfull hboxes, either.
+\hbadness = 6666
+
+% Following George Bush, get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+ \ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+ \else
+ \emergencystretch = .15\hsize
+ \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth;
+% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip;
+% 7) physical page height; 8) physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading. The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+ \voffset = #3\relax
+ \topskip = #6\relax
+ \splittopskip = \topskip
+ %
+ \vsize = #1\relax
+ \advance\vsize by \topskip
+ \outervsize = \vsize
+ \advance\outervsize by 2\topandbottommargin
+ \pageheight = \vsize
+ %
+ \hsize = #2\relax
+ \outerhsize = \hsize
+ \advance\outerhsize by 0.5in
+ \pagewidth = \hsize
+ %
+ \normaloffset = #4\relax
+ \bindingoffset = #5\relax
+ %
+ \ifpdf
+ \pdfpageheight #7\relax
+ \pdfpagewidth #8\relax
+ % if we don't reset these, they will remain at "1 true in" of
+ % whatever layout pdftex was dumped with.
+ \pdfhorigin = 1 true in
+ \pdfvorigin = 1 true in
+ \fi
+ %
+ \setleading{\textleading}
+ %
+ \parindent = \defaultparindent
+ \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+ \parskip = 3pt plus 2pt minus 1pt
+ \textleading = 13.2pt
+ %
+ % If page is nothing but text, make it come out even.
+ \internalpagesizes{607.2pt}{6in}% that's 46 lines
+ {\voffset}{.25in}%
+ {\bindingoffset}{36pt}%
+ {11in}{8.5in}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.25 trim size.
+\def\smallbook{{\globaldefs = 1
+ \parskip = 2pt plus 1pt
+ \textleading = 12pt
+ %
+ \internalpagesizes{7.5in}{5in}%
+ {-.2in}{0in}%
+ {\bindingoffset}{16pt}%
+ {9.25in}{7in}%
+ %
+ \lispnarrowing = 0.3in
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = .5cm
+}}
+
+% Use @smallerbook to reset parameters for 6x9 trim size.
+% (Just testing, parameters still in flux.)
+\def\smallerbook{{\globaldefs = 1
+ \parskip = 1.5pt plus 1pt
+ \textleading = 12pt
+ %
+ \internalpagesizes{7.4in}{4.8in}%
+ {-.2in}{-.4in}%
+ {0pt}{14pt}%
+ {9in}{6in}%
+ %
+ \lispnarrowing = 0.25in
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = .4cm
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+ \parskip = 3pt plus 2pt minus 1pt
+ \textleading = 13.2pt
+ %
+ % Double-side printing via postscript on Laserjet 4050
+ % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm.
+ % To change the settings for a different printer or situation, adjust
+ % \normaloffset until the front-side and back-side texts align. Then
+ % do the same for \bindingoffset. You can set these for testing in
+ % your texinfo source file like this:
+ % @tex
+ % \global\normaloffset = -6mm
+ % \global\bindingoffset = 10mm
+ % @end tex
+ \internalpagesizes{673.2pt}{160mm}% that's 51 lines
+ {\voffset}{\hoffset}%
+ {\bindingoffset}{44pt}%
+ {297mm}{210mm}%
+ %
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = 5mm
+}}
+
+% Use @afivepaper to print on European A5 paper.
+% From romildo@urano.iceb.ufop.br, 2 July 2000.
+% He also recommends making @example and @lisp be small.
+\def\afivepaper{{\globaldefs = 1
+ \parskip = 2pt plus 1pt minus 0.1pt
+ \textleading = 12.5pt
+ %
+ \internalpagesizes{160mm}{120mm}%
+ {\voffset}{\hoffset}%
+ {\bindingoffset}{8pt}%
+ {210mm}{148mm}%
+ %
+ \lispnarrowing = 0.2in
+ \tolerance = 800
+ \hfuzz = 1.2pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = 2mm
+ \tableindent = 12mm
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.
+\def\afourlatex{{\globaldefs = 1
+ \afourpaper
+ \internalpagesizes{237mm}{150mm}%
+ {\voffset}{4.6mm}%
+ {\bindingoffset}{7mm}%
+ {297mm}{210mm}%
+ %
+ % Must explicitly reset to 0 because we call \afourpaper.
+ \globaldefs = 0
+}}
+
+ % Aggiunto formato 17x24, comunemente usato per i testi scientifici.
+\def\manuale{{\globaldefs = 1
+ \parskip = 2pt plus 1pt minus 0.1pt
+ \textleading = 12.0pt
+ %
+ \internalpagesizes{190mm}{120mm}%
+ {\voffset}{0mm}%
+ {\hoffset}{0mm}%
+ {\bindingoffset}{4.6mm}%
+ {240mm}{170mm}%
+ %
+ \lispnarrowing = 0.2in
+ \tolerance = 800
+ \hfuzz = 1.2pt
+ \contentsrightmargin = 0pt
+ \defbodyindent = 2mm
+ \tableindent = 12mm
+}}
+
+% Use @afourwide to print on A4 paper in landscape format.
+\def\afourwide{{\globaldefs = 1
+ \afourpaper
+ \internalpagesizes{241mm}{165mm}%
+ {\voffset}{-2.95mm}%
+ {\bindingoffset}{7mm}%
+ {297mm}{210mm}%
+ \globaldefs = 0
+}}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\parseargdef\pagesizes{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+ \globaldefs = 1
+ %
+ \parskip = 3pt plus 2pt minus 1pt
+ \setleading{\textleading}%
+ %
+ \dimen0 = #1\relax
+ \advance\dimen0 by \voffset
+ %
+ \dimen2 = \hsize
+ \advance\dimen2 by \normaloffset
+ %
+ \internalpagesizes{#1}{\hsize}%
+ {\voffset}{\normaloffset}%
+ {\bindingoffset}{44pt}%
+ {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+
+\message{and turning on texinfo input format.}
+
+\def^^L{\par} % remove \outer, so ^L can appear in an @comment
+
+% DEL is a comment character, in case @c does not suffice.
+\catcode`\^^? = 14
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other \def\normaldoublequote{"}
+\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix
+\catcode`\+=\other \def\normalplus{+}
+\catcode`\<=\other \def\normalless{<}
+\catcode`\>=\other \def\normalgreater{>}
+\catcode`\^=\other \def\normalcaret{^}
+\catcode`\_=\other \def\normalunderscore{_}
+\catcode`\|=\other \def\normalverticalbar{|}
+\catcode`\~=\other \def\normaltilde{~}
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font. Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts. But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Set catcodes for Texinfo file
+
+% Active characters for printing the wanted glyph.
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+%
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active \def\activetilde{{\tt\char126}} \let~ = \activetilde
+\chardef\hatchar=`\^
+\catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+\let\realunder=_
+
+\catcode`\|=\active \def|{{\tt\char124}}
+
+\chardef \less=`\<
+\catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless
+\chardef \gtr=`\>
+\catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr
+\catcode`\+=\active \def+{{\tt \char 43}}
+\catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+\catcode`\-=\active \let-=\normaldash
+
+
+% used for headline/footline in the output routine, in case the page
+% breaks in the middle of an @tex block.
+\def\texinfochars{%
+ \let< = \activeless
+ \let> = \activegtr
+ \let~ = \activetilde
+ \let^ = \activehat
+ \markupsetuplqdefault \markupsetuprqdefault
+ \let\b = \strong
+ \let\i = \smartitalic
+ % in principle, all other definitions in \tex have to be undone too.
+}
+
+% Used sometimes to turn off (effectively) the active characters even after
+% parsing them.
+\def\turnoffactive{%
+ \normalturnoffactive
+ \otherbackslash
+}
+
+\catcode`\@=0
+
+% \backslashcurfont outputs one backslash character in current font,
+% as in \char`\\.
+\global\chardef\backslashcurfont=`\\
+\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work
+
+% \realbackslash is an actual character `\' with catcode other, and
+% \doublebackslash is two of them (for the pdf outlines).
+{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}}
+
+% In Texinfo, backslash is an active character; it prints the backslash
+% in fixed width font.
+\catcode`\\=\active % @ for escape char from now on.
+
+% Print a typewriter backslash. For math mode, we can't simply use
+% \backslashcurfont: the story here is that in math mode, the \char
+% of \backslashcurfont ends up printing the roman \ from the math symbol
+% font (because \char in math mode uses the \mathcode, and plain.tex
+% sets \mathcode`\\="026E). Hence we use an explicit \mathchar,
+% which is the decimal equivalent of "715c (class 7, e.g., use \fam;
+% ignored family value; char position "5C). We can't use " for the
+% usual hex value because it has already been made active.
+
+@def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}}
+@let@backslashchar = @ttbackslash % @backslashchar{} is for user documents.
+
+% \rawbackslash defines an active \ to do \backslashcurfont.
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other. We switch back and forth between these.
+@gdef@rawbackslash{@let\=@backslashcurfont}
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.
+%
+{@catcode`- = @active
+ @gdef@normalturnoffactive{%
+ @nonasciistringdefs
+ @let-=@normaldash
+ @let"=@normaldoublequote
+ @let$=@normaldollar %$ font-lock fix
+ @let+=@normalplus
+ @let<=@normalless
+ @let>=@normalgreater
+ @let^=@normalcaret
+ @let_=@normalunderscore
+ @let|=@normalverticalbar
+ @let~=@normaltilde
+ @let\=@ttbackslash
+ @markupsetuplqdefault
+ @markupsetuprqdefault
+ @unsepspaces
+ }
+}
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have @fixbackslash turn them back on.
+@catcode`+=@other @catcode`@_=@other
+
+% \enablebackslashhack - allow file to begin `\input texinfo'
+%
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+% If the file did not have a `\input texinfo', then it is turned off after
+% the first line; otherwise the first `\' in the file would cause an error.
+% This is used on the very last line of this file, texinfo.tex.
+% We also use @c to call @fixbackslash, in case ends of lines are hidden.
+{
+@catcode`@^=7
+@catcode`@^^M=13@gdef@enablebackslashhack{%
+ @global@let\ = @eatinput%
+ @catcode`@^^M=13%
+ @def@c{@fixbackslash@c}%
+ @def ^^M{@let^^M@secondlinenl}%
+ @gdef @secondlinenl{@let^^M@thirdlinenl}%
+ @gdef @thirdlinenl{@fixbackslash}%
+}}
+
+{@catcode`@^=7 @catcode`@^^M=13%
+@gdef@eatinput input texinfo#1^^M{@fixbackslash}}
+
+% Emergency active definition of newline, in case an active newline token
+% appears by mistake.
+{@catcode`@^=7 @catcode13=13%
+@gdef@enableemergencynewline{%
+ @gdef^^M{%
+ @par%
+ %<warning: active newline>@par%
+}}}
+
+
+@gdef@fixbackslash{%
+ @ifx\@eatinput @let\ = @ttbackslash @fi
+ @catcode13=5 % regular end of line
+ @enableemergencynewline
+ @let@c=@texinfoc
+ % Also turn back on active characters that might appear in the input
+ % file name, in case not using a pre-dumped format.
+ @catcode`+=@active
+ @catcode`@_=@active
+ %
+ % If texinfo.cnf is present on the system, read it.
+ % Useful for site-wide @afourpaper, etc. This macro, @fixbackslash, gets
+ % called at the beginning of every Texinfo file. Not opening texinfo.cnf
+ % directly in this file, texinfo.tex, makes it possible to make a format
+ % file for Texinfo.
+ %
+ @openin 1 texinfo.cnf
+ @ifeof 1 @else @input texinfo.cnf @fi
+ @closein 1
+}
+
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These (along with & and #) are made active for url-breaking, so need
+% active definitions as the normal characters.
+@def@normaldot{.}
+@def@normalquest{?}
+@def@normalslash{/}
+
+% These look ok in all fonts, so just make them not special.
+% @hashchar{} gets its own user-level command, because of #line.
+@catcode`@& = @other @def@normalamp{&}
+@catcode`@# = @other @def@normalhash{#}
+@catcode`@% = @other @def@normalpercent{%}
+
+@let @hashchar = @normalhash
+
+@c Finally, make ` and ' active, so that txicodequoteundirected and
+@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we
+@c don't make ` and ' active, @code will not get them as active chars.
+@c Do this last of all since we use ` in the previous @catcode assignments.
+@catcode`@'=@active
+@catcode`@`=@active
+@markupsetuplqdefault
+@markupsetuprqdefault
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message\\|emacs-page"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@ignore
+ arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115
+@end ignore
+@enablebackslashhack
diff --git a/doc/it/txi-it.tex b/doc/it/txi-it.tex
new file mode 100644
index 00000000..ba3bf6a5
--- /dev/null
+++ b/doc/it/txi-it.tex
@@ -0,0 +1,84 @@
+% $Id: txi-it.tex 5191 2013-02-23 00:11:18Z karl $
+% txi-it.tex -- Italian translations for texinfo.tex
+%
+% Copyright 1999, 2007, 2008 Free Software Foundation.
+%
+% This program is free software; you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation; either version 3 of the License, or
+% (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+\txisetlanguage{italian}{2}{2}
+
+\plainfrenchspacing
+
+\gdef\putwordAppendix{Appendice}
+\gdef\putwordChapter{Capitolo}
+\gdef\putwordfile{file}
+\gdef\putwordin{in}
+\gdef\putwordIndexIsEmpty{(L'indice \'e vuoto)}
+\gdef\putwordIndexNonexistent{(L'indice non esiste)}
+\gdef\putwordInfo{Info}
+\gdef\putwordInstanceVariableof{Variabile di istanza di}
+\gdef\putwordMethodon{Metodo di}
+\gdef\putwordNoTitle{Nessun titolo}
+\gdef\putwordof{di}
+\gdef\putwordon{su}
+\gdef\putwordpage{pagina}
+\gdef\putwordsection{sezione}
+\gdef\putwordSection{Sezione}
+\gdef\putwordsee{si veda la}
+\gdef\putwordSee{Si veda la}
+\gdef\putwordShortTOC{Sommario abbreviato}
+\gdef\putwordTOC{Sommario}
+%
+\gdef\putwordMJan{Gennaio}
+\gdef\putwordMFeb{Febbraio}
+\gdef\putwordMMar{Marzo}
+\gdef\putwordMApr{Aprile}
+\gdef\putwordMMay{Maggio}
+\gdef\putwordMJun{Giugno}
+\gdef\putwordMJul{Luglio}
+\gdef\putwordMAug{Agosto}
+\gdef\putwordMSep{Settembre}
+\gdef\putwordMOct{Ottobre}
+\gdef\putwordMNov{Novembre}
+\gdef\putwordMDec{Dicembre}
+%
+\gdef\putwordDefmac{Macro}
+\gdef\putwordDefspec{Forma speciale}
+\gdef\putwordDefvar{Variabile}
+\gdef\putwordDefopt{Opzione}
+\gdef\putwordDeffunc{Funzione}
+
+\gdef\putwordla{la}
+\gdef\putwordLa{La}
+\gdef\putwordsivedail{si veda il}
+\gdef\putwordSivedail{Si veda il}
+% Produces article before Section names
+\def\refla#1{\putwordla{} \xrefX[#1,,,,,,,]}
+\def\refLa#1{\putwordLa{} \xrefX[#1,,,,,,,]}
+% Produces article before Chapter names
+\def\pxrefil#1{\putwordsivedail{} \xrefX[#1,,,,,,,]}
+\def\pxrefIl#1{\putwordSivedail{} \xrefX[#1,,,,,,,]}
+\def\xrefil#1{\putwordsivedail{} \xrefX[#1,,,,,,,]}
+\def\xrefIl#1{\putwordSivedail{} \xrefX[#1,,,,,,,]}
+
+% Produces Day Month Year style of output.
+\def\today{%
+ \number\day\space
+ \ifcase\month
+ \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+ \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+ \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+ \fi
+ \space\number\year}
+% ultimo aggiornamento: 19 febbraio 2015 21:11
diff --git a/doc/it/vettore-elementi.eps b/doc/it/vettore-elementi.eps
new file mode 100644
index 00000000..87979fb8
--- /dev/null
+++ b/doc/it/vettore-elementi.eps
@@ -0,0 +1,159 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Title: vettore-elementi.fig
+%%Creator: fig2dev Version 3.2 Patchlevel 5e
+%%CreationDate: Mon Feb 9 17:13:19 2015
+%%For: marco@casa1 (Marco)
+%%BoundingBox: 0 0 383 76
+%Magnification: 1.0000
+%%EndComments
+%%BeginProlog
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+/pageheader {
+save
+newpath 0 76 moveto 0 0 lineto 383 0 lineto 383 76 lineto closepath clip newpath
+-203.3 199.4 translate
+1 -1 scale
+$F2psBegin
+10 setmiterlimit
+0 slj 0 slc
+ 0.06299 0.06299 sc
+} bind def
+/pagefooter {
+$F2psEnd
+restore
+} bind def
+%%EndProlog
+pageheader
+%
+% Fig objects follow
+%
+%
+% here starts figure with depth 50
+% Polyline
+0 slj
+0 slc
+7.500 slw
+n 4455 1980 m 4455 2700 l 4455 2655 l
+ 4455 2700 l gs col0 s gr
+% Polyline
+n 6075 1980 m
+ 6075 2700 l gs col0 s gr
+% Polyline
+n 7425 1980 m
+ 7425 2700 l gs col0 s gr
+/Courier-Bold ff 190.50 scf sf
+3735 2340 m
+gs 1 -1 sc (8) col0 sh gr
+/Courier-Bold ff 190.50 scf sf
+6795 2340 m
+gs 1 -1 sc ("") col0 sh gr
+/Courier-Bold ff 190.50 scf sf
+7875 2340 m
+gs 1 -1 sc (30) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+3735 3150 m
+gs 1 -1 sc (0) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+5175 3150 m
+gs 1 -1 sc (1) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+6795 3150 m
+gs 1 -1 sc (2) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+7875 3150 m
+gs 1 -1 sc (3) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+8730 2340 m
+gs 1 -1 sc (Valore) col0 sh gr
+/Times-Roman ff 190.50 scf sf
+8730 3150 m
+gs 1 -1 sc (Indice) col0 sh gr
+/Courier-Bold ff 190.50 scf sf
+5175 2340 m
+gs 1 -1 sc ("pippo") col0 sh gr
+% here ends figure;
+%
+% here starts figure with depth 40
+% Polyline
+0 slj
+0 slc
+7.500 slw
+n 3240 1980 m 8415 1980 l 8415 2700 l 3240 2700 l
+ cp gs col0 s gr
+% here ends figure;
+pagefooter
+showpage
+%%Trailer
+%EOF
diff --git a/doc/it/vettore-elementi.fig b/doc/it/vettore-elementi.fig
new file mode 100644
index 00000000..37f3449c
--- /dev/null
+++ b/doc/it/vettore-elementi.fig
@@ -0,0 +1,27 @@
+#FIG 3.2 Produced by xfig version 3.2.5c
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 40 -1 -1 0.000 0 0 -1 0 0 5
+ 3240 1980 8415 1980 8415 2700 3240 2700 3240 1980
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+ 4455 1980 4455 2700 4455 2655 4455 2700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6075 1980 6075 2700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7425 1980 7425 2700
+4 0 0 50 -1 14 12 0.0000 4 135 90 3735 2340 8\001
+4 0 0 50 -1 14 12 0.0000 4 45 180 6795 2340 ""\001
+4 0 0 50 -1 14 12 0.0000 4 135 180 7875 2340 30\001
+4 0 0 50 -1 0 12 0.0000 4 135 90 3735 3150 0\001
+4 0 0 50 -1 0 12 0.0000 4 135 90 5175 3150 1\001
+4 0 0 50 -1 0 12 0.0000 4 135 90 6795 3150 2\001
+4 0 0 50 -1 0 12 0.0000 4 135 90 7875 3150 3\001
+4 0 0 50 -1 0 12 0.0000 4 135 540 8730 2340 Valore\001
+4 0 0 50 -1 0 12 0.0000 4 135 540 8730 3150 Indice\001
+4 0 0 50 -1 14 12 0.0000 4 165 630 5175 2340 "pippo"\001
diff --git a/doc/it/vettore-elementi.pdf b/doc/it/vettore-elementi.pdf
new file mode 100644
index 00000000..cfec8760
--- /dev/null
+++ b/doc/it/vettore-elementi.pdf
Binary files differ
diff --git a/doc/it/vettore-elementi.png b/doc/it/vettore-elementi.png
new file mode 100644
index 00000000..87ef434d
--- /dev/null
+++ b/doc/it/vettore-elementi.png
Binary files differ
diff --git a/doc/it/vettore-elementi.txt b/doc/it/vettore-elementi.txt
new file mode 100644
index 00000000..5d7efb83
--- /dev/null
+++ b/doc/it/vettore-elementi.txt
@@ -0,0 +1,4 @@
++---------+---------+--------+---------+
+| 8 | "pippo" | "" | 30 | @r{Value}
++---------+---------+--------+---------+
+ 0 1 2 3 @r{Index}
diff --git a/doc/texinfo.tex b/doc/texinfo.tex
index ddda670e..b40a6e2a 100644
--- a/doc/texinfo.tex
+++ b/doc/texinfo.tex
@@ -3,11 +3,11 @@
% Load plain if necessary, i.e., if running under initex.
\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
%
-\def\texinfoversion{2016-02-05.07}
+\def\texinfoversion{2017-06-04.19}
%
% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-% 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
+% 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
% Free Software Foundation, Inc.
%
% This texinfo.tex file is free software: you can redistribute it and/or
@@ -67,6 +67,10 @@
\everyjob{\message{[Texinfo version \texinfoversion]}%
\catcode`+=\active \catcode`\_=\active}
+% LaTeX's \typeout. This ensures that the messages it is used for
+% are identical in format to the corresponding ones from latex/pdflatex.
+\def\typeout{\immediate\write17}%
+
\chardef\other=12
% We never want plain's \outer definition of \+ in Texinfo.
@@ -161,6 +165,9 @@
% Give the space character the catcode for a space.
\def\spaceisspace{\catcode`\ =10\relax}
+% Likewise for ^^M, the end of line character.
+\def\endlineisspace{\catcode13=10\relax}
+
\chardef\dashChar = `\-
\chardef\slashChar = `\/
\chardef\underChar = `\_
@@ -310,7 +317,7 @@
% Margin to add to right of even pages, to left of odd pages.
\newdimen\bindingoffset
\newdimen\normaloffset
-\newdimen\pagewidth \newdimen\pageheight
+\newdimen\txipagewidth \newdimen\txipageheight
% Main output routine.
%
@@ -334,7 +341,7 @@
% Common context changes for both heading and footing.
% Do this outside of the \shipout so @code etc. will be expanded in
% the headline as they should be, not taken literally (outputting ''code).
- \def\commmonheadfootline{\let\hsize=\pagewidth \texinfochars}
+ \def\commmonheadfootline{\let\hsize=\txipagewidth \texinfochars}
%
% Retrieve the information for the headings from the marks in the page,
% and call Plain TeX's \makeheadline and \makefootline, which use the
@@ -433,7 +440,7 @@
\newinsert\margin \dimen\margin=\maxdimen
% Main part of page, including any footnotes
-\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+\def\pagebody#1{\vbox to\txipageheight{\boxmaxdepth=\maxdepth #1}}
{\catcode`\@ =11
\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
% marginal hacks, juha@viisa.uucp (Juha Takala)
@@ -724,11 +731,11 @@
% \dimen0 is the vertical size of the group's box.
\dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox
% \dimen2 is how much space is left on the page (more or less).
- \dimen2 = \pageheight \advance\dimen2 by -\pagetotal
+ \dimen2 = \txipageheight \advance\dimen2 by -\pagetotal
% if the group doesn't fit on the current page, and it's a big big
% group, force a page break.
\ifdim \dimen0 > \dimen2
- \ifdim \pagetotal < \vfilllimit\pageheight
+ \ifdim \pagetotal < \vfilllimit\txipageheight
\page
\fi
\fi
@@ -858,36 +865,6 @@ where each line of input produces a line of output.}
\temp
}
-% @| inserts a changebar to the left of the current line. It should
-% surround any changed text. This approach does *not* work if the
-% change spans more than two lines of output. To handle that, we would
-% have adopt a much more difficult approach (putting marks into the main
-% vertical list for the beginning and end of each change). This command
-% is not documented, not supported, and doesn't work.
-%
-\def\|{%
- % \vadjust can only be used in horizontal mode.
- \leavevmode
- %
- % Append this vertical mode material after the current line in the output.
- \vadjust{%
- % We want to insert a rule with the height and depth of the current
- % leading; that is exactly what \strutbox is supposed to record.
- \vskip-\baselineskip
- %
- % \vadjust-items are inserted at the left edge of the type. So
- % the \llap here moves out into the left-hand margin.
- \llap{%
- %
- % For a thicker or thinner bar, change the `1pt'.
- \vrule height\baselineskip width1pt
- %
- % This is the space between the bar and the text.
- \hskip 12pt
- }%
- }%
-}
-
% @include FILE -- \input text of FILE.
%
\def\include{\parseargusing\filenamecatcodes\includezzz}
@@ -976,21 +953,14 @@ where each line of input produces a line of output.}
% @comment ...line which is ignored...
% @c is the same as @comment
% @ignore ... @end ignore is another way to write a comment
-%
-\def\comment{\begingroup \catcode`\^^M=\active%
-\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other\commentxxx}%
-{\catcode`\^^M=\active%
-\gdef\commentxxx#1^^M{\endgroup%
-\futurelet\nexttoken\commentxxxx}%
-\gdef\commentxxxx{\ifx\nexttoken\aftermacro\expandafter\comment\fi}%
-}
\def\c{\begingroup \catcode`\^^M=\active%
\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
\cxxx}
{\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}}
-% See comment in \scanmacro about why the definitions of @c and @comment differ
+%
+\let\comment\c
% @paragraphindent NCHARS
% We'll use ems for NCHARS, close enough.
@@ -1100,6 +1070,86 @@ where each line of input produces a line of output.}
\newif\ifpdf
\newif\ifpdfmakepagedest
+%
+% For LuaTeX
+%
+
+\newif\iftxiuseunicodedestname
+\txiuseunicodedestnamefalse % For pdfTeX etc.
+
+\ifx\luatexversion\thisisundefined
+\else
+ % Use Unicode destination names
+ \txiuseunicodedestnametrue
+ % Escape PDF strings with converting UTF-16 from UTF-8
+ \begingroup
+ \catcode`\%=12
+ \directlua{
+ function UTF16oct(str)
+ tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377')
+ for c in string.utfvalues(str) do
+ if c < 0x10000 then
+ tex.sprint(
+ string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o',
+ (c / 256), (c % 256)))
+ else
+ c = c - 0x10000
+ local c_hi = c / 1024 + 0xd800
+ local c_lo = c % 1024 + 0xdc00
+ tex.sprint(
+ string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o',
+ (c_hi / 256), (c_hi % 256),
+ (c_lo / 256), (c_lo % 256)))
+ end
+ end
+ end
+ }
+ \endgroup
+ \def\pdfescapestrutfsixteen#1{\directlua{UTF16oct('\luaescapestring{#1}')}}
+ % Escape PDF strings without converting
+ \begingroup
+ \directlua{
+ function PDFescstr(str)
+ for c in string.bytes(str) do
+ if c <= 0x20 or c >= 0x80 or c == 0x28 or c == 0x29 or c == 0x5c then
+ tex.sprint(
+ string.format(string.char(0x5c) .. string.char(0x25) .. '03o',
+ c))
+ else
+ tex.sprint(string.char(c))
+ end
+ end
+ end
+ }
+ \endgroup
+ \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}}
+ \ifnum\luatexversion>84
+ % For LuaTeX >= 0.85
+ \def\pdfdest{\pdfextension dest}
+ \let\pdfoutput\outputmode
+ \def\pdfliteral{\pdfextension literal}
+ \def\pdfcatalog{\pdfextension catalog}
+ \def\pdftexversion{\numexpr\pdffeedback version\relax}
+ \let\pdfximage\saveimageresource
+ \let\pdfrefximage\useimageresource
+ \let\pdflastximage\lastsavedimageresourceindex
+ \def\pdfendlink{\pdfextension endlink\relax}
+ \def\pdfoutline{\pdfextension outline}
+ \def\pdfstartlink{\pdfextension startlink}
+ \def\pdffontattr{\pdfextension fontattr}
+ \def\pdfobj{\pdfextension obj}
+ \def\pdflastobj{\numexpr\pdffeedback lastobj\relax}
+ \let\pdfpagewidth\pagewidth
+ \let\pdfpageheight\pageheight
+ \edef\pdfhorigin{\pdfvariable horigin}
+ \edef\pdfvorigin{\pdfvariable vorigin}
+ \fi
+\fi
+
% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
% can be set). So we test for \relax and 0 as well as being undefined.
\ifx\pdfoutput\thisisundefined
@@ -1130,12 +1180,21 @@ where each line of input produces a line of output.}
\ifx\pdfescapestring\thisisundefined
% No primitive available; should we give a warning or log?
% Many times it won't matter.
+ \xdef#1{#1}%
\else
% The expandable \pdfescapestring primitive escapes parentheses,
% backslashes, and other special chars.
\xdef#1{\pdfescapestring{#1}}%
\fi
}
+\def\txiescapepdfutfsixteen#1{%
+ \ifx\pdfescapestrutfsixteen\thisisundefined
+ % No UTF-16 converting macro available.
+ \txiescapepdf{#1}%
+ \else
+ \xdef#1{\pdfescapestrutfsixteen{#1}}%
+ \fi
+}
\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
with PDF output, and none of those formats could be found. (.eps cannot
@@ -1245,17 +1304,77 @@ output) for that.)}
\pdfrefximage \pdflastximage
\fi}
%
- \def\pdfmkdest#1{{%
+ \def\setpdfdestname#1{{%
% We have to set dummies so commands such as @code, and characters
% such as \, aren't expanded when present in a section title.
\indexnofonts
- \turnoffactive
\makevalueexpandable
+ \turnoffactive
+ \iftxiuseunicodedestname
+ \ifx \declaredencoding \latone
+ % Pass through Latin-1 characters.
+ % LuaTeX with byte wise I/O converts Latin-1 characters to Unicode.
+ \else
+ \ifx \declaredencoding \utfeight
+ % Pass through Unicode characters.
+ \else
+ % Use ASCII approximations in destination names.
+ \passthroughcharsfalse
+ \fi
+ \fi
+ \else
+ % Use ASCII approximations in destination names.
+ \passthroughcharsfalse
+ \fi
\def\pdfdestname{#1}%
\txiescapepdf\pdfdestname
- \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
}}
%
+ \def\setpdfoutlinetext#1{{%
+ \indexnofonts
+ \makevalueexpandable
+ \turnoffactive
+ \ifx \declaredencoding \latone
+ % The PDF format can use an extended form of Latin-1 in bookmark
+ % strings. See Appendix D of the PDF Reference, Sixth Edition, for
+ % the "PDFDocEncoding".
+ \passthroughcharstrue
+ % Pass through Latin-1 characters.
+ % LuaTeX: Convert to Unicode
+ % pdfTeX: Use Latin-1 as PDFDocEncoding
+ \def\pdfoutlinetext{#1}%
+ \else
+ \ifx \declaredencoding \utfeight
+ \ifx\luatexversion\thisisundefined
+ % For pdfTeX with UTF-8.
+ % TODO: the PDF format can use UTF-16 in bookmark strings,
+ % but the code for this isn't done yet.
+ % Use ASCII approximations.
+ \passthroughcharsfalse
+ \def\pdfoutlinetext{#1}%
+ \else
+ % For LuaTeX with UTF-8.
+ % Pass through Unicode characters for title texts.
+ \passthroughcharstrue
+ \def\pdfoutlinetext{#1}%
+ \fi
+ \else
+ % For non-Latin-1 or non-UTF-8 encodings.
+ % Use ASCII approximations.
+ \passthroughcharsfalse
+ \def\pdfoutlinetext{#1}%
+ \fi
+ \fi
+ % LuaTeX: Convert to UTF-16
+ % pdfTeX: Use Latin-1 as PDFDocEncoding
+ \txiescapepdfutfsixteen\pdfoutlinetext
+ }}
+ %
+ \def\pdfmkdest#1{%
+ \setpdfdestname{#1}%
+ \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+ }
+ %
% used to mark target names; must be expandable.
\def\pdfmkpgn#1{#1}
%
@@ -1283,18 +1402,13 @@ output) for that.)}
% page number. We could generate a destination for the section
% text in the case where a section has no node, but it doesn't
% seem worth the trouble, since most documents are normally structured.
- \edef\pdfoutlinedest{#3}%
- \ifx\pdfoutlinedest\empty
- \def\pdfoutlinedest{#4}%
- \else
- \txiescapepdf\pdfoutlinedest
+ \setpdfoutlinetext{#1}
+ \setpdfdestname{#3}
+ \ifx\pdfdestname\empty
+ \def\pdfdestname{#4}%
\fi
%
- % Also escape PDF chars in the display string.
- \edef\pdfoutlinetext{#1}%
- \txiescapepdf\pdfoutlinetext
- %
- \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+ \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}%
}
%
\def\pdfmakeoutlines{%
@@ -1450,23 +1564,254 @@ output) for that.)}
\fi % \ifx\pdfoutput
%
-% @image support for XeTeX
+% For XeTeX
%
-\newif\ifxeteximgpdf
\ifx\XeTeXrevision\thisisundefined
\else
%
+ % XeTeX version check
+ %
+ \ifnum\strcmp{\the\XeTeXversion\XeTeXrevision}{0.99996}>-1
+ % TeX Live 2016 contains XeTeX 0.99996 and xdvipdfmx 20160307.
+ % It can use the `dvipdfmx:config' special (from TeX Live SVN r40941).
+ % For avoiding PDF destination name replacement, we use this special
+ % instead of xdvipdfmx's command line option `-C 0x0010'.
+ \special{dvipdfmx:config C 0x0010}
+ % XeTeX 0.99995+ comes with xdvipdfmx 20160307+.
+ % It can handle Unicode destination names for PDF.
+ \txiuseunicodedestnametrue
+ \else
+ % XeTeX < 0.99996 (TeX Live < 2016) cannot use the
+ % `dvipdfmx:config' special.
+ % So for avoiding PDF destination name replacement,
+ % xdvipdfmx's command line option `-C 0x0010' is necessary.
+ %
+ % XeTeX < 0.99995 can not handle Unicode destination names for PDF
+ % because xdvipdfmx 20150315 has a UTF-16 conversion issue.
+ % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+ \txiuseunicodedestnamefalse
+ \fi
+ %
+ % Color support
+ %
+ \def\rgbDarkRed{0.50 0.09 0.12}
+ \def\rgbBlack{0 0 0}
+ %
+ \def\pdfsetcolor#1{\special{pdf:scolor [#1]}}
+ %
+ % Set color, and create a mark which defines \thiscolor accordingly,
+ % so that \makeheadline knows which color to restore.
+ \def\setcolor#1{%
+ \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}%
+ \domark
+ \pdfsetcolor{#1}%
+ }
+ %
+ \def\maincolor{\rgbBlack}
+ \pdfsetcolor{\maincolor}
+ \edef\thiscolor{\maincolor}
+ \def\lastcolordefs{}
+ %
+ \def\makefootline{%
+ \baselineskip24pt
+ \line{\pdfsetcolor{\maincolor}\the\footline}%
+ }
+ %
+ \def\makeheadline{%
+ \vbox to 0pt{%
+ \vskip-22.5pt
+ \line{%
+ \vbox to8.5pt{}%
+ % Extract \thiscolor definition from the marks.
+ \getcolormarks
+ % Typeset the headline with \maincolor, then restore the color.
+ \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+ }%
+ \vss
+ }%
+ \nointerlineskip
+ }
+ %
+ % PDF outline support
+ %
+ % Emulate pdfTeX primitive
+ \def\pdfdest name#1 xyz{%
+ \special{pdf:dest (#1) [@thispage /XYZ @xpos @ypos null]}%
+ }
+ %
+ \def\setpdfdestname#1{{%
+ % We have to set dummies so commands such as @code, and characters
+ % such as \, aren't expanded when present in a section title.
+ \indexnofonts
+ \makevalueexpandable
+ \turnoffactive
+ \iftxiuseunicodedestname
+ % Pass through Unicode characters.
+ \else
+ % Use ASCII approximations in destination names.
+ \passthroughcharsfalse
+ \fi
+ \def\pdfdestname{#1}%
+ \txiescapepdf\pdfdestname
+ }}
+ %
+ \def\setpdfoutlinetext#1{{%
+ \turnoffactive
+ % Always use Unicode characters in title texts.
+ \def\pdfoutlinetext{#1}%
+ % For XeTeX, xdvipdfmx converts to UTF-16.
+ % So we do not convert.
+ \txiescapepdf\pdfoutlinetext
+ }}
+ %
+ \def\pdfmkdest#1{%
+ \setpdfdestname{#1}%
+ \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+ }
+ %
+ % by default, use black for everything.
+ \def\urlcolor{\rgbBlack}
+ \def\linkcolor{\rgbBlack}
+ \def\endlink{\setcolor{\maincolor}\pdfendlink}
+ %
+ \def\dopdfoutline#1#2#3#4{%
+ \setpdfoutlinetext{#1}
+ \setpdfdestname{#3}
+ \ifx\pdfdestname\empty
+ \def\pdfdestname{#4}%
+ \fi
+ %
+ \special{pdf:out [-] #2 << /Title (\pdfoutlinetext) /A
+ << /S /GoTo /D (\pdfdestname) >> >> }%
+ }
+ %
+ \def\pdfmakeoutlines{%
+ \begingroup
+ %
+ % For XeTeX, counts of subentries are not necessary.
+ % Therefore, we read toc only once.
+ %
+ % We use node names as destinations.
+ \def\partentry##1##2##3##4{}% ignore parts in the outlines
+ \def\numchapentry##1##2##3##4{%
+ \dopdfoutline{##1}{1}{##3}{##4}}%
+ \def\numsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{2}{##3}{##4}}%
+ \def\numsubsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{3}{##3}{##4}}%
+ \def\numsubsubsecentry##1##2##3##4{%
+ \dopdfoutline{##1}{4}{##3}{##4}}%
+ %
+ \let\appentry\numchapentry%
+ \let\appsecentry\numsecentry%
+ \let\appsubsecentry\numsubsecentry%
+ \let\appsubsubsecentry\numsubsubsecentry%
+ \let\unnchapentry\numchapentry%
+ \let\unnsecentry\numsecentry%
+ \let\unnsubsecentry\numsubsecentry%
+ \let\unnsubsubsecentry\numsubsubsecentry%
+ %
+ % For XeTeX, xdvipdfmx converts strings to UTF-16.
+ % Therefore, the encoding and the language may not be considered.
+ %
+ \indexnofonts
+ \setupdatafile
+ % We can have normal brace characters in the PDF outlines, unlike
+ % Texinfo index files. So set that up.
+ \def\{{\lbracecharliteral}%
+ \def\}{\rbracecharliteral}%
+ \catcode`\\=\active \otherbackslash
+ \input \tocreadfilename
+ \endgroup
+ }
+ {\catcode`[=1 \catcode`]=2
+ \catcode`{=\other \catcode`}=\other
+ \gdef\lbracecharliteral[{]%
+ \gdef\rbracecharliteral[}]%
+ ]
+
+ \special{pdf:docview << /PageMode /UseOutlines >> }
+ % ``\special{pdf:tounicode ...}'' is not necessary
+ % because xdvipdfmx converts strings from UTF-8 to UTF-16 without it.
+ % However, due to a UTF-16 conversion issue of xdvipdfmx 20150315,
+ % ``\special{pdf:dest ...}'' cannot handle non-ASCII strings.
+ % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+%
+ \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+ \ifx\PP\D\let\nextsp\relax
+ \else\let\nextsp\skipspaces
+ \addtokens{\filename}{\PP}%
+ \advance\filenamelength by 1
+ \fi
+ \nextsp}
+ \def\getfilename#1{%
+ \filenamelength=0
+ % If we don't expand the argument now, \skipspaces will get
+ % snagged on things like "@value{foo}".
+ \edef\temp{#1}%
+ \expandafter\skipspaces\temp|\relax
+ }
+ % make a live url in pdf output.
+ \def\pdfurl#1{%
+ \begingroup
+ % it seems we really need yet another set of dummies; have not
+ % tried to figure out what each command should do in the context
+ % of @url. for now, just make @/ a no-op, that's the only one
+ % people have actually reported a problem with.
+ %
+ \normalturnoffactive
+ \def\@{@}%
+ \let\/=\empty
+ \makevalueexpandable
+ % do we want to go so far as to use \indexnofonts instead of just
+ % special-casing \var here?
+ \def\var##1{##1}%
+ %
+ \leavevmode\setcolor{\urlcolor}%
+ \special{pdf:bann << /Border [0 0 0]
+ /Subtype /Link /A << /S /URI /URI (#1) >> >>}%
+ \endgroup}
+ \def\endlink{\setcolor{\maincolor}\special{pdf:eann}}
+ \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+ \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+ \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+ \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+ \def\maketoks{%
+ \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+ \ifx\first0\adn0
+ \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+ \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+ \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+ \else
+ \ifnum0=\countA\else\makelink\fi
+ \ifx\first.\let\next=\done\else
+ \let\next=\maketoks
+ \addtokens{\toksB}{\the\toksD}
+ \ifx\first,\addtokens{\toksB}{\space}\fi
+ \fi
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \next}
+ \def\makelink{\addtokens{\toksB}%
+ {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+ \def\pdflink#1{%
+ \special{pdf:bann << /Border [0 0 0]
+ /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}%
+ \setcolor{\linkcolor}#1\endlink}
+ \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+%
+ %
+ % @image support
+ %
% #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
\def\doxeteximage#1#2#3{%
\def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
\def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
%
- % XeTeX (and the PDF format) support .pdf, .png, .jpg (among
+ % XeTeX (and the PDF format) supports .pdf, .png, .jpg (among
% others). Let's try in that order, PDF first since if
% someone has a scalable image, presumably better to use that than a
% bitmap.
\let\xeteximgext=\empty
- \xeteximgpdffalse
\begingroup
\openin 1 #1.pdf \ifeof 1
\openin 1 #1.PDF \ifeof 1
@@ -1483,57 +1828,32 @@ output) for that.)}
\fi
\else \gdef\xeteximgext{png}%
\fi
- \else \gdef\xeteximgext{PDF} \global\xeteximgpdftrue%
+ \else \gdef\xeteximgext{PDF}%
\fi
- \else \gdef\xeteximgext{pdf} \global\xeteximgpdftrue%
+ \else \gdef\xeteximgext{pdf}%
\fi
\closein 1
\endgroup
%
- \ifxeteximgpdf
+ \def\xetexpdfext{pdf}%
+ \ifx\xeteximgext\xetexpdfext
\XeTeXpdffile "#1".\xeteximgext ""
\else
- \XeTeXpicfile "#1".\xeteximgext ""
+ \def\xetexpdfext{PDF}%
+ \ifx\xeteximgext\xetexpdfext
+ \XeTeXpdffile "#1".\xeteximgext ""
+ \else
+ \XeTeXpicfile "#1".\xeteximgext ""
+ \fi
\fi
\ifdim \wd0 >0pt width \xeteximagewidth \fi
\ifdim \wd2 >0pt height \xeteximageheight \fi \relax
}
\fi
-\message{fonts,}
-
-% Change the current font style to #1, remembering it in \curfontstyle.
-% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
-% italics, not bold italics.
-%
-\def\setfontstyle#1{%
- \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
- \csname ten#1\endcsname % change the current font
-}
-% Select #1 fonts with the current style.
%
-\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname}
-
-\def\rm{\fam=0 \setfontstyle{rm}}
-\def\it{\fam=\itfam \setfontstyle{it}}
-\def\sl{\fam=\slfam \setfontstyle{sl}}
-\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
-\def\tt{\fam=\ttfam \setfontstyle{tt}}
-
-% Unfortunately, we have to override this for titles and the like, since
-% in those cases "rm" is bold. Sigh.
-\def\rmisbold{\rm\def\curfontstyle{bf}}
-
-% Texinfo sort of supports the sans serif font style, which plain TeX does not.
-% So we set up a \sf.
-\newfam\sffam
-\def\sf{\fam=\sffam \setfontstyle{sf}}
-\let\li = \sf % Sometimes we call it \li, not \sf.
-
-% We don't need math for this font style.
-\def\ttsl{\setfontstyle{ttsl}}
-
+\message{fonts,}
% Set the baselineskip to #1, and the lineskip and strut size
% correspondingly. There is no deep meaning behind these magic numbers
@@ -1884,8 +2204,8 @@ end
\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
\setfont\defsl\slshape{10}{\magstep1}{OT1TT}
\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
-\def\df{\let\tentt=\deftt \let\tenbf = \defbf
-\let\tenttsl=\defttsl \let\tensl=\defsl \bf}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\ttslfont=\defttsl \let\slfont=\defsl \bf}
% Fonts for indices, footnotes, small examples (9pt).
\def\smallnominalsize{9pt}
@@ -1972,7 +2292,7 @@ end
\font\ssecsy=cmsy10 scaled 1315
\def\ssececsize{1200}
-% Reduced fonts for @acro in text (10pt).
+% Reduced fonts for @acronym in text (10pt).
\def\reducednominalsize{10pt}
\setfont\reducedrm\rmshape{10}{1000}{OT1}
\setfont\reducedtt\ttshape{10}{1000}{OT1TT}
@@ -2018,8 +2338,8 @@ end
\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
\setfont\defsl\slshape{10}{\magstephalf}{OT1TT}
\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
-\def\df{\let\tentt=\deftt \let\tenbf = \defbf
-\let\tensl=\defsl \let\tenttsl=\defttsl \bf}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\slfont=\defsl \let\ttslfont=\defttsl \bf}
% Fonts for indices, footnotes, small examples (9pt).
\def\smallnominalsize{9pt}
@@ -2105,7 +2425,7 @@ end
\font\ssecsy=cmsy10
\def\ssececsize{1000}
-% Reduced fonts for @acro in text (9pt).
+% Reduced fonts for @acronym in text (9pt).
\def\reducednominalsize{9pt}
\setfont\reducedrm\rmshape{9}{1000}{OT1}
\setfont\reducedtt\ttshape{9}{1000}{OT1TT}
@@ -2125,6 +2445,12 @@ end
\rm
} % end of 10pt text font size definitions, \definetextfontsizex
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}{OT1}
+\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}{OT1}
+\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+
% We provide the user-level command
% @fonttextsize 10
@@ -2151,20 +2477,47 @@ end
\endgroup
}
+%
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+ \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+ \csname #1font\endcsname % change the current font
+}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
% In order for the font changes to affect most math symbols and letters,
% we have to define the \textfont of the standard families. We don't
% bother to reset \scriptfont and \scriptscriptfont; awaiting user need.
%
\def\resetmathfonts{%
- \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy
- \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf
- \textfont\ttfam=\tentt \textfont\sffam=\tensf
+ \textfont0=\rmfont \textfont1=\ifont \textfont2=\syfont
+ \textfont\itfam=\itfont \textfont\slfam=\slfont \textfont\bffam=\bffont
+ \textfont\ttfam=\ttfont \textfont\sffam=\sffont
}
-% The font-changing commands redefine the meanings of \tenSTYLE, instead
-% of just \STYLE. We do this because \STYLE needs to also set the
-% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire
-% \tenSTYLE to set the current font.
+%
+
+% The font-changing commands (all called \...fonts) redefine the meanings
+% of \STYLEfont, instead of just \STYLE. We do this because \STYLE needs
+% to also set the current \fam for math mode. Our \STYLE (e.g., \rm)
+% commands hardwire \STYLEfont to set the current font.
%
% Each font-changing command also sets the names \lsize (one size lower)
% and \lllsize (three sizes lower). These relative commands are used
@@ -2172,78 +2525,63 @@ end
%
% This all needs generalizing, badly.
%
-\def\textfonts{%
- \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
- \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
- \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
- \let\tenttsl=\textttsl
- \def\curfontsize{text}%
- \def\lsize{reduced}\def\lllsize{smaller}%
- \resetmathfonts \setleading{\textleading}}
-\def\titlefonts{%
- \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
- \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
- \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
- \let\tenttsl=\titlettsl
- \def\curfontsize{title}%
- \def\lsize{chap}\def\lllsize{subsec}%
- \resetmathfonts \setleading{27pt}}
-\def\titlefont#1{{\titlefonts\rmisbold #1}}
-\def\chapfonts{%
- \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
- \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
- \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
- \let\tenttsl=\chapttsl
- \def\curfontsize{chap}%
- \def\lsize{sec}\def\lllsize{text}%
- \resetmathfonts \setleading{19pt}}
-\def\secfonts{%
- \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
- \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
- \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
- \let\tenttsl=\secttsl
- \def\curfontsize{sec}%
- \def\lsize{subsec}\def\lllsize{reduced}%
- \resetmathfonts \setleading{17pt}}
-\def\subsecfonts{%
- \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
- \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
- \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
- \let\tenttsl=\ssecttsl
- \def\curfontsize{ssec}%
- \def\lsize{text}\def\lllsize{small}%
- \resetmathfonts \setleading{15pt}}
-\let\subsubsecfonts = \subsecfonts
-\def\reducedfonts{%
- \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl
- \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc
- \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy
- \let\tenttsl=\reducedttsl
- \def\curfontsize{reduced}%
- \def\lsize{small}\def\lllsize{smaller}%
- \resetmathfonts \setleading{10.5pt}}
-\def\smallfonts{%
- \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl
- \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc
- \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy
- \let\tenttsl=\smallttsl
- \def\curfontsize{small}%
- \def\lsize{smaller}\def\lllsize{smaller}%
- \resetmathfonts \setleading{10.5pt}}
-\def\smallerfonts{%
- \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl
- \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc
- \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy
- \let\tenttsl=\smallerttsl
- \def\curfontsize{smaller}%
- \def\lsize{smaller}\def\lllsize{smaller}%
- \resetmathfonts \setleading{9.5pt}}
-% Fonts for short table of contents.
-\setfont\shortcontrm\rmshape{12}{1000}{OT1}
-\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12
-\setfont\shortcontsl\slshape{12}{1000}{OT1}
-\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+\def\assignfonts#1{%
+ \expandafter\let\expandafter\rmfont\csname #1rm\endcsname
+ \expandafter\let\expandafter\itfont\csname #1it\endcsname
+ \expandafter\let\expandafter\slfont\csname #1sl\endcsname
+ \expandafter\let\expandafter\bffont\csname #1bf\endcsname
+ \expandafter\let\expandafter\ttfont\csname #1tt\endcsname
+ \expandafter\let\expandafter\smallcaps\csname #1sc\endcsname
+ \expandafter\let\expandafter\sffont \csname #1sf\endcsname
+ \expandafter\let\expandafter\ifont \csname #1i\endcsname
+ \expandafter\let\expandafter\syfont \csname #1sy\endcsname
+ \expandafter\let\expandafter\ttslfont\csname #1ttsl\endcsname
+}
+
+\newif\ifrmisbold
+
+% Select smaller font size with the current style. Used to change font size
+% in, e.g., the LaTeX logo and acronyms. If we are using bold fonts for
+% normal roman text, also use bold fonts for roman text in the smaller size.
+\def\switchtolllsize{%
+ \expandafter\assignfonts\expandafter{\lllsize}%
+ \ifrmisbold
+ \let\rmfont\bffont
+ \fi
+ \csname\curfontstyle\endcsname
+}%
+
+\def\switchtolsize{%
+ \expandafter\assignfonts\expandafter{\lsize}%
+ \ifrmisbold
+ \let\rmfont\bffont
+ \fi
+ \csname\curfontstyle\endcsname
+}%
+
+\def\definefontsetatsize#1#2#3#4#5{%
+\expandafter\def\csname #1fonts\endcsname{%
+ \def\curfontsize{#1}%
+ \def\lsize{#2}\def\lllsize{#3}%
+ \csname rmisbold#5\endcsname
+ \assignfonts{#1}%
+ \resetmathfonts
+ \setleading{#4}%
+}}
+
+\definefontsetatsize{text} {reduced}{smaller}{\textleading}{false}
+\definefontsetatsize{title} {chap} {subsec} {27pt} {true}
+\definefontsetatsize{chap} {sec} {text} {19pt} {true}
+\definefontsetatsize{sec} {subsec} {reduced}{17pt} {true}
+\definefontsetatsize{ssec} {text} {small} {15pt} {true}
+\definefontsetatsize{reduced}{small} {smaller}{10.5pt}{false}
+\definefontsetatsize{small} {smaller}{smaller}{10.5pt}{false}
+\definefontsetatsize{smaller}{smaller}{smaller}{9.5pt} {false}
+
+\def\titlefont#1{{\titlefonts\rm #1}}
+\let\subsecfonts = \ssecfonts
+\let\subsubsecfonts = \ssecfonts
% Define these just so they can be easily changed for other fonts.
\def\angleleft{$\langle$}
@@ -2659,6 +2997,7 @@ end
\setbox0 = \hbox{\ignorespaces #2}% look for second arg
\ifdim\wd0 > 0pt
\ifpdf
+ % For pdfTeX and LuaTeX
\ifurefurlonlylink
% PDF plus option to not display url, show just arg
\unhbox0
@@ -2668,7 +3007,19 @@ end
\unhbox0\ (\urefcode{#1})%
\fi
\else
- \unhbox0\ (\urefcode{#1})% DVI, always show arg and url
+ \ifx\XeTeXrevision\thisisundefined
+ \unhbox0\ (\urefcode{#1})% DVI, always show arg and url
+ \else
+ % For XeTeX
+ \ifurefurlonlylink
+ % PDF plus option to not display url, show just arg
+ \unhbox0
+ \else
+ % PDF, normally display both arg and url for consistency,
+ % visibility, if the pdf is eventually used to print, etc.
+ \unhbox0\ (\urefcode{#1})%
+ \fi
+ \fi
\fi
\else
\urefcode{#1}% only url given, so show it
@@ -2769,7 +3120,18 @@ end
\endlink
\endgroup}
\else
- \let\email=\uref
+ \ifx\XeTeXrevision\thisisundefined
+ \let\email=\uref
+ \else
+ \def\email#1{\doemail#1,,\finish}
+ \def\doemail#1,#2,#3\finish{\begingroup
+ \unsepspaces
+ \pdfurl{mailto:#1}%
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+ \endlink
+ \endgroup}
+ \fi
\fi
% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
@@ -2844,7 +3206,7 @@ end
%
\def\acronym#1{\doacronym #1,,\finish}
\def\doacronym#1,#2,#3\finish{%
- {\selectfonts\lsize #1}%
+ {\switchtolsize #1}%
\def\temp{#2}%
\ifx\temp\empty \else
\space ({\unsepspaces \ignorespaces \temp \unskip})%
@@ -2937,10 +3299,10 @@ end
% fix it (significant additions to font machinery) until someone notices.
%
\def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi}
-\def\finishsub#1{$\sb{\hbox{\selectfonts\lllsize #1}}$}%
+\def\finishsub#1{$\sb{\hbox{\switchtolllsize #1}}$}%
%
\def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi}
-\def\finishsup#1{$\ptexsp{\hbox{\selectfonts\lllsize #1}}$}%
+\def\finishsup#1{$\ptexsp{\hbox{\switchtolllsize #1}}$}%
% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
@@ -3004,23 +3366,10 @@ end
\let\atchar=\@
% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
-% Unless we're in typewriter, use \ecfont because the CM text fonts do
-% not have braces, and we don't want to switch into math.
-\def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}}
-\def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}}
-\let\{=\mylbrace \let\lbracechar=\{
-\let\}=\myrbrace \let\rbracechar=\}
-\begingroup
- % Definitions to produce \{ and \} commands for indices,
- % and @{ and @} for the aux/toc files.
- \catcode`\{ = \other \catcode`\} = \other
- \catcode`\[ = 1 \catcode`\] = 2
- \catcode`\! = 0 \catcode`\\ = \other
- !gdef!lbracecmd[\{]%
- !gdef!rbracecmd[\}]%
- !gdef!lbraceatcmd[@{]%
- !gdef!rbraceatcmd[@}]%
-!endgroup
+\def\lbracechar{{\ifmonospace\char123\else\ensuremath\lbrace\fi}}
+\def\rbracechar{{\ifmonospace\char125\else\ensuremath\rbrace\fi}}
+\let\{=\lbracechar
+\let\}=\rbracechar
% @comma{} to avoid , parsing problems.
\let\comma = ,
@@ -3038,8 +3387,8 @@ end
% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
\def\questiondown{?`}
\def\exclamdown{!`}
-\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}}
-\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}}
+\def\ordf{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{o}}}
% Dotless i and dotless j, used for accents.
\def\imacro{i}
@@ -3068,12 +3417,12 @@ end
{\setbox0=\hbox{T}%
\vbox to \ht0{\hbox{%
\ifx\textnominalsize\xwordpt
- % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX.
+ % for 10pt running text, lllsize (8pt) is too small for the A in LaTeX.
% Revert to plain's \scriptsize, which is 7pt.
\count255=\the\fam $\fam\count255 \scriptstyle A$%
\else
% For 11pt, we can use our lllsize.
- \selectfonts\lllsize A%
+ \switchtolllsize A%
\fi
}%
\vss
@@ -3139,7 +3488,7 @@ end
%
\newbox\errorbox
%
-{\tentt \global\dimen0 = 3em}% Width of the box.
+{\ttfont \global\dimen0 = 3em}% Width of the box.
\dimen2 = .55pt % Thickness of rules
% The text. (`r' is open on the right, `e' somewhat less so on the left.)
\setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt}
@@ -3290,7 +3639,7 @@ end
% Adapted from the plain.tex definition of \copyright.
%
\def\registeredsymbol{%
- $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}%
+ $^{{\ooalign{\hfil\raise.07ex\hbox{\switchtolllsize R}%
\hfil\crcr\Orb}}%
}$%
}
@@ -3323,13 +3672,16 @@ end
\newif\ifseenauthor
\newif\iffinishedtitlepage
-% Do an implicit @contents or @shortcontents after @end titlepage if the
-% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
-%
-\newif\ifsetcontentsaftertitlepage
- \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
-\newif\ifsetshortcontentsaftertitlepage
- \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+% @setcontentsaftertitlepage used to do an implicit @contents or
+% @shortcontents after @end titlepage, but it is now obsolete.
+\def\setcontentsaftertitlepage{%
+ \errmessage{@setcontentsaftertitlepage has been removed as a Texinfo
+ command; move your @contents command if you want the contents
+ after the title page.}}%
+\def\setshortcontentsaftertitlepage{%
+ \errmessage{@setshortcontentsaftertitlepage has been removed as a Texinfo
+ command; move your @shortcontents and @contents commands if you
+ want the contents after the title page.}}%
\parseargdef\shorttitlepage{%
\begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}%
@@ -3371,20 +3723,6 @@ end
% Need this before the \...aftertitlepage checks so that if they are
% in effect the toc pages will come out with page numbers.
\HEADINGSon
- %
- % If they want short, they certainly want long too.
- \ifsetshortcontentsaftertitlepage
- \shortcontents
- \contents
- \global\let\shortcontents = \relax
- \global\let\contents = \relax
- \fi
- %
- \ifsetcontentsaftertitlepage
- \contents
- \global\let\contents = \relax
- \global\let\shortcontents = \relax
- \fi
}
\def\finishtitlepage{%
@@ -3395,12 +3733,11 @@ end
% Settings used for typesetting titles: no hyphenation, no indentation,
% don't worry much about spacing, ragged right. This should be used
-% inside a \vbox, and fonts need to be set appropriately first. Because
-% it is always used for titles, nothing else, we call \rmisbold. \par
-% should be specified before the end of the \vbox, since a vbox is a group.
+% inside a \vbox, and fonts need to be set appropriately first. \par should
+% be specified before the end of the \vbox, since a vbox is a group.
%
\def\raggedtitlesettings{%
- \rmisbold
+ \rm
\hyphenpenalty=10000
\parindent=0pt
\tolerance=5000
@@ -3409,7 +3746,7 @@ end
% Macros to be used within @titlepage:
-\let\subtitlerm=\tenrm
+\let\subtitlerm=\rmfont
\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
\parseargdef\title{%
@@ -3435,7 +3772,7 @@ end
\else
\checkenv\titlepage
\ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
- {\secfonts\rmisbold \leftline{#1}}%
+ {\secfonts\rm \leftline{#1}}%
\fi
}
@@ -3488,7 +3825,7 @@ end
%
% Leave some space for the footline. Hopefully ok to assume
% @evenfooting will not be used by itself.
- \global\advance\pageheight by -12pt
+ \global\advance\txipageheight by -12pt
\global\advance\vsize by -12pt
}
@@ -3513,9 +3850,9 @@ end
\def\oddheadingmarks{\headingmarks{odd}{heading}}
\def\evenfootingmarks{\headingmarks{even}{footing}}
\def\oddfootingmarks{\headingmarks{odd}{footing}}
-\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1}
+\parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1}
\headingmarks{odd}{heading}{#1} }
-\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1}
+\parseargdef\everyfootingmarks{\headingmarks{even}{footing}{#1}
\headingmarks{odd}{footing}{#1} }
% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
\def\headingmarks#1#2#3 {%
@@ -3536,7 +3873,7 @@ end
% By default, they are off at the start of a document,
% and turned `on' after @end titlepage.
-\def\headings #1 {\csname HEADINGS#1\endcsname}
+\parseargdef\headings{\csname HEADINGS#1\endcsname}
\def\headingsoff{% non-global headings elimination
\evenheadline={\hfil}\evenfootline={\hfil}%
@@ -4350,6 +4687,31 @@ end
\fi
}
+% Like \expandablevalue, but completely expandable (the \message in the
+% definition above operates at the execution level of TeX). Used when
+% writing to auxiliary files, due to the expansion that \write does.
+% If flag is undefined, pass through an unexpanded @value command: maybe it
+% will be set by the time it is read back in.
+%
+% NB flag names containing - or _ may not work here.
+\def\dummyvalue#1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \noexpand\value{#1}%
+ \else
+ \csname SET#1\endcsname
+ \fi
+}
+
+% Used for @value's in index entries to form the sort key: expand the @value
+% if possible, otherwise sort late.
+\def\indexnofontsvalue#1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ ZZZZZZZ
+ \else
+ \csname SET#1\endcsname
+ \fi
+}
+
% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
% with @set.
%
@@ -4474,14 +4836,7 @@ end
% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
% #3 the target index (bar).
\def\dosynindex#1#2#3{%
- % Only do \closeout if we haven't already done it, else we'll end up
- % closing the target index.
- \expandafter \ifx\csname donesynindex#2\endcsname \relax
- % The \closeout helps reduce unnecessary open files; the limit on the
- % Acorn RISC OS is a mere 16 files.
- \expandafter\closeout\csname#2indfile\endcsname
- \expandafter\let\csname donesynindex#2\endcsname = 1
- \fi
+ \requireopenindexfile{#3}%
% redefine \fooindfile:
\expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
\expandafter\let\csname#2indfile\endcsname=\temp
@@ -4491,7 +4846,7 @@ end
% Define \doindex, the driver for all index macros.
% Argument #1 is generated by the calling \fooindex macro,
-% and it the two-letter name of the index.
+% and it is the two-letter name of the index.
\def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx}
\def\doindexxxx #1{\doind{\indexname}{#1}}
@@ -4500,63 +4855,61 @@ end
\def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx}
\def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}}
-% Used when writing an index entry out to an index file, to prevent
+
+% Used when writing an index entry out to an index file to prevent
% expansion of Texinfo commands that can appear in an index entry.
%
\def\indexdummies{%
\escapechar = `\\ % use backslash in output files.
- \def\@{@}% change to @@ when we switch to @ as escape char in index files.
- \def\ {\realbackslash\space }%
- %
- % Need these unexpandable (because we define \tt as a dummy)
- % definitions when @{ or @} appear in index entry text. Also, more
- % complicated, when \tex is in effect and \{ is a \delimiter again.
- % We can't use \lbracecmd and \rbracecmd because texindex assumes
- % braces and backslashes are used only as delimiters. Perhaps we
- % should use @lbracechar and @rbracechar?
- \def\{{{\tt\char123}}%
- \def\}{{\tt\char125}}%
+ \definedummyletter\@%
+ \definedummyletter\ %
+ %
+ % For texindex which always views { and } as separators.
+ \def\{{\lbracechar{}}%
+ \def\}{\rbracechar{}}%
%
% Do the redefinitions.
- \commondummies
+ \definedummies
}
-% For the aux and toc files, @ is the escape character. So we want to
-% redefine everything using @ as the escape character (instead of
-% \realbackslash, still used for index files). When everything uses @,
-% this will be simpler.
+% Used for the aux and toc files, where @ is the escape character.
%
\def\atdummies{%
- \def\@{@@}%
- \def\ {@ }%
- \let\{ = \lbraceatcmd
- \let\} = \rbraceatcmd
+ \definedummyletter\@%
+ \definedummyletter\ %
+ \definedummyletter\{%
+ \definedummyletter\}%
%
% Do the redefinitions.
- \commondummies
+ \definedummies
\otherbackslash
}
-% Called from \indexdummies and \atdummies.
+% \definedummyword defines \#1 as \string\#1\space, thus effectively
+% preventing its expansion. This is used only for control words,
+% not control letters, because the \space would be incorrect for
+% control characters, but is needed to separate the control word
+% from whatever follows.
%
-\def\commondummies{%
- % \definedummyword defines \#1 as \string\#1\space, thus effectively
- % preventing its expansion. This is used only for control words,
- % not control letters, because the \space would be incorrect for
- % control characters, but is needed to separate the control word
- % from whatever follows.
- %
- % For control letters, we have \definedummyletter, which omits the
- % space.
- %
- % These can be used both for control words that take an argument and
- % those that do not. If it is followed by {arg} in the input, then
- % that will dutifully get written to the index (or wherever).
- %
- \def\definedummyword ##1{\def##1{\string##1\space}}%
- \def\definedummyletter##1{\def##1{\string##1}}%
- \let\definedummyaccent\definedummyletter
+% These can be used both for control words that take an argument and
+% those that do not. If it is followed by {arg} in the input, then
+% that will dutifully get written to the index (or wherever).
+%
+% For control letters, we have \definedummyletter, which omits the
+% space.
+%
+\def\definedummyword #1{\def#1{\string#1\space}}%
+\def\definedummyletter#1{\def#1{\string#1}}%
+\let\definedummyaccent\definedummyletter
+
+% Called from \indexdummies and \atdummies, to effectively prevent
+% the expansion of commands.
+%
+\def\definedummies{%
%
+ \let\commondummyword\definedummyword
+ \let\commondummyletter\definedummyletter
+ \let\commondummyaccent\definedummyaccent
\commondummiesnofonts
%
\definedummyletter\_%
@@ -4597,6 +4950,7 @@ end
\definedummyword\TeX
%
% Assorted special characters.
+ \definedummyword\atchar
\definedummyword\arrow
\definedummyword\bullet
\definedummyword\comma
@@ -4636,85 +4990,82 @@ end
%
% We want to disable all macros so that they are not expanded by \write.
\macrolist
+ \let\value\dummyvalue
%
\normalturnoffactive
- %
- % Handle some cases of @value -- where it does not contain any
- % (non-fully-expandable) commands.
- \makevalueexpandable
}
-% \commondummiesnofonts: common to \commondummies and \indexnofonts.
-% Define \definedumyletter, \definedummyaccent and \definedummyword before
-% using.
+% \commondummiesnofonts: common to \definedummies and \indexnofonts.
+% Define \commondummyletter, \commondummyaccent and \commondummyword before
+% using. Used for accents, font commands, and various control letters.
%
\def\commondummiesnofonts{%
% Control letters and accents.
- \definedummyletter\!%
- \definedummyaccent\"%
- \definedummyaccent\'%
- \definedummyletter\*%
- \definedummyaccent\,%
- \definedummyletter\.%
- \definedummyletter\/%
- \definedummyletter\:%
- \definedummyaccent\=%
- \definedummyletter\?%
- \definedummyaccent\^%
- \definedummyaccent\`%
- \definedummyaccent\~%
- \definedummyword\u
- \definedummyword\v
- \definedummyword\H
- \definedummyword\dotaccent
- \definedummyword\ogonek
- \definedummyword\ringaccent
- \definedummyword\tieaccent
- \definedummyword\ubaraccent
- \definedummyword\udotaccent
- \definedummyword\dotless
+ \commondummyletter\!%
+ \commondummyaccent\"%
+ \commondummyaccent\'%
+ \commondummyletter\*%
+ \commondummyaccent\,%
+ \commondummyletter\.%
+ \commondummyletter\/%
+ \commondummyletter\:%
+ \commondummyaccent\=%
+ \commondummyletter\?%
+ \commondummyaccent\^%
+ \commondummyaccent\`%
+ \commondummyaccent\~%
+ \commondummyword\u
+ \commondummyword\v
+ \commondummyword\H
+ \commondummyword\dotaccent
+ \commondummyword\ogonek
+ \commondummyword\ringaccent
+ \commondummyword\tieaccent
+ \commondummyword\ubaraccent
+ \commondummyword\udotaccent
+ \commondummyword\dotless
%
% Texinfo font commands.
- \definedummyword\b
- \definedummyword\i
- \definedummyword\r
- \definedummyword\sansserif
- \definedummyword\sc
- \definedummyword\slanted
- \definedummyword\t
+ \commondummyword\b
+ \commondummyword\i
+ \commondummyword\r
+ \commondummyword\sansserif
+ \commondummyword\sc
+ \commondummyword\slanted
+ \commondummyword\t
%
% Commands that take arguments.
- \definedummyword\abbr
- \definedummyword\acronym
- \definedummyword\anchor
- \definedummyword\cite
- \definedummyword\code
- \definedummyword\command
- \definedummyword\dfn
- \definedummyword\dmn
- \definedummyword\email
- \definedummyword\emph
- \definedummyword\env
- \definedummyword\file
- \definedummyword\image
- \definedummyword\indicateurl
- \definedummyword\inforef
- \definedummyword\kbd
- \definedummyword\key
- \definedummyword\math
- \definedummyword\option
- \definedummyword\pxref
- \definedummyword\ref
- \definedummyword\samp
- \definedummyword\strong
- \definedummyword\tie
- \definedummyword\U
- \definedummyword\uref
- \definedummyword\url
- \definedummyword\var
- \definedummyword\verb
- \definedummyword\w
- \definedummyword\xref
+ \commondummyword\abbr
+ \commondummyword\acronym
+ \commondummyword\anchor
+ \commondummyword\cite
+ \commondummyword\code
+ \commondummyword\command
+ \commondummyword\dfn
+ \commondummyword\dmn
+ \commondummyword\email
+ \commondummyword\emph
+ \commondummyword\env
+ \commondummyword\file
+ \commondummyword\image
+ \commondummyword\indicateurl
+ \commondummyword\inforef
+ \commondummyword\kbd
+ \commondummyword\key
+ \commondummyword\math
+ \commondummyword\option
+ \commondummyword\pxref
+ \commondummyword\ref
+ \commondummyword\samp
+ \commondummyword\strong
+ \commondummyword\tie
+ \commondummyword\U
+ \commondummyword\uref
+ \commondummyword\url
+ \commondummyword\var
+ \commondummyword\verb
+ \commondummyword\w
+ \commondummyword\xref
}
% For testing: output @{ and @} in index sort strings as \{ and \}.
@@ -4770,11 +5121,11 @@ end
%
\def\indexnofonts{%
% Accent commands should become @asis.
- \def\definedummyaccent##1{\let##1\asis}%
+ \def\commondummyaccent##1{\let##1\asis}%
% We can just ignore other control letters.
- \def\definedummyletter##1{\let##1\empty}%
+ \def\commondummyletter##1{\let##1\empty}%
% All control words become @asis by default; overrides below.
- \let\definedummyword\definedummyaccent
+ \let\commondummyword\commondummyaccent
\commondummiesnofonts
%
% Don't no-op \tt, since it isn't a user-level command
@@ -4816,37 +5167,40 @@ end
\def\LaTeX{LaTeX}%
\def\TeX{TeX}%
%
- % Assorted special characters.
- % (The following {} will end up in the sort string, but that's ok.)
- \def\arrow{->}%
- \def\bullet{bullet}%
- \def\comma{,}%
- \def\copyright{copyright}%
- \def\dots{...}%
- \def\enddots{...}%
- \def\equiv{==}%
- \def\error{error}%
- \def\euro{euro}%
- \def\expansion{==>}%
- \def\geq{>=}%
- \def\guillemetleft{<<}%
- \def\guillemetright{>>}%
- \def\guilsinglleft{<}%
- \def\guilsinglright{>}%
- \def\leq{<=}%
- \def\minus{-}%
- \def\point{.}%
- \def\pounds{pounds}%
- \def\print{-|}%
- \def\quotedblbase{"}%
- \def\quotedblleft{"}%
- \def\quotedblright{"}%
- \def\quoteleft{`}%
- \def\quoteright{'}%
- \def\quotesinglbase{,}%
- \def\registeredsymbol{R}%
- \def\result{=>}%
- \def\textdegree{o}%
+ % Assorted special characters. \defglyph gives the control sequence a
+ % definition that removes the {} that follows its use.
+ \defglyph\atchar{@}%
+ \defglyph\arrow{->}%
+ \defglyph\bullet{bullet}%
+ \defglyph\comma{,}%
+ \defglyph\copyright{copyright}%
+ \defglyph\dots{...}%
+ \defglyph\enddots{...}%
+ \defglyph\equiv{==}%
+ \defglyph\error{error}%
+ \defglyph\euro{euro}%
+ \defglyph\expansion{==>}%
+ \defglyph\geq{>=}%
+ \defglyph\guillemetleft{<<}%
+ \defglyph\guillemetright{>>}%
+ \defglyph\guilsinglleft{<}%
+ \defglyph\guilsinglright{>}%
+ \defglyph\leq{<=}%
+ \defglyph\lbracechar{\{}%
+ \defglyph\minus{-}%
+ \defglyph\point{.}%
+ \defglyph\pounds{pounds}%
+ \defglyph\print{-|}%
+ \defglyph\quotedblbase{"}%
+ \defglyph\quotedblleft{"}%
+ \defglyph\quotedblright{"}%
+ \defglyph\quoteleft{`}%
+ \defglyph\quoteright{'}%
+ \defglyph\quotesinglbase{,}%
+ \defglyph\rbracechar{\}}%
+ \defglyph\registeredsymbol{R}%
+ \defglyph\result{=>}%
+ \defglyph\textdegree{o}%
%
% We need to get rid of all macros, leaving only the arguments (if present).
% Of course this is not nearly correct, but it is the best we can do for now.
@@ -4859,7 +5213,11 @@ end
% goes to end-of-line is not handled.
%
\macrolist
+ \let\value\indexnofontsvalue
}
+\def\defglyph#1#2{\def#1##1{#2}} % see above
+
+
\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
@@ -4906,9 +5264,10 @@ end
\ifx\suffix\indexisfl\def\suffix{f1}\fi
% Open the file
\immediate\openout\csname#1indfile\endcsname \jobname.\suffix
- % Using \immediate here prevents an object entering into the current box,
- % which could confound checks such as those in \safewhatsit for preceding
- % skips.
+ % Using \immediate above here prevents an object entering into the current
+ % box, which could confound checks such as those in \safewhatsit for
+ % preceding skips.
+ \typeout{Writing index file \jobname.\suffix}%
\fi}
\def\indexisfl{fl}
@@ -5106,7 +5465,7 @@ end
% \initial {@}
% as its first line, TeX doesn't complain about mismatched braces
% (because it thinks @} is a control sequence).
- \catcode`\@ = 11
+ \catcode`\@ = 12
% See comment in \requireopenindexfile.
\def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi
\openin 1 \jobname.\indexname s
@@ -5116,9 +5475,9 @@ end
% index. The easiest way to prevent this problem is to make sure
% there is some text.
\putwordIndexNonexistent
+ \typeout{No file \jobname.\indexname s.}%
\else
\catcode`\\ = 0
- \escapechar = `\\
%
% If the index file exists but is empty, then \openin leaves \ifeof
% false. We have to make TeX try to read something from the file, so
@@ -5134,17 +5493,15 @@ end
\let\indexlbrace\{ % Likewise, set these sequences for braces
\let\indexrbrace\} % used in the sort key.
\begindoublecolumns
- \let\entryorphanpenalty=\indexorphanpenalty
+ \let\dotheinsertentrybox\dotheinsertentryboxwithpenalty
%
% Read input from the index file line by line.
\loopdo
- \ifeof1
- \let\firsttoken\relax
- \else
+ \ifeof1 \else
\read 1 to \nextline
- \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}%
- \act
\fi
+ %
+ \indexinputprocessing
\thisline
%
\ifeof1\else
@@ -5156,12 +5513,20 @@ end
\fi
\closein 1
\endgroup}
+\def\loopdo#1\repeat{\def\body{#1}\loopdoxxx}
+\def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next}
+\def\indexinputprocessing{%
+ \ifeof1
+ \let\firsttoken\relax
+ \else
+ \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}%
+ \act
+ \fi
+}
\def\getfirsttoken#1{\expandafter\getfirsttokenx#1\endfirsttoken}
\long\def\getfirsttokenx#1#2\endfirsttoken{\noexpand#1}
-\def\loopdo#1\repeat{\def\body{#1}\loopdoxxx}
-\def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next}
% These macros are used by the sorted index file itself.
% Change them to control the appearance of the index.
@@ -5235,6 +5600,12 @@ end
\def\entry{%
\begingroup
%
+ % For pdfTeX and XeTeX.
+ % The redefinition of \domark stops marks being added in \pdflink to
+ % preserve coloured links across page boundaries. Otherwise the marks
+ % would get in the way of \lastbox in \insertentrybox.
+ \let\domark\relax
+ %
% Start a new paragraph if necessary, so our assignments below can't
% affect previous text.
\par
@@ -5248,10 +5619,6 @@ end
\def\*{\unskip\space\ignorespaces}%
\def\entrybreak{\hfil\break}% An undocumented command
%
- % A bit of stretch before each entry for the benefit of balancing
- % columns.
- \vskip 0pt plus0.5pt
- %
% Swallow the left brace of the text (first parameter):
\afterassignment\doentry
\let\temp =
@@ -5285,26 +5652,25 @@ end
%
\ifpdf
\pdfgettoks#1.%
- \bgroup\let\domark\relax
- \hskip\skip\thinshrinkable\the\toksA
- \egroup
- % The redefinion of \domark stops marks being added in \pdflink to
- % preserve coloured links across page boundaries. Otherwise the marks
- % would get in the way of \lastbox in \insertindexentrybox.
+ \hskip\skip\thinshrinkable\the\toksA
\else
- \hskip\skip\thinshrinkable #1%
+ \ifx\XeTeXrevision\thisisundefined
+ \hskip\skip\thinshrinkable #1%
+ \else
+ \pdfgettoks#1.%
+ \hskip\skip\thinshrinkable\the\toksA
+ \fi
\fi
\fi
\egroup % end \boxA
\ifdim\wd\boxB = 0pt
- \global\setbox\entryindexbox=\vbox{\unhbox\boxA}%
+ \global\setbox\entrybox=\vbox{\unhbox\boxA}%
\else
- \global\setbox\entryindexbox=\vbox\bgroup
- \prevdepth=\entrylinedepth
- \noindent
+ \global\setbox\entrybox=\vbox\bgroup
% We want the text of the entries to be aligned to the left, and the
% page numbers to be aligned to the right.
%
+ \parindent = 0pt
\advance\leftskip by 0pt plus 1fil
\advance\leftskip by 0pt plus -1fill
\rightskip = 0pt plus -1fil
@@ -5313,8 +5679,6 @@ end
% if the list of page numbers is long, to be aligned to the right.
\parfillskip=0pt plus -1fill
%
- \hangindent=1em
- %
\advance\rightskip by \entryrightmargin
% Determine how far we can stretch into the margin.
% This allows, e.g., "Appendix H GNU Free Documentation License" to
@@ -5334,17 +5698,21 @@ end
\ifdim\dimen@ > 0.8\dimen@ii % due to long index text
\dimen@ = 0.7\dimen@ % Try to split the text roughly evenly
\dimen@ii = \hsize
- \advance \dimen@ii by -1em
\ifnum\dimen@>\dimen@ii
% If the entry is too long, use the whole line
\dimen@ = \dimen@ii
\fi
\advance\leftskip by 0pt plus 1fill % ragged right
\advance \dimen@ by 1\rightskip
- \parshape = 2 0pt \dimen@ 1em \dimen@ii
- % Ideally we'd add a finite glue at the end of the first line only, but
- % TeX doesn't seem to provide a way to do such a thing.
+ \parshape = 2 0pt \dimen@ 0em \dimen@ii
+ % Ideally we'd add a finite glue at the end of the first line only,
+ % instead of using \parshape with explicit line lengths, but TeX
+ % doesn't seem to provide a way to do such a thing.
+ %
+ \leftskip = 1em
+ \parindent = -1em
\fi\fi
+ \indent % start paragraph
\unhbox\boxA
%
% Do not prefer a separate line ending with a hyphen to fewer lines.
@@ -5360,53 +5728,54 @@ end
\egroup % The \vbox
\fi
\endgroup
- % delay text of entry until after penalty
- \bgroup\aftergroup\insertindexentrybox
- \entryorphanpenalty
+ \dotheinsertentrybox
}}
\newskip\thinshrinkable
\skip\thinshrinkable=.15em minus .15em
-\newbox\entryindexbox
-\def\insertindexentrybox{%
- \copy\entryindexbox
- % The following gets the depth of the last box. This is for even
- % line spacing when entries span several lines.
- \setbox\dummybox\vbox{%
- \unvbox\entryindexbox
- \nointerlineskip
- \lastbox
- \global\entrylinedepth=\prevdepth
- }%
- % Note that we couldn't simply \unvbox\entryindexbox followed by
- % \nointerlineskip\lastbox to remove the last box and then reinstate it,
- % because this resets how far the box has been \moveleft'ed to 0. \unvbox
- % doesn't affect \prevdepth either.
+\newbox\entrybox
+\def\insertentrybox{%
+ \ourunvbox\entrybox
}
-\newdimen\entrylinedepth
-% Default is no penalty
-\let\entryorphanpenalty\egroup
+% default definition
+\let\dotheinsertentrybox\insertentrybox
+
+% Use \lastbox to take apart vbox box by box, and add each sub-box
+% to the current vertical list.
+\def\ourunvbox#1{%
+\bgroup % for local binding of \delayedbox
+ % Remove the last box from box #1
+ \global\setbox#1=\vbox{%
+ \unvbox#1%
+ \unskip % remove any glue
+ \unpenalty
+ \global\setbox\interbox=\lastbox
+ }%
+ \setbox\delayedbox=\box\interbox
+ \ifdim\ht#1=0pt\else
+ \ourunvbox#1 % Repeat on what's left of the box
+ \nobreak
+ \fi
+ \box\delayedbox
+\egroup
+}
+\newbox\delayedbox
+\newbox\interbox
% Used from \printindex. \firsttoken should be the first token
% after the \entry. If it's not another \entry, we are at the last
% line of a group of index entries, so insert a penalty to discourage
-% orphaned index entries.
-\long\def\indexorphanpenalty{%
- \def\isentry{\entry}%
+% widowed index entries.
+\def\dotheinsertentryboxwithpenalty{%
\ifx\firsttoken\isentry
\else
- \unskip\penalty 9000
- % The \unskip here stops breaking before the glue. It relies on the
- % \vskip above being there, otherwise there is an error
- % "You can't use `\unskip' in vertical mode". There has to be glue
- % in the current vertical list that hasn't been added to the
- % "current page". See Chapter 24 of the TeXbook. This contradicts
- % Section 8.3.7 in "TeX by Topic," though.
+ \penalty 9000
\fi
- \egroup % now comes the box added with \aftergroup
+ \insertentrybox
}
+\def\isentry{\entry}%
% Like plain.tex's \dotfill, except uses up at least 1 em.
% The filll stretch here overpowers both the fil and fill stretch to push
@@ -5427,7 +5796,11 @@ end
\ifpdf
\pdfgettoks#2.\ \the\toksA % The page number ends the paragraph.
\else
- #2
+ \ifx\XeTeXrevision\thisisundefined
+ #2
+ \else
+ \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph.
+ \fi
\fi
\par
}}
@@ -5439,8 +5812,6 @@ end
\newbox\partialpage
\newdimen\doublecolumnhsize
-\newdimen\doublecolumntopgap
-\doublecolumntopgap = 0pt
% Use inside an output routine to save \topmark and \firstmark
\def\savemarks{%
@@ -5521,14 +5892,12 @@ end
\divide\doublecolumnhsize by 2
\hsize = \doublecolumnhsize
%
- % Double the \vsize as well. (We don't need a separate register here,
- % since nobody clobbers \vsize.)
- \global\doublecolumntopgap = \topskip
- \global\advance\doublecolumntopgap by -1\baselineskip
- \advance\vsize by -1\doublecolumntopgap
+ % Double the \vsize as well.
+ \advance\vsize by -\ht\partialpage
\vsize = 2\vsize
- \topskip=0pt
- \global\entrylinedepth=0pt\relax
+ %
+ % For the benefit of balancing columns
+ \advance\baselineskip by 0pt plus 0.5pt
}
% The double-column output routine for all double-column pages except
@@ -5542,12 +5911,12 @@ end
% previous page.
\dimen@ = \vsize
\divide\dimen@ by 2
- \advance\dimen@ by -\ht\partialpage
%
% box0 will be the left-hand column, box2 the right.
- \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \setbox0=\vsplit\PAGE to\dimen@ \setbox2=\vsplit\PAGE to\dimen@
+ \global\advance\vsize by 2\ht\partialpage
\onepageout\pagesofar
- \unvbox255
+ \unvbox\PAGE
\penalty\outputpenalty
}
%
@@ -5558,9 +5927,7 @@ end
%
\hsize = \doublecolumnhsize
\wd0=\hsize \wd2=\hsize
- \vbox{%
- \vskip\doublecolumntopgap
- \hbox to\pagewidth{\box0\hfil\box2}}%
+ \hbox to\txipagewidth{\box0\hfil\box2}%
}
@@ -5587,7 +5954,7 @@ end
% goal. When TeX sees \eject from below which follows the final
% section, it invokes the new output routine that we've set after
% \balancecolumns below; \onepageout will try to fit the two columns
- % and the final section into the vbox of \pageheight (see
+ % and the final section into the vbox of \txipageheight (see
% \pagebody), causing an overfull box.
%
% Note that glue won't work here, because glue does not exercise the
@@ -5613,9 +5980,9 @@ end
%
% \pagegoal was set to the doubled \vsize above, since we restarted
% the current page. We're now back to normal single-column
- % typesetting, so reset \pagegoal to the normal \vsize (after the
- % \endgroup where \vsize got restored).
- \pagegoal = \vsize
+ % typesetting, so reset \pagegoal to the normal \vsize.
+ \global\vsize = \txipageheight %
+ \pagegoal = \txipageheight %
}
\newbox\balancedcolumns
\setbox\balancedcolumns=\vbox{shouldnt see this}%
@@ -5623,42 +5990,49 @@ end
% Only called for the last of the double column material. \doublecolumnout
% does the others.
\def\balancecolumns{%
- \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+ \setbox0 = \vbox{\unvbox\PAGE}% like \box255 but more efficient, see p.120.
\dimen@ = \ht0
\advance\dimen@ by \topskip
\advance\dimen@ by-\baselineskip
- \ifdim\dimen@<14\baselineskip
+ \ifdim\dimen@<5\baselineskip
% Don't split a short final column in two.
\setbox2=\vbox{}%
\else
\divide\dimen@ by 2 % target to split to
\dimen@ii = \dimen@
\splittopskip = \topskip
- % Loop until the second column is no higher than the first
+ % Loop until left column is at least as high as the right column.
{%
\vbadness = 10000
\loop
\global\setbox3 = \copy0
\global\setbox1 = \vsplit3 to \dimen@
- % Remove glue from bottom of first column to
- % make sure it is higher than the second.
- \global\setbox1 = \vbox{\unvbox1\unpenalty\unskip}%
- \ifdim\ht3>\ht1
+ \ifdim\ht1<\ht3
\global\advance\dimen@ by 1pt
\repeat
}%
- \multiply\dimen@ii by 4
- \divide\dimen@ii by 5
- \ifdim\ht3<\dimen@ii
- % Column heights are too different, so don't make their bottoms
- % flush with each other. The glue at the end of the second column
- % allows a second column to stretch, reducing the difference in
- % height between the two.
- \setbox0=\vbox to\dimen@{\unvbox1\vfill}%
- \setbox2=\vbox to\dimen@{\unvbox3\vskip 0pt plus 0.3\ht0}%
+ % Now the left column is in box 1, and the right column in box 3.
+ % Check whether the left column has come out higher than the page itself.
+ % (Note that we have doubled \vsize for the double columns, so
+ % the actual height of the page is 0.5\vsize).
+ \ifdim2\ht1>\vsize
+ % Just split the last of the double column material roughly in half.
+ \setbox2=\box0
+ \setbox0 = \vsplit2 to \dimen@ii
+ \setbox0=\vbox to \dimen@ii {\unvbox0\vfill}%
+ \setbox2=\vbox to \dimen@ii {\unvbox2\vfill}%
\else
- \setbox0=\vbox to\dimen@{\unvbox1}%
- \setbox2=\vbox to\dimen@{\unvbox3}%
+ % Compare the heights of the two columns.
+ \ifdim4\ht1>5\ht3
+ % Column heights are too different, so don't make their bottoms
+ % flush with each other.
+ \setbox2=\vbox to \ht1 {\unvbox3\vfill}%
+ \setbox0=\vbox to \ht1 {\unvbox1\vfill}%
+ \else
+ % Make column bottoms flush with each other.
+ \setbox2=\vbox to\ht1{\unvbox3\unskip}%
+ \setbox0=\vbox to\ht1{\unvbox1\unskip}%
+ \fi
\fi
\fi
%
@@ -5677,7 +6051,7 @@ end
\null
\vskip.3\vsize % move it down on the page a bit
\begingroup
- \noindent \titlefonts\rmisbold #1\par % the text
+ \noindent \titlefonts\rm #1\par % the text
\let\lastnode=\empty % no node to associate with
\writetocentry{part}{#1}{}% but put it in the toc
\headingsoff % no headline or footline on the part page
@@ -6071,7 +6445,7 @@ end
\fi
}
-\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname}
\def\CHAPPAGoff{%
\global\let\contentsalignmacro = \chappager
@@ -6163,7 +6537,7 @@ end
\domark
%
{%
- \chapfonts \rmisbold
+ \chapfonts \rm
\let\footnote=\errfootnoteheading % give better error message
%
% Have to define \lastsection before calling \donoderef, because the
@@ -6217,30 +6591,6 @@ end
}
-% I don't think this chapter style is supported any more, so I'm not
-% updating it with the new noderef stuff. We'll see. --karl, 11aug03.
-%
-\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
-%
-\def\unnchfopen #1{%
- \chapoddpage
- \vbox{\chapfonts \raggedtitlesettings #1\par}%
- \nobreak\bigskip\nobreak
-}
-\def\chfopen #1#2{\chapoddpage {\chapfonts
-\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
-\par\penalty 5000 %
-}
-\def\centerchfopen #1{%
- \chapoddpage
- \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}%
- \nobreak\bigskip \nobreak
-}
-\def\CHAPFopen{%
- \global\let\chapmacro=\chfopen
- \global\let\centerchapmacro=\centerchfopen}
-
-
% Section titles. These macros combine the section number parts and
% call the generic \sectionheading to do the printing.
%
@@ -6279,7 +6629,7 @@ end
\let\footnote=\errfootnoteheading
%
% Switch to the right set of fonts.
- \csname #2fonts\endcsname \rmisbold
+ \csname #2fonts\endcsname \rm
%
% Insert first mark before the heading break (see notes for \domark).
\let\prevsectiondefs=\lastsectiondefs
@@ -6443,7 +6793,14 @@ end
% 1 and 2 (the page numbers aren't printed), and so are the first
% two pages of the document. Thus, we'd have two destinations named
% `1', and two named `2'.
- \ifpdf \global\pdfmakepagedesttrue \fi
+ \ifpdf
+ \global\pdfmakepagedesttrue
+ \else
+ \ifx\XeTeXrevision\thisisundefined
+ \else
+ \global\pdfmakepagedesttrue
+ \fi
+ \fi
}
@@ -6703,7 +7060,6 @@ end
\catcode `\>=\other
\catcode `\`=\other
\catcode `\'=\other
- \escapechar=`\\
%
% ' is active in math mode (mathcode"8000). So reset it, and all our
% other math active characters (just in case), to plain's definitions.
@@ -7546,7 +7902,7 @@ end
\fi % no return type
#3% output function name
}%
- {\rm\enskip}% hskip 0.5 em of \tenrm
+ {\rm\enskip}% hskip 0.5 em of \rmfont
%
\boldbrax
% arguments will be output next, if any.
@@ -7675,43 +8031,41 @@ end
}
\fi
-\let\aftermacroxxx\relax
-\def\aftermacro{\aftermacroxxx}
-
% alias because \c means cedilla in @tex or @math
\let\texinfoc=\c
+\newcount\savedcatcodeone
+\newcount\savedcatcodetwo
+
% Used at the time of macro expansion.
% Argument is macro body with arguments substituted
\def\scanmacro#1{%
\newlinechar`\^^M
- \def\xprocessmacroarg{\eatspaces}%
+ \def\xeatspaces{\eatspaces}%
+ %
+ % Temporarily undo catcode changes of \printindex. Set catcode of @ to
+ % 0 so that @-commands in macro expansions aren't printed literally when
+ % formatting an index file, where \ is used as the escape character.
+ \savedcatcodeone=\catcode`\@
+ \savedcatcodetwo=\catcode`\\
+ \catcode`\@=0
+ \catcode`\\=\active
%
% Process the macro body under the current catcode regime.
- \scantokens{#1\texinfoc}\aftermacro%
+ \scantokens{#1@texinfoc}%
%
- % The \c is to remove the \newlinechar added by \scantokens, and
+ \catcode`\@=\savedcatcodeone
+ \catcode`\\=\savedcatcodetwo
+ %
+ % The \texinfoc is to remove the \newlinechar added by \scantokens, and
% can be noticed by \parsearg.
- % The \aftermacro allows a \comment at the end of the macro definition
- % to duplicate itself past the final \newlinechar added by \scantokens:
- % this is used in the definition of \group to comment out a newline. We
- % don't do the same for \c to support Texinfo files with macros that ended
- % with a @c, which should no longer be necessary.
% We avoid surrounding the call to \scantokens with \bgroup and \egroup
% to allow macros to open or close groups themselves.
}
% Used for copying and captions
\def\scanexp#1{%
- \bgroup
- % Undo catcode changes of \startcontents and \printindex
- % When called from @insertcopying or (short)caption, we need active
- % backslash to get it printed correctly.
- % FIXME: This may not be needed.
- %\catcode`\@=0 \catcode`\\=\active \escapechar=`\@
- \edef\temp{\noexpand\scanmacro{#1}}%
- \temp
- \egroup
+ \expandafter\scanmacro\expandafter{#1}%
}
\newcount\paramno % Count of parameters
@@ -7719,7 +8073,7 @@ end
\newif\ifrecursive % Is it recursive?
% List of all defined macros in the form
-% \definedummyword\macro1\definedummyword\macro2...
+% \commondummyword\macro1\commondummyword\macro2...
% Currently is also contains all @aliases; the list can be split
% if there is a need.
\def\macrolist{}
@@ -7727,7 +8081,7 @@ end
% Add the macro to \macrolist
\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname}
\def\addtomacrolistxxx#1{%
- \toks0 = \expandafter{\macrolist\definedummyword#1}%
+ \toks0 = \expandafter{\macrolist\commondummyword#1}%
\xdef\macrolist{\the\toks0}%
}
@@ -7781,7 +8135,7 @@ end
\catcode`\_=\other
\catcode`\|=\other
\catcode`\~=\other
- \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi
+ \passthroughcharstrue
}
\def\scanargctxt{% used for copying and captions, not macros.
@@ -7868,7 +8222,7 @@ end
% Remove the macro name from \macrolist:
\begingroup
\expandafter\let\csname#1\endcsname \relax
- \let\definedummyword\unmacrodo
+ \let\commondummyword\unmacrodo
\xdef\macrolist{\macrolist}%
\endgroup
\else
@@ -7883,7 +8237,7 @@ end
\ifx #1\relax
% remove this
\else
- \noexpand\definedummyword \noexpand#1%
+ \noexpand\commondummyword \noexpand#1%
\fi
}
@@ -7915,7 +8269,7 @@ end
\paramno=0\def\paramlist{}%
\let\hash\relax
% \hash is redefined to `#' later to get it into definitions
- \let\processmacroarg\relax
+ \let\xeatspaces\relax
\parsemargdefxxx#1,;,%
\ifnum\paramno<10\relax\else
\paramno0\relax
@@ -7927,7 +8281,7 @@ end
\else \let\next=\parsemargdefxxx
\advance\paramno by 1
\expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
- {\processmacroarg{\hash\the\paramno}}%
+ {\xeatspaces{\hash\the\paramno}}%
\edef\paramlist{\paramlist\hash\the\paramno,}%
\fi\next}
@@ -8153,128 +8507,75 @@ end
%%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%%
-
-% Remove following spaces at the expansion stage.
-% This works because spaces are discarded before each argument when TeX is
-% getting the arguments for a macro.
-% This must not be immediately followed by a }.
-\long\def\gobblespaces#1{#1}
-
% This defines a Texinfo @macro or @rmacro, called by \parsemacbody.
% \macrobody has the body of the macro in it, with placeholders for
-% its parameters, looking like "\processmacroarg{\hash 1}".
+% its parameters, looking like "\xeatspaces{\hash 1}".
% \paramno is the number of parameters
% \paramlist is a TeX parameter text, e.g. "#1,#2,#3,"
-% There are eight cases: recursive and nonrecursive macros of zero, one,
-% up to nine, and many arguments.
+% There are four cases: macros of zero, one, up to nine, and many arguments.
% \xdef is used so that macro definitions will survive the file
% they're defined in: @include reads the file inside a group.
%
\def\defmacro{%
\let\hash=##% convert placeholders to macro parameter chars
\ifnum\paramno=1
- \def\processmacroarg{\gobblespaces}%
+ \def\xeatspaces##1{##1}%
% This removes the pair of braces around the argument. We don't
% use \eatspaces, because this can cause ends of lines to be lost
% when the argument to \eatspaces is read, leading to line-based
% commands like "@itemize" not being read correctly.
\else
- \def\processmacroarg{\xprocessmacroarg}%
- \let\xprocessmacroarg\relax
+ \let\xeatspaces\relax % suppress expansion
\fi
- \ifrecursive %%%%%%%%%%%%%% Recursive %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \ifcase\paramno
- % 0
- \expandafter\xdef\csname\the\macname\endcsname{%
- \noexpand\scanmacro{\macrobody}}%
- \or % 1
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup
+ \noexpand\spaceisspace
+ \noexpand\endlineisspace
+ \noexpand\expandafter % skip any whitespace after the macro name.
+ \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@@\endcsname{%
+ \egroup
+ \noexpand\scanmacro{\macrobody}}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+ \egroup
+ \noexpand\scanmacro{\macrobody}%
+ }%
+ \else % at most 9
+ \ifnum\paramno<10\relax
+ % @MACNAME sets the context for reading the macro argument
+ % @MACNAME@@ gets the argument, processes backslashes and appends a
+ % comma.
+ % @MACNAME@@@ removes braces surrounding the argument list.
+ % @MACNAME@@@@ scans the macro body with arguments substituted.
\expandafter\xdef\csname\the\macname\endcsname{%
- \bgroup
- \noexpand\braceorline
- \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+ \bgroup
+ \noexpand\expandafter % This \expandafter skip any spaces after the
+ \noexpand\macroargctxt % macro before we change the catcode of space.
+ \noexpand\expandafter
+ \expandafter\noexpand\csname\the\macname @@\endcsname}%
+ \expandafter\xdef\csname\the\macname @@\endcsname##1{%
+ \noexpand\passargtomacro
+ \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
\expandafter\xdef\csname\the\macname @@@\endcsname##1{%
- \expandafter\noexpand\csname\the\macname @@@@\endcsname{%
- \noexpand\gobblespaces##1\empty}%
- % The \empty is for \gobblespaces in case #1 is empty
- }%
- \expandafter\xdef\csname\the\macname @@@@\endcsname##1{%
- \egroup\noexpand\scanmacro{\macrobody}}%
- \else
- \ifnum\paramno<10\relax % at most 9
- % See non-recursive section below for comments
- \expandafter\xdef\csname\the\macname\endcsname{%
- \bgroup
- \noexpand\expandafter
- \noexpand\macroargctxt
- \noexpand\expandafter
- \expandafter\noexpand\csname\the\macname @@\endcsname}%
- \expandafter\xdef\csname\the\macname @@\endcsname##1{%
- \noexpand\passargtomacro
- \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
- \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
- \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
- \expandafter\expandafter
- \expandafter\xdef
- \expandafter\expandafter
- \csname\the\macname @@@@\endcsname\paramlist{%
- \egroup\noexpand\scanmacro{\macrobody}}%
- \else % 10 or more
- \expandafter\xdef\csname\the\macname\endcsname{%
- \noexpand\getargvals@{\the\macname}{\argl}%
- }%
- \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
- \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
- \fi
- \fi
- \else %%%%%%%%%%%%%%%%%%%%%% Non-recursive %%%%%%%%%%%%%%%%%%%%%%%%%%
- \ifcase\paramno
- % 0
+ \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname @@@@\endcsname\paramlist{%
+ \egroup\noexpand\scanmacro{\macrobody}}%
+ \else % 10 or more:
\expandafter\xdef\csname\the\macname\endcsname{%
- \noexpand\scanmacro{\macrobody}}%
- \or % 1
- \expandafter\xdef\csname\the\macname\endcsname{%
- \bgroup
- \noexpand\braceorline
- \expandafter\noexpand\csname\the\macname @@@\endcsname}%
- \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
- \expandafter\noexpand\csname\the\macname @@@@\endcsname{%
- \noexpand\gobblespaces##1\empty}%
- % The \empty is for \gobblespaces in case #1 is empty
- }%
- \expandafter\xdef\csname\the\macname @@@@\endcsname##1{%
- \egroup
- \noexpand\scanmacro{\macrobody}%
- }%
- \else % at most 9
- \ifnum\paramno<10\relax
- % @MACNAME sets the context for reading the macro argument
- % @MACNAME@@ gets the argument, processes backslashes and appends a
- % comma.
- % @MACNAME@@@ removes braces surrounding the argument list.
- % @MACNAME@@@@ scans the macro body with arguments substituted.
- \expandafter\xdef\csname\the\macname\endcsname{%
- \bgroup
- \noexpand\expandafter % This \expandafter skip any spaces after the
- \noexpand\macroargctxt % macro before we change the catcode of space.
- \noexpand\expandafter
- \expandafter\noexpand\csname\the\macname @@\endcsname}%
- \expandafter\xdef\csname\the\macname @@\endcsname##1{%
- \noexpand\passargtomacro
- \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
- \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
- \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
- \expandafter\expandafter
- \expandafter\xdef
- \expandafter\expandafter
- \csname\the\macname @@@@\endcsname\paramlist{%
- \egroup\noexpand\scanmacro{\macrobody}}%
- \else % 10 or more:
- \expandafter\xdef\csname\the\macname\endcsname{%
- \noexpand\getargvals@{\the\macname}{\argl}%
- }%
- \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
- \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse
- \fi
+ \noexpand\getargvals@{\the\macname}{\argl}%
+ }%
+ \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
+ \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
\fi
\fi}
@@ -8470,6 +8771,8 @@ end
{%
\requireauxfile
\atdummies % preserve commands, but don't expand them
+ % match definition in \xrdef, \refx, \xrefX.
+ \def\value##1{##1}%
\edef\writexrdef##1##2{%
\write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
##1}{##2}}% these are parameters of \writexrdef
@@ -8560,9 +8863,10 @@ end
%
% Make link in pdf output.
\ifpdf
+ % For pdfTeX and LuaTeX
{\indexnofonts
- \turnoffactive
\makevalueexpandable
+ \turnoffactive
% This expands tokens, so do it after making catcode changes, so _
% etc. don't get their TeX definitions. This ignores all spaces in
% #4, including (wrongly) those in the middle of the filename.
@@ -8570,28 +8874,67 @@ end
%
% This (wrongly) does not take account of leading or trailing
% spaces in #1, which should be ignored.
- \edef\pdfxrefdest{#1}%
- \ifx\pdfxrefdest\empty
- \def\pdfxrefdest{Top}% no empty targets
- \else
- \txiescapepdf\pdfxrefdest % escape PDF special chars
+ \setpdfdestname{#1}%
+ %
+ \ifx\pdfdestname\empty
+ \def\pdfdestname{Top}% no empty targets
\fi
%
\leavevmode
\startlink attr{/Border [0 0 0]}%
\ifnum\filenamelength>0
- goto file{\the\filename.pdf} name{\pdfxrefdest}%
+ goto file{\the\filename.pdf} name{\pdfdestname}%
\else
- goto name{\pdfmkpgn{\pdfxrefdest}}%
+ goto name{\pdfmkpgn{\pdfdestname}}%
\fi
}%
\setcolor{\linkcolor}%
+ \else
+ \ifx\XeTeXrevision\thisisundefined
+ \else
+ % For XeTeX
+ {\indexnofonts
+ \makevalueexpandable
+ \turnoffactive
+ % This expands tokens, so do it after making catcode changes, so _
+ % etc. don't get their TeX definitions. This ignores all spaces in
+ % #4, including (wrongly) those in the middle of the filename.
+ \getfilename{#4}%
+ %
+ % This (wrongly) does not take account of leading or trailing
+ % spaces in #1, which should be ignored.
+ \setpdfdestname{#1}%
+ %
+ \ifx\pdfdestname\empty
+ \def\pdfdestname{Top}% no empty targets
+ \fi
+ %
+ \leavevmode
+ \ifnum\filenamelength>0
+ % With default settings,
+ % XeTeX (xdvipdfmx) replaces link destination names with integers.
+ % In this case, the replaced destination names of
+ % remote PDFs are no longer known. In order to avoid a replacement,
+ % you can use xdvipdfmx's command line option `-C 0x0010'.
+ % If you use XeTeX 0.99996+ (TeX Live 2016+),
+ % this command line option is no longer necessary
+ % because we can use the `dvipdfmx:config' special.
+ \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+ << /S /GoToR /F (\the\filename.pdf) /D (\pdfdestname) >> >>}%
+ \else
+ \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+ << /S /GoTo /D (\pdfdestname) >> >>}%
+ \fi
+ }%
+ \setcolor{\linkcolor}%
+ \fi
\fi
{%
% Have to otherify everything special to allow the \csname to
% include an _ in the xref name, etc.
\indexnofonts
\turnoffactive
+ \def\value##1{##1}%
\expandafter\global\expandafter\let\expandafter\Xthisreftitle
\csname XR#1-title\endcsname
}%
@@ -8732,14 +9075,14 @@ end
\fi\fi\fi
}
-% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
-% If its value is nonempty, SUFFIX is output afterward.
-%
+% \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME. SUFFIX
+% is output afterwards if non-empty.
\def\refx#1#2{%
\requireauxfile
{%
\indexnofonts
\otherbackslash
+ \def\value##1{##1}%
\expandafter\global\expandafter\let\expandafter\thisrefX
\csname XR#1\endcsname
}%
@@ -8764,20 +9107,28 @@ end
#2% Output the suffix in any case.
}
-% This is the macro invoked by entries in the aux file. Usually it's
-% just a \def (we prepend XR to the control sequence name to avoid
-% collisions). But if this is a float type, we have more work to do.
+% This is the macro invoked by entries in the aux file. Define a control
+% sequence for a cross-reference target (we prepend XR to the control sequence
+% name to avoid collisions). The value is the page number. If this is a float
+% type, we have more work to do.
%
\def\xrdef#1#2{%
- {% The node name might contain 8-bit characters, which in our current
- % implementation are changed to commands like @'e. Don't let these
- % mess up the control sequence name.
+ {% Expand the node or anchor name to remove control sequences.
+ % \turnoffactive stops 8-bit characters being changed to commands
+ % like @'e. \refx does the same to retrieve the value in the definition.
\indexnofonts
\turnoffactive
+ \def\value##1{##1}%
\xdef\safexrefname{#1}%
}%
%
- \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref
+ \bgroup
+ \expandafter\gdef\csname XR\safexrefname\endcsname{#2}%
+ \egroup
+ % We put the \gdef inside a group to avoid the definitions building up on
+ % TeX's save stack, which can cause it to run out of space for aux files with
+ % thousands of lines. \gdef doesn't use the save stack, but \csname does
+ % when it defines an unknown control sequence as \relax.
%
% Was that xref control sequence that we just defined for a float?
\expandafter\iffloat\csname XR\safexrefname\endcsname
@@ -8895,9 +9246,6 @@ end
% now. --karl, 15jan04.
\catcode`\\=\other
%
- % Make the characters 128-255 be printing characters.
- {\setnonasciicharscatcodenonglobal\other}%
- %
% @ is our escape character in .aux files, and we need braces.
\catcode`\{=1
\catcode`\}=2
@@ -8961,7 +9309,7 @@ end
% We want to typeset this text as a normal paragraph, even if the
% footnote reference occurs in (for example) a display environment.
% So reset some parameters.
- \hsize=\pagewidth
+ \hsize=\txipagewidth
\interlinepenalty\interfootnotelinepenalty
\splittopskip\ht\strutbox % top baseline for broken footnotes
\splitmaxdepth\dp\strutbox
@@ -9276,7 +9624,7 @@ end
%
\ifx\thiscaption\empty \else
\ifx\floatident\empty \else
- \appendtomacro\captionline{: }% had ident, so need a colon between
+ \appendtomacro\captionline{: }% had ident, so need a colon between
\fi
%
% caption text.
@@ -9303,30 +9651,17 @@ end
\requireauxfile
\atdummies
%
- % since we read the caption text in the macro world, where ^^M
- % is turned into a normal character, we have to scan it back, so
- % we don't write the literal three characters "^^M" into the aux file.
- \scanexp{%
- \xdef\noexpand\gtemp{%
- \ifx\thisshortcaption\empty
- \thiscaption
- \else
- \thisshortcaption
- \fi
- }%
- }%
+ \ifx\thisshortcaption\empty
+ \def\gtemp{\thiscaption}%
+ \else
+ \def\gtemp{\thisshortcaption}%
+ \fi
\immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
- \ifx\gtemp\empty \else : \gtemp \fi}}%
+ \ifx\gtemp\empty \else : \gtemp \fi}}%
}%
\fi
\egroup % end of \vtop
%
- % place the captured inserts
- %
- % BEWARE: when the floats start floating, we have to issue warning
- % whenever an insert appears inside a float which could possibly
- % float. --kasal, 26may04
- %
\checkinserts
}
@@ -9501,43 +9836,68 @@ directory should work if nowhere else does.}
\global\righthyphenmin = #3\relax
}
-% Get input by bytes instead of by UTF-8 codepoints for XeTeX and LuaTeX,
-% otherwise the encoding support is completely broken.
+% XeTeX and LuaTeX can handle Unicode natively.
+% Their default I/O uses UTF-8 sequences instead of a byte-wise operation.
+% Other TeX engines' I/O (pdfTeX, etc.) is byte-wise.
+%
+\newif\iftxinativeunicodecapable
+\newif\iftxiusebytewiseio
+
\ifx\XeTeXrevision\thisisundefined
+ \ifx\luatexversion\thisisundefined
+ \txinativeunicodecapablefalse
+ \txiusebytewiseiotrue
+ \else
+ \txinativeunicodecapabletrue
+ \txiusebytewiseiofalse
+ \fi
\else
-\XeTeXdefaultencoding "bytes" % For subsequent files to be read
-\XeTeXinputencoding "bytes" % Effective in texinfo.tex only
-% Unfortunately, there seems to be no corresponding XeTeX command for
-% output encoding. This is a problem for auxiliary index and TOC files.
-% The only solution would be perhaps to write out @U{...} sequences in
-% place of UTF-8 characters.
+ \txinativeunicodecapabletrue
+ \txiusebytewiseiofalse
\fi
-\ifx\luatexversion\thisisundefined
-\else
-\directlua{
-local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub
-local function convert_char (char)
- return utf8_char(byte(char))
-end
-
-local function convert_line (line)
- return gsub(line, ".", convert_char)
-end
-
-callback.register("process_input_buffer", convert_line)
+% Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex
+% for non-UTF-8 (byte-wise) encodings.
+%
+\def\setbytewiseio{%
+ \ifx\XeTeXrevision\thisisundefined
+ \else
+ \XeTeXdefaultencoding "bytes" % For subsequent files to be read
+ \XeTeXinputencoding "bytes" % For document root file
+ % Unfortunately, there seems to be no corresponding XeTeX command for
+ % output encoding. This is a problem for auxiliary index and TOC files.
+ % The only solution would be perhaps to write out @U{...} sequences in
+ % place of non-ASCII characters.
+ \fi
-local function convert_line_out (line)
- local line_out = ""
- for c in string.utfvalues(line) do
- line_out = line_out .. string.char(c)
- end
- return line_out
-end
+ \ifx\luatexversion\thisisundefined
+ \else
+ \directlua{
+ local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub
+ local function convert_char (char)
+ return utf8_char(byte(char))
+ end
+
+ local function convert_line (line)
+ return gsub(line, ".", convert_char)
+ end
+
+ callback.register("process_input_buffer", convert_line)
+
+ local function convert_line_out (line)
+ local line_out = ""
+ for c in string.utfvalues(line) do
+ line_out = line_out .. string.char(c)
+ end
+ return line_out
+ end
+
+ callback.register("process_output_buffer", convert_line_out)
+ }
+ \fi
-callback.register("process_output_buffer", convert_line_out)
+ \txiusebytewiseiotrue
}
-\fi
% Helpers for encodings.
@@ -9564,13 +9924,6 @@ callback.register("process_output_buffer", convert_line_out)
%
\def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz}
\def\documentencodingzzz#1{%
- % Get input by bytes instead of by UTF-8 codepoints for XeTeX,
- % otherwise the encoding support is completely broken.
- % This settings is for the document root file.
- \ifx\XeTeXrevision\thisisundefined
- \else
- \XeTeXinputencoding "bytes"
- \fi
%
% Encoding being declared for the document.
\def\declaredencoding{\csname #1.enc\endcsname}%
@@ -9587,22 +9940,38 @@ callback.register("process_output_buffer", convert_line_out)
\asciichardefs
%
\else \ifx \declaredencoding \lattwo
+ \iftxinativeunicodecapable
+ \setbytewiseio
+ \fi
\setnonasciicharscatcode\active
\lattwochardefs
%
\else \ifx \declaredencoding \latone
+ \iftxinativeunicodecapable
+ \setbytewiseio
+ \fi
\setnonasciicharscatcode\active
\latonechardefs
%
\else \ifx \declaredencoding \latnine
+ \iftxinativeunicodecapable
+ \setbytewiseio
+ \fi
\setnonasciicharscatcode\active
\latninechardefs
%
\else \ifx \declaredencoding \utfeight
- \setnonasciicharscatcode\active
- % since we already invoked \utfeightchardefs at the top level
- % (below), do not re-invoke it, then our check for duplicated
- % definitions triggers. Making non-ascii chars active is enough.
+ \iftxinativeunicodecapable
+ % For native Unicode handling (XeTeX and LuaTeX)
+ \nativeunicodechardefs
+ \else
+ % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX)
+ \setnonasciicharscatcode\active
+ % since we already invoked \utfeightchardefs at the top level
+ % (below), do not re-invoke it, otherwise our check for duplicated
+ % definitions gets triggered. Making non-ascii chars active is
+ % sufficient.
+ \fi
%
\else
\message{Ignoring unknown document encoding: #1.}%
@@ -9612,6 +9981,18 @@ callback.register("process_output_buffer", convert_line_out)
\fi % latone
\fi % lattwo
\fi % ascii
+ %
+ \ifx\XeTeXrevision\thisisundefined
+ \else
+ \ifx \declaredencoding \utfeight
+ \else
+ \ifx \declaredencoding \ascii
+ \else
+ \message{Warning: XeTeX with non-UTF-8 encodings cannot handle %
+ non-ASCII characters in auxiliary files.}%
+ \fi
+ \fi
+ \fi
}
% emacs-page
@@ -9628,109 +10009,119 @@ callback.register("process_output_buffer", convert_line_out)
% macros containing the character definitions.
\setnonasciicharscatcode\active
%
+
+\def\gdefchar#1#2{%
+\gdef#1{%
+ \ifpassthroughchars
+ \string#1%
+ \else
+ #2%
+ \fi
+}}
+
% Latin1 (ISO-8859-1) character definitions.
\def\latonechardefs{%
- \gdef^^a0{\tie}
- \gdef^^a1{\exclamdown}
- \gdef^^a2{{\tcfont \char162}} % cent
- \gdef^^a3{\pounds}
- \gdef^^a4{{\tcfont \char164}} % currency
- \gdef^^a5{{\tcfont \char165}} % yen
- \gdef^^a6{{\tcfont \char166}} % broken bar
- \gdef^^a7{\S}
- \gdef^^a8{\"{}}
- \gdef^^a9{\copyright}
- \gdef^^aa{\ordf}
- \gdef^^ab{\guillemetleft}
- \gdef^^ac{\ensuremath\lnot}
- \gdef^^ad{\-}
- \gdef^^ae{\registeredsymbol}
- \gdef^^af{\={}}
- %
- \gdef^^b0{\textdegree}
- \gdef^^b1{$\pm$}
- \gdef^^b2{$^2$}
- \gdef^^b3{$^3$}
- \gdef^^b4{\'{}}
- \gdef^^b5{$\mu$}
- \gdef^^b6{\P}
- \gdef^^b7{\ensuremath\cdot}
- \gdef^^b8{\cedilla\ }
- \gdef^^b9{$^1$}
- \gdef^^ba{\ordm}
- \gdef^^bb{\guillemetright}
- \gdef^^bc{$1\over4$}
- \gdef^^bd{$1\over2$}
- \gdef^^be{$3\over4$}
- \gdef^^bf{\questiondown}
- %
- \gdef^^c0{\`A}
- \gdef^^c1{\'A}
- \gdef^^c2{\^A}
- \gdef^^c3{\~A}
- \gdef^^c4{\"A}
- \gdef^^c5{\ringaccent A}
- \gdef^^c6{\AE}
- \gdef^^c7{\cedilla C}
- \gdef^^c8{\`E}
- \gdef^^c9{\'E}
- \gdef^^ca{\^E}
- \gdef^^cb{\"E}
- \gdef^^cc{\`I}
- \gdef^^cd{\'I}
- \gdef^^ce{\^I}
- \gdef^^cf{\"I}
- %
- \gdef^^d0{\DH}
- \gdef^^d1{\~N}
- \gdef^^d2{\`O}
- \gdef^^d3{\'O}
- \gdef^^d4{\^O}
- \gdef^^d5{\~O}
- \gdef^^d6{\"O}
- \gdef^^d7{$\times$}
- \gdef^^d8{\O}
- \gdef^^d9{\`U}
- \gdef^^da{\'U}
- \gdef^^db{\^U}
- \gdef^^dc{\"U}
- \gdef^^dd{\'Y}
- \gdef^^de{\TH}
- \gdef^^df{\ss}
- %
- \gdef^^e0{\`a}
- \gdef^^e1{\'a}
- \gdef^^e2{\^a}
- \gdef^^e3{\~a}
- \gdef^^e4{\"a}
- \gdef^^e5{\ringaccent a}
- \gdef^^e6{\ae}
- \gdef^^e7{\cedilla c}
- \gdef^^e8{\`e}
- \gdef^^e9{\'e}
- \gdef^^ea{\^e}
- \gdef^^eb{\"e}
- \gdef^^ec{\`{\dotless i}}
- \gdef^^ed{\'{\dotless i}}
- \gdef^^ee{\^{\dotless i}}
- \gdef^^ef{\"{\dotless i}}
- %
- \gdef^^f0{\dh}
- \gdef^^f1{\~n}
- \gdef^^f2{\`o}
- \gdef^^f3{\'o}
- \gdef^^f4{\^o}
- \gdef^^f5{\~o}
- \gdef^^f6{\"o}
- \gdef^^f7{$\div$}
- \gdef^^f8{\o}
- \gdef^^f9{\`u}
- \gdef^^fa{\'u}
- \gdef^^fb{\^u}
- \gdef^^fc{\"u}
- \gdef^^fd{\'y}
- \gdef^^fe{\th}
- \gdef^^ff{\"y}
+ \gdefchar^^a0{\tie}
+ \gdefchar^^a1{\exclamdown}
+ \gdefchar^^a2{{\tcfont \char162}} % cent
+ \gdefchar^^a3{\pounds{}}
+ \gdefchar^^a4{{\tcfont \char164}} % currency
+ \gdefchar^^a5{{\tcfont \char165}} % yen
+ \gdefchar^^a6{{\tcfont \char166}} % broken bar
+ \gdefchar^^a7{\S}
+ \gdefchar^^a8{\"{}}
+ \gdefchar^^a9{\copyright{}}
+ \gdefchar^^aa{\ordf}
+ \gdefchar^^ab{\guillemetleft{}}
+ \gdefchar^^ac{\ensuremath\lnot}
+ \gdefchar^^ad{\-}
+ \gdefchar^^ae{\registeredsymbol{}}
+ \gdefchar^^af{\={}}
+ %
+ \gdefchar^^b0{\textdegree}
+ \gdefchar^^b1{$\pm$}
+ \gdefchar^^b2{$^2$}
+ \gdefchar^^b3{$^3$}
+ \gdefchar^^b4{\'{}}
+ \gdefchar^^b5{$\mu$}
+ \gdefchar^^b6{\P}
+ \gdefchar^^b7{\ensuremath\cdot}
+ \gdefchar^^b8{\cedilla\ }
+ \gdefchar^^b9{$^1$}
+ \gdefchar^^ba{\ordm}
+ \gdefchar^^bb{\guillemetright{}}
+ \gdefchar^^bc{$1\over4$}
+ \gdefchar^^bd{$1\over2$}
+ \gdefchar^^be{$3\over4$}
+ \gdefchar^^bf{\questiondown}
+ %
+ \gdefchar^^c0{\`A}
+ \gdefchar^^c1{\'A}
+ \gdefchar^^c2{\^A}
+ \gdefchar^^c3{\~A}
+ \gdefchar^^c4{\"A}
+ \gdefchar^^c5{\ringaccent A}
+ \gdefchar^^c6{\AE}
+ \gdefchar^^c7{\cedilla C}
+ \gdefchar^^c8{\`E}
+ \gdefchar^^c9{\'E}
+ \gdefchar^^ca{\^E}
+ \gdefchar^^cb{\"E}
+ \gdefchar^^cc{\`I}
+ \gdefchar^^cd{\'I}
+ \gdefchar^^ce{\^I}
+ \gdefchar^^cf{\"I}
+ %
+ \gdefchar^^d0{\DH}
+ \gdefchar^^d1{\~N}
+ \gdefchar^^d2{\`O}
+ \gdefchar^^d3{\'O}
+ \gdefchar^^d4{\^O}
+ \gdefchar^^d5{\~O}
+ \gdefchar^^d6{\"O}
+ \gdefchar^^d7{$\times$}
+ \gdefchar^^d8{\O}
+ \gdefchar^^d9{\`U}
+ \gdefchar^^da{\'U}
+ \gdefchar^^db{\^U}
+ \gdefchar^^dc{\"U}
+ \gdefchar^^dd{\'Y}
+ \gdefchar^^de{\TH}
+ \gdefchar^^df{\ss}
+ %
+ \gdefchar^^e0{\`a}
+ \gdefchar^^e1{\'a}
+ \gdefchar^^e2{\^a}
+ \gdefchar^^e3{\~a}
+ \gdefchar^^e4{\"a}
+ \gdefchar^^e5{\ringaccent a}
+ \gdefchar^^e6{\ae}
+ \gdefchar^^e7{\cedilla c}
+ \gdefchar^^e8{\`e}
+ \gdefchar^^e9{\'e}
+ \gdefchar^^ea{\^e}
+ \gdefchar^^eb{\"e}
+ \gdefchar^^ec{\`{\dotless i}}
+ \gdefchar^^ed{\'{\dotless i}}
+ \gdefchar^^ee{\^{\dotless i}}
+ \gdefchar^^ef{\"{\dotless i}}
+ %
+ \gdefchar^^f0{\dh}
+ \gdefchar^^f1{\~n}
+ \gdefchar^^f2{\`o}
+ \gdefchar^^f3{\'o}
+ \gdefchar^^f4{\^o}
+ \gdefchar^^f5{\~o}
+ \gdefchar^^f6{\"o}
+ \gdefchar^^f7{$\div$}
+ \gdefchar^^f8{\o}
+ \gdefchar^^f9{\`u}
+ \gdefchar^^fa{\'u}
+ \gdefchar^^fb{\^u}
+ \gdefchar^^fc{\"u}
+ \gdefchar^^fd{\'y}
+ \gdefchar^^fe{\th}
+ \gdefchar^^ff{\"y}
}
% Latin9 (ISO-8859-15) encoding character definitions.
@@ -9738,119 +10129,119 @@ callback.register("process_output_buffer", convert_line_out)
% Encoding is almost identical to Latin1.
\latonechardefs
%
- \gdef^^a4{\euro}
- \gdef^^a6{\v S}
- \gdef^^a8{\v s}
- \gdef^^b4{\v Z}
- \gdef^^b8{\v z}
- \gdef^^bc{\OE}
- \gdef^^bd{\oe}
- \gdef^^be{\"Y}
+ \gdefchar^^a4{\euro{}}
+ \gdefchar^^a6{\v S}
+ \gdefchar^^a8{\v s}
+ \gdefchar^^b4{\v Z}
+ \gdefchar^^b8{\v z}
+ \gdefchar^^bc{\OE}
+ \gdefchar^^bd{\oe}
+ \gdefchar^^be{\"Y}
}
% Latin2 (ISO-8859-2) character definitions.
\def\lattwochardefs{%
- \gdef^^a0{\tie}
- \gdef^^a1{\ogonek{A}}
- \gdef^^a2{\u{}}
- \gdef^^a3{\L}
- \gdef^^a4{\missingcharmsg{CURRENCY SIGN}}
- \gdef^^a5{\v L}
- \gdef^^a6{\'S}
- \gdef^^a7{\S}
- \gdef^^a8{\"{}}
- \gdef^^a9{\v S}
- \gdef^^aa{\cedilla S}
- \gdef^^ab{\v T}
- \gdef^^ac{\'Z}
- \gdef^^ad{\-}
- \gdef^^ae{\v Z}
- \gdef^^af{\dotaccent Z}
- %
- \gdef^^b0{\textdegree}
- \gdef^^b1{\ogonek{a}}
- \gdef^^b2{\ogonek{ }}
- \gdef^^b3{\l}
- \gdef^^b4{\'{}}
- \gdef^^b5{\v l}
- \gdef^^b6{\'s}
- \gdef^^b7{\v{}}
- \gdef^^b8{\cedilla\ }
- \gdef^^b9{\v s}
- \gdef^^ba{\cedilla s}
- \gdef^^bb{\v t}
- \gdef^^bc{\'z}
- \gdef^^bd{\H{}}
- \gdef^^be{\v z}
- \gdef^^bf{\dotaccent z}
- %
- \gdef^^c0{\'R}
- \gdef^^c1{\'A}
- \gdef^^c2{\^A}
- \gdef^^c3{\u A}
- \gdef^^c4{\"A}
- \gdef^^c5{\'L}
- \gdef^^c6{\'C}
- \gdef^^c7{\cedilla C}
- \gdef^^c8{\v C}
- \gdef^^c9{\'E}
- \gdef^^ca{\ogonek{E}}
- \gdef^^cb{\"E}
- \gdef^^cc{\v E}
- \gdef^^cd{\'I}
- \gdef^^ce{\^I}
- \gdef^^cf{\v D}
- %
- \gdef^^d0{\DH}
- \gdef^^d1{\'N}
- \gdef^^d2{\v N}
- \gdef^^d3{\'O}
- \gdef^^d4{\^O}
- \gdef^^d5{\H O}
- \gdef^^d6{\"O}
- \gdef^^d7{$\times$}
- \gdef^^d8{\v R}
- \gdef^^d9{\ringaccent U}
- \gdef^^da{\'U}
- \gdef^^db{\H U}
- \gdef^^dc{\"U}
- \gdef^^dd{\'Y}
- \gdef^^de{\cedilla T}
- \gdef^^df{\ss}
- %
- \gdef^^e0{\'r}
- \gdef^^e1{\'a}
- \gdef^^e2{\^a}
- \gdef^^e3{\u a}
- \gdef^^e4{\"a}
- \gdef^^e5{\'l}
- \gdef^^e6{\'c}
- \gdef^^e7{\cedilla c}
- \gdef^^e8{\v c}
- \gdef^^e9{\'e}
- \gdef^^ea{\ogonek{e}}
- \gdef^^eb{\"e}
- \gdef^^ec{\v e}
- \gdef^^ed{\'{\dotless{i}}}
- \gdef^^ee{\^{\dotless{i}}}
- \gdef^^ef{\v d}
- %
- \gdef^^f0{\dh}
- \gdef^^f1{\'n}
- \gdef^^f2{\v n}
- \gdef^^f3{\'o}
- \gdef^^f4{\^o}
- \gdef^^f5{\H o}
- \gdef^^f6{\"o}
- \gdef^^f7{$\div$}
- \gdef^^f8{\v r}
- \gdef^^f9{\ringaccent u}
- \gdef^^fa{\'u}
- \gdef^^fb{\H u}
- \gdef^^fc{\"u}
- \gdef^^fd{\'y}
- \gdef^^fe{\cedilla t}
- \gdef^^ff{\dotaccent{}}
+ \gdefchar^^a0{\tie}
+ \gdefchar^^a1{\ogonek{A}}
+ \gdefchar^^a2{\u{}}
+ \gdefchar^^a3{\L}
+ \gdefchar^^a4{\missingcharmsg{CURRENCY SIGN}}
+ \gdefchar^^a5{\v L}
+ \gdefchar^^a6{\'S}
+ \gdefchar^^a7{\S}
+ \gdefchar^^a8{\"{}}
+ \gdefchar^^a9{\v S}
+ \gdefchar^^aa{\cedilla S}
+ \gdefchar^^ab{\v T}
+ \gdefchar^^ac{\'Z}
+ \gdefchar^^ad{\-}
+ \gdefchar^^ae{\v Z}
+ \gdefchar^^af{\dotaccent Z}
+ %
+ \gdefchar^^b0{\textdegree{}}
+ \gdefchar^^b1{\ogonek{a}}
+ \gdefchar^^b2{\ogonek{ }}
+ \gdefchar^^b3{\l}
+ \gdefchar^^b4{\'{}}
+ \gdefchar^^b5{\v l}
+ \gdefchar^^b6{\'s}
+ \gdefchar^^b7{\v{}}
+ \gdefchar^^b8{\cedilla\ }
+ \gdefchar^^b9{\v s}
+ \gdefchar^^ba{\cedilla s}
+ \gdefchar^^bb{\v t}
+ \gdefchar^^bc{\'z}
+ \gdefchar^^bd{\H{}}
+ \gdefchar^^be{\v z}
+ \gdefchar^^bf{\dotaccent z}
+ %
+ \gdefchar^^c0{\'R}
+ \gdefchar^^c1{\'A}
+ \gdefchar^^c2{\^A}
+ \gdefchar^^c3{\u A}
+ \gdefchar^^c4{\"A}
+ \gdefchar^^c5{\'L}
+ \gdefchar^^c6{\'C}
+ \gdefchar^^c7{\cedilla C}
+ \gdefchar^^c8{\v C}
+ \gdefchar^^c9{\'E}
+ \gdefchar^^ca{\ogonek{E}}
+ \gdefchar^^cb{\"E}
+ \gdefchar^^cc{\v E}
+ \gdefchar^^cd{\'I}
+ \gdefchar^^ce{\^I}
+ \gdefchar^^cf{\v D}
+ %
+ \gdefchar^^d0{\DH}
+ \gdefchar^^d1{\'N}
+ \gdefchar^^d2{\v N}
+ \gdefchar^^d3{\'O}
+ \gdefchar^^d4{\^O}
+ \gdefchar^^d5{\H O}
+ \gdefchar^^d6{\"O}
+ \gdefchar^^d7{$\times$}
+ \gdefchar^^d8{\v R}
+ \gdefchar^^d9{\ringaccent U}
+ \gdefchar^^da{\'U}
+ \gdefchar^^db{\H U}
+ \gdefchar^^dc{\"U}
+ \gdefchar^^dd{\'Y}
+ \gdefchar^^de{\cedilla T}
+ \gdefchar^^df{\ss}
+ %
+ \gdefchar^^e0{\'r}
+ \gdefchar^^e1{\'a}
+ \gdefchar^^e2{\^a}
+ \gdefchar^^e3{\u a}
+ \gdefchar^^e4{\"a}
+ \gdefchar^^e5{\'l}
+ \gdefchar^^e6{\'c}
+ \gdefchar^^e7{\cedilla c}
+ \gdefchar^^e8{\v c}
+ \gdefchar^^e9{\'e}
+ \gdefchar^^ea{\ogonek{e}}
+ \gdefchar^^eb{\"e}
+ \gdefchar^^ec{\v e}
+ \gdefchar^^ed{\'{\dotless{i}}}
+ \gdefchar^^ee{\^{\dotless{i}}}
+ \gdefchar^^ef{\v d}
+ %
+ \gdefchar^^f0{\dh}
+ \gdefchar^^f1{\'n}
+ \gdefchar^^f2{\v n}
+ \gdefchar^^f3{\'o}
+ \gdefchar^^f4{\^o}
+ \gdefchar^^f5{\H o}
+ \gdefchar^^f6{\"o}
+ \gdefchar^^f7{$\div$}
+ \gdefchar^^f8{\v r}
+ \gdefchar^^f9{\ringaccent u}
+ \gdefchar^^fa{\'u}
+ \gdefchar^^fb{\H u}
+ \gdefchar^^fc{\"u}
+ \gdefchar^^fd{\'y}
+ \gdefchar^^fe{\cedilla t}
+ \gdefchar^^ff{\dotaccent{}}
}
% UTF-8 character definitions.
@@ -9880,35 +10271,56 @@ callback.register("process_output_buffer", convert_line_out)
\fi
}
+% Give non-ASCII bytes the active definitions for processing UTF-8 sequences
\begingroup
\catcode`\~13
+ \catcode`\$12
\catcode`\"12
+ % Loop from \countUTFx to \countUTFy, performing \UTFviiiTmp
+ % substituting ~ and $ with a character token of that value.
\def\UTFviiiLoop{%
\global\catcode\countUTFx\active
\uccode`\~\countUTFx
+ \uccode`\$\countUTFx
\uppercase\expandafter{\UTFviiiTmp}%
\advance\countUTFx by 1
\ifnum\countUTFx < \countUTFy
\expandafter\UTFviiiLoop
\fi}
+ % For bytes other than the first in a UTF-8 sequence. Not expected to
+ % be expanded except when writing to auxiliary files.
+ \countUTFx = "80
+ \countUTFy = "C2
+ \def\UTFviiiTmp{%
+ \gdef~{%
+ \ifpassthroughchars $\fi}}%
+ \UTFviiiLoop
+
\countUTFx = "C2
\countUTFy = "E0
\def\UTFviiiTmp{%
- \xdef~{\noexpand\UTFviiiTwoOctets\string~}}
+ \gdef~{%
+ \ifpassthroughchars $%
+ \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}%
\UTFviiiLoop
\countUTFx = "E0
\countUTFy = "F0
\def\UTFviiiTmp{%
- \xdef~{\noexpand\UTFviiiThreeOctets\string~}}
+ \gdef~{%
+ \ifpassthroughchars $%
+ \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}%
\UTFviiiLoop
\countUTFx = "F0
\countUTFy = "F4
\def\UTFviiiTmp{%
- \xdef~{\noexpand\UTFviiiFourOctets\string~}}
+ \gdef~{%
+ \ifpassthroughchars $%
+ \else\expandafter\UTFviiiFourOctets\expandafter$\fi
+ }}%
\UTFviiiLoop
\endgroup
@@ -9917,13 +10329,36 @@ callback.register("process_output_buffer", convert_line_out)
% @U{xxxx} to produce U+xxxx, if we support it.
\def\U#1{%
\expandafter\ifx\csname uni:#1\endcsname \relax
- \errhelp = \EMsimple
- \errmessage{Unicode character U+#1 not supported, sorry}%
+ \iftxinativeunicodecapable
+ % All Unicode characters can be used if native Unicode handling is
+ % active. However, if the font does not have the glyph,
+ % letters are missing.
+ \begingroup
+ \uccode`\.="#1\relax
+ \uppercase{.}
+ \endgroup
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unicode character U+#1 not supported, sorry}%
+ \fi
\else
\csname uni:#1\endcsname
\fi
}
+% These macros are used here to construct the name of a control
+% sequence to be defined.
+\def\UTFviiiTwoOctetsName#1#2{%
+ \csname u8:#1\string #2\endcsname}%
+\def\UTFviiiThreeOctetsName#1#2#3{%
+ \csname u8:#1\string #2\string #3\endcsname}%
+\def\UTFviiiFourOctetsName#1#2#3#4{%
+ \csname u8:#1\string #2\string #3\string #4\endcsname}%
+
+% For UTF-8 byte sequences (TeX, e-TeX and pdfTeX),
+% provide a definition macro to replace a Unicode character;
+% this gets used by the @U command
+%
\begingroup
\catcode`\"=12
\catcode`\<=12
@@ -9932,20 +10367,22 @@ callback.register("process_output_buffer", convert_line_out)
\catcode`\;=12
\catcode`\!=12
\catcode`\~=13
- \gdef\DeclareUnicodeCharacter#1#2{%
+ \gdef\DeclareUnicodeCharacterUTFviii#1#2{%
\countUTFz = "#1\relax
- %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}%
\begingroup
\parseXMLCharref
- \def\UTFviiiTwoOctets##1##2{%
- \csname u8:##1\string ##2\endcsname}%
- \def\UTFviiiThreeOctets##1##2##3{%
- \csname u8:##1\string ##2\string ##3\endcsname}%
- \def\UTFviiiFourOctets##1##2##3##4{%
- \csname u8:##1\string ##2\string ##3\string ##4\endcsname}%
- \expandafter\expandafter\expandafter\expandafter
- \expandafter\expandafter\expandafter
- \gdef\UTFviiiTmp{#2}%
+
+ % Give \u8:... its definition. The sequence of seven \expandafter's
+ % expands after the \gdef three times, e.g.
+ %
+ % 1. \UTFviiTwoOctetsName B1 B2
+ % 2. \csname u8:B1 \string B2 \endcsname
+ % 3. \u8: B1 B2 (a single control sequence token)
+ %
+ \expandafter\expandafter
+ \expandafter\expandafter
+ \expandafter\expandafter
+ \expandafter\gdef \UTFviiiTmp{#2}%
%
\expandafter\ifx\csname uni:#1\endcsname \relax \else
\message{Internal error, already defined: #1}%
@@ -9954,42 +10391,67 @@ callback.register("process_output_buffer", convert_line_out)
% define an additional control sequence for this code point.
\expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp
\endgroup}
-
+ %
+ % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp
+ % to the corresponding UTF-8 sequence.
\gdef\parseXMLCharref{%
\ifnum\countUTFz < "A0\relax
\errhelp = \EMsimple
\errmessage{Cannot define Unicode char value < 00A0}%
\else\ifnum\countUTFz < "800\relax
\parseUTFviiiA,%
- \parseUTFviiiB C\UTFviiiTwoOctets.,%
+ \parseUTFviiiB C\UTFviiiTwoOctetsName.,%
\else\ifnum\countUTFz < "10000\relax
\parseUTFviiiA;%
\parseUTFviiiA,%
- \parseUTFviiiB E\UTFviiiThreeOctets.{,;}%
+ \parseUTFviiiB E\UTFviiiThreeOctetsName.{,;}%
\else
\parseUTFviiiA;%
\parseUTFviiiA,%
\parseUTFviiiA!%
- \parseUTFviiiB F\UTFviiiFourOctets.{!,;}%
+ \parseUTFviiiB F\UTFviiiFourOctetsName.{!,;}%
\fi\fi\fi
}
+ % Extract a byte from the end of the UTF-8 representation of \countUTFx.
+ % It must be a non-initial byte in the sequence.
+ % Change \uccode of #1 for it to be used in \parseUTFviiiB as one
+ % of the bytes.
\gdef\parseUTFviiiA#1{%
\countUTFx = \countUTFz
\divide\countUTFz by 64
- \countUTFy = \countUTFz
+ \countUTFy = \countUTFz % Save to be the future value of \countUTFz.
\multiply\countUTFz by 64
+
+ % \countUTFz is now \countUTFx with the last 5 bits cleared. Subtract
+ % in order to get the last five bits.
\advance\countUTFx by -\countUTFz
+
+ % Convert this to the byte in the UTF-8 sequence.
\advance\countUTFx by 128
\uccode `#1\countUTFx
\countUTFz = \countUTFy}
+ % Used to put a UTF-8 byte sequence into \UTFviiiTmp
+ % #1 is the increment for \countUTFz to yield a the first byte of the UTF-8
+ % sequence.
+ % #2 is one of the \UTFviii*OctetsName macros.
+ % #3 is always a full stop (.)
+ % #4 is a template for the other bytes in the sequence. The values for these
+ % bytes is substituted in here with \uppercase using the \uccode's.
\gdef\parseUTFviiiB#1#2#3#4{%
\advance\countUTFz by "#10\relax
\uccode `#3\countUTFz
\uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
\endgroup
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro that sets a catcode to `other' non-globally
+%
+\def\DeclareUnicodeCharacterNativeOther#1#2{%
+ \catcode"#1=\other
+}
+
% https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M
% U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
% U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)
@@ -10004,732 +10466,748 @@ callback.register("process_output_buffer", convert_line_out)
% We won't be doing that here in this simple file. But we can try to at
% least make most of the characters not bomb out.
%
-\def\utfeightchardefs{%
- \DeclareUnicodeCharacter{00A0}{\tie}
- \DeclareUnicodeCharacter{00A1}{\exclamdown}
+\def\unicodechardefs{%
+ \DeclareUnicodeCharacter{00A0}{\tie}%
+ \DeclareUnicodeCharacter{00A1}{\exclamdown}%
\DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent
- \DeclareUnicodeCharacter{00A3}{\pounds}
+ \DeclareUnicodeCharacter{00A3}{\pounds{}}%
\DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency
\DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen
\DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar
- \DeclareUnicodeCharacter{00A7}{\S}
- \DeclareUnicodeCharacter{00A8}{\"{ }}
- \DeclareUnicodeCharacter{00A9}{\copyright}
- \DeclareUnicodeCharacter{00AA}{\ordf}
- \DeclareUnicodeCharacter{00AB}{\guillemetleft}
- \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}
- \DeclareUnicodeCharacter{00AD}{\-}
- \DeclareUnicodeCharacter{00AE}{\registeredsymbol}
- \DeclareUnicodeCharacter{00AF}{\={ }}
- %
- \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}
- \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}
- \DeclareUnicodeCharacter{00B2}{$^2$}
- \DeclareUnicodeCharacter{00B3}{$^3$}
- \DeclareUnicodeCharacter{00B4}{\'{ }}
- \DeclareUnicodeCharacter{00B5}{$\mu$}
- \DeclareUnicodeCharacter{00B6}{\P}
- \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}
- \DeclareUnicodeCharacter{00B8}{\cedilla{ }}
- \DeclareUnicodeCharacter{00B9}{$^1$}
- \DeclareUnicodeCharacter{00BA}{\ordm}
- \DeclareUnicodeCharacter{00BB}{\guillemetright}
- \DeclareUnicodeCharacter{00BC}{$1\over4$}
- \DeclareUnicodeCharacter{00BD}{$1\over2$}
- \DeclareUnicodeCharacter{00BE}{$3\over4$}
- \DeclareUnicodeCharacter{00BF}{\questiondown}
- %
- \DeclareUnicodeCharacter{00C0}{\`A}
- \DeclareUnicodeCharacter{00C1}{\'A}
- \DeclareUnicodeCharacter{00C2}{\^A}
- \DeclareUnicodeCharacter{00C3}{\~A}
- \DeclareUnicodeCharacter{00C4}{\"A}
- \DeclareUnicodeCharacter{00C5}{\AA}
- \DeclareUnicodeCharacter{00C6}{\AE}
- \DeclareUnicodeCharacter{00C7}{\cedilla{C}}
- \DeclareUnicodeCharacter{00C8}{\`E}
- \DeclareUnicodeCharacter{00C9}{\'E}
- \DeclareUnicodeCharacter{00CA}{\^E}
- \DeclareUnicodeCharacter{00CB}{\"E}
- \DeclareUnicodeCharacter{00CC}{\`I}
- \DeclareUnicodeCharacter{00CD}{\'I}
- \DeclareUnicodeCharacter{00CE}{\^I}
- \DeclareUnicodeCharacter{00CF}{\"I}
- %
- \DeclareUnicodeCharacter{00D0}{\DH}
- \DeclareUnicodeCharacter{00D1}{\~N}
- \DeclareUnicodeCharacter{00D2}{\`O}
- \DeclareUnicodeCharacter{00D3}{\'O}
- \DeclareUnicodeCharacter{00D4}{\^O}
- \DeclareUnicodeCharacter{00D5}{\~O}
- \DeclareUnicodeCharacter{00D6}{\"O}
- \DeclareUnicodeCharacter{00D7}{\ensuremath\times}
- \DeclareUnicodeCharacter{00D8}{\O}
- \DeclareUnicodeCharacter{00D9}{\`U}
- \DeclareUnicodeCharacter{00DA}{\'U}
- \DeclareUnicodeCharacter{00DB}{\^U}
- \DeclareUnicodeCharacter{00DC}{\"U}
- \DeclareUnicodeCharacter{00DD}{\'Y}
- \DeclareUnicodeCharacter{00DE}{\TH}
- \DeclareUnicodeCharacter{00DF}{\ss}
- %
- \DeclareUnicodeCharacter{00E0}{\`a}
- \DeclareUnicodeCharacter{00E1}{\'a}
- \DeclareUnicodeCharacter{00E2}{\^a}
- \DeclareUnicodeCharacter{00E3}{\~a}
- \DeclareUnicodeCharacter{00E4}{\"a}
- \DeclareUnicodeCharacter{00E5}{\aa}
- \DeclareUnicodeCharacter{00E6}{\ae}
- \DeclareUnicodeCharacter{00E7}{\cedilla{c}}
- \DeclareUnicodeCharacter{00E8}{\`e}
- \DeclareUnicodeCharacter{00E9}{\'e}
- \DeclareUnicodeCharacter{00EA}{\^e}
- \DeclareUnicodeCharacter{00EB}{\"e}
- \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}
- \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}
- \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}
- \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}
- %
- \DeclareUnicodeCharacter{00F0}{\dh}
- \DeclareUnicodeCharacter{00F1}{\~n}
- \DeclareUnicodeCharacter{00F2}{\`o}
- \DeclareUnicodeCharacter{00F3}{\'o}
- \DeclareUnicodeCharacter{00F4}{\^o}
- \DeclareUnicodeCharacter{00F5}{\~o}
- \DeclareUnicodeCharacter{00F6}{\"o}
- \DeclareUnicodeCharacter{00F7}{\ensuremath\div}
- \DeclareUnicodeCharacter{00F8}{\o}
- \DeclareUnicodeCharacter{00F9}{\`u}
- \DeclareUnicodeCharacter{00FA}{\'u}
- \DeclareUnicodeCharacter{00FB}{\^u}
- \DeclareUnicodeCharacter{00FC}{\"u}
- \DeclareUnicodeCharacter{00FD}{\'y}
- \DeclareUnicodeCharacter{00FE}{\th}
- \DeclareUnicodeCharacter{00FF}{\"y}
- %
- \DeclareUnicodeCharacter{0100}{\=A}
- \DeclareUnicodeCharacter{0101}{\=a}
- \DeclareUnicodeCharacter{0102}{\u{A}}
- \DeclareUnicodeCharacter{0103}{\u{a}}
- \DeclareUnicodeCharacter{0104}{\ogonek{A}}
- \DeclareUnicodeCharacter{0105}{\ogonek{a}}
- \DeclareUnicodeCharacter{0106}{\'C}
- \DeclareUnicodeCharacter{0107}{\'c}
- \DeclareUnicodeCharacter{0108}{\^C}
- \DeclareUnicodeCharacter{0109}{\^c}
- \DeclareUnicodeCharacter{010A}{\dotaccent{C}}
- \DeclareUnicodeCharacter{010B}{\dotaccent{c}}
- \DeclareUnicodeCharacter{010C}{\v{C}}
- \DeclareUnicodeCharacter{010D}{\v{c}}
- \DeclareUnicodeCharacter{010E}{\v{D}}
- \DeclareUnicodeCharacter{010F}{d'}
- %
- \DeclareUnicodeCharacter{0110}{\DH}
- \DeclareUnicodeCharacter{0111}{\dh}
- \DeclareUnicodeCharacter{0112}{\=E}
- \DeclareUnicodeCharacter{0113}{\=e}
- \DeclareUnicodeCharacter{0114}{\u{E}}
- \DeclareUnicodeCharacter{0115}{\u{e}}
- \DeclareUnicodeCharacter{0116}{\dotaccent{E}}
- \DeclareUnicodeCharacter{0117}{\dotaccent{e}}
- \DeclareUnicodeCharacter{0118}{\ogonek{E}}
- \DeclareUnicodeCharacter{0119}{\ogonek{e}}
- \DeclareUnicodeCharacter{011A}{\v{E}}
- \DeclareUnicodeCharacter{011B}{\v{e}}
- \DeclareUnicodeCharacter{011C}{\^G}
- \DeclareUnicodeCharacter{011D}{\^g}
- \DeclareUnicodeCharacter{011E}{\u{G}}
- \DeclareUnicodeCharacter{011F}{\u{g}}
- %
- \DeclareUnicodeCharacter{0120}{\dotaccent{G}}
- \DeclareUnicodeCharacter{0121}{\dotaccent{g}}
- \DeclareUnicodeCharacter{0122}{\cedilla{G}}
- \DeclareUnicodeCharacter{0123}{\cedilla{g}}
- \DeclareUnicodeCharacter{0124}{\^H}
- \DeclareUnicodeCharacter{0125}{\^h}
- \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}
- \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}
- \DeclareUnicodeCharacter{0128}{\~I}
- \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}
- \DeclareUnicodeCharacter{012A}{\=I}
- \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}
- \DeclareUnicodeCharacter{012C}{\u{I}}
- \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}
- \DeclareUnicodeCharacter{012E}{\ogonek{I}}
- \DeclareUnicodeCharacter{012F}{\ogonek{i}}
- %
- \DeclareUnicodeCharacter{0130}{\dotaccent{I}}
- \DeclareUnicodeCharacter{0131}{\dotless{i}}
- \DeclareUnicodeCharacter{0132}{IJ}
- \DeclareUnicodeCharacter{0133}{ij}
- \DeclareUnicodeCharacter{0134}{\^J}
- \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}
- \DeclareUnicodeCharacter{0136}{\cedilla{K}}
- \DeclareUnicodeCharacter{0137}{\cedilla{k}}
- \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}
- \DeclareUnicodeCharacter{0139}{\'L}
- \DeclareUnicodeCharacter{013A}{\'l}
- \DeclareUnicodeCharacter{013B}{\cedilla{L}}
- \DeclareUnicodeCharacter{013C}{\cedilla{l}}
+ \DeclareUnicodeCharacter{00A7}{\S}%
+ \DeclareUnicodeCharacter{00A8}{\"{ }}%
+ \DeclareUnicodeCharacter{00A9}{\copyright{}}%
+ \DeclareUnicodeCharacter{00AA}{\ordf}%
+ \DeclareUnicodeCharacter{00AB}{\guillemetleft{}}%
+ \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}%
+ \DeclareUnicodeCharacter{00AD}{\-}%
+ \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}%
+ \DeclareUnicodeCharacter{00AF}{\={ }}%
+ %
+ \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}%
+ \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}%
+ \DeclareUnicodeCharacter{00B2}{$^2$}%
+ \DeclareUnicodeCharacter{00B3}{$^3$}%
+ \DeclareUnicodeCharacter{00B4}{\'{ }}%
+ \DeclareUnicodeCharacter{00B5}{$\mu$}%
+ \DeclareUnicodeCharacter{00B6}{\P}%
+ \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}%
+ \DeclareUnicodeCharacter{00B8}{\cedilla{ }}%
+ \DeclareUnicodeCharacter{00B9}{$^1$}%
+ \DeclareUnicodeCharacter{00BA}{\ordm}%
+ \DeclareUnicodeCharacter{00BB}{\guillemetright{}}%
+ \DeclareUnicodeCharacter{00BC}{$1\over4$}%
+ \DeclareUnicodeCharacter{00BD}{$1\over2$}%
+ \DeclareUnicodeCharacter{00BE}{$3\over4$}%
+ \DeclareUnicodeCharacter{00BF}{\questiondown}%
+ %
+ \DeclareUnicodeCharacter{00C0}{\`A}%
+ \DeclareUnicodeCharacter{00C1}{\'A}%
+ \DeclareUnicodeCharacter{00C2}{\^A}%
+ \DeclareUnicodeCharacter{00C3}{\~A}%
+ \DeclareUnicodeCharacter{00C4}{\"A}%
+ \DeclareUnicodeCharacter{00C5}{\AA}%
+ \DeclareUnicodeCharacter{00C6}{\AE}%
+ \DeclareUnicodeCharacter{00C7}{\cedilla{C}}%
+ \DeclareUnicodeCharacter{00C8}{\`E}%
+ \DeclareUnicodeCharacter{00C9}{\'E}%
+ \DeclareUnicodeCharacter{00CA}{\^E}%
+ \DeclareUnicodeCharacter{00CB}{\"E}%
+ \DeclareUnicodeCharacter{00CC}{\`I}%
+ \DeclareUnicodeCharacter{00CD}{\'I}%
+ \DeclareUnicodeCharacter{00CE}{\^I}%
+ \DeclareUnicodeCharacter{00CF}{\"I}%
+ %
+ \DeclareUnicodeCharacter{00D0}{\DH}%
+ \DeclareUnicodeCharacter{00D1}{\~N}%
+ \DeclareUnicodeCharacter{00D2}{\`O}%
+ \DeclareUnicodeCharacter{00D3}{\'O}%
+ \DeclareUnicodeCharacter{00D4}{\^O}%
+ \DeclareUnicodeCharacter{00D5}{\~O}%
+ \DeclareUnicodeCharacter{00D6}{\"O}%
+ \DeclareUnicodeCharacter{00D7}{\ensuremath\times}%
+ \DeclareUnicodeCharacter{00D8}{\O}%
+ \DeclareUnicodeCharacter{00D9}{\`U}%
+ \DeclareUnicodeCharacter{00DA}{\'U}%
+ \DeclareUnicodeCharacter{00DB}{\^U}%
+ \DeclareUnicodeCharacter{00DC}{\"U}%
+ \DeclareUnicodeCharacter{00DD}{\'Y}%
+ \DeclareUnicodeCharacter{00DE}{\TH}%
+ \DeclareUnicodeCharacter{00DF}{\ss}%
+ %
+ \DeclareUnicodeCharacter{00E0}{\`a}%
+ \DeclareUnicodeCharacter{00E1}{\'a}%
+ \DeclareUnicodeCharacter{00E2}{\^a}%
+ \DeclareUnicodeCharacter{00E3}{\~a}%
+ \DeclareUnicodeCharacter{00E4}{\"a}%
+ \DeclareUnicodeCharacter{00E5}{\aa}%
+ \DeclareUnicodeCharacter{00E6}{\ae}%
+ \DeclareUnicodeCharacter{00E7}{\cedilla{c}}%
+ \DeclareUnicodeCharacter{00E8}{\`e}%
+ \DeclareUnicodeCharacter{00E9}{\'e}%
+ \DeclareUnicodeCharacter{00EA}{\^e}%
+ \DeclareUnicodeCharacter{00EB}{\"e}%
+ \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}%
+ \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}%
+ \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}%
+ \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}%
+ %
+ \DeclareUnicodeCharacter{00F0}{\dh}%
+ \DeclareUnicodeCharacter{00F1}{\~n}%
+ \DeclareUnicodeCharacter{00F2}{\`o}%
+ \DeclareUnicodeCharacter{00F3}{\'o}%
+ \DeclareUnicodeCharacter{00F4}{\^o}%
+ \DeclareUnicodeCharacter{00F5}{\~o}%
+ \DeclareUnicodeCharacter{00F6}{\"o}%
+ \DeclareUnicodeCharacter{00F7}{\ensuremath\div}%
+ \DeclareUnicodeCharacter{00F8}{\o}%
+ \DeclareUnicodeCharacter{00F9}{\`u}%
+ \DeclareUnicodeCharacter{00FA}{\'u}%
+ \DeclareUnicodeCharacter{00FB}{\^u}%
+ \DeclareUnicodeCharacter{00FC}{\"u}%
+ \DeclareUnicodeCharacter{00FD}{\'y}%
+ \DeclareUnicodeCharacter{00FE}{\th}%
+ \DeclareUnicodeCharacter{00FF}{\"y}%
+ %
+ \DeclareUnicodeCharacter{0100}{\=A}%
+ \DeclareUnicodeCharacter{0101}{\=a}%
+ \DeclareUnicodeCharacter{0102}{\u{A}}%
+ \DeclareUnicodeCharacter{0103}{\u{a}}%
+ \DeclareUnicodeCharacter{0104}{\ogonek{A}}%
+ \DeclareUnicodeCharacter{0105}{\ogonek{a}}%
+ \DeclareUnicodeCharacter{0106}{\'C}%
+ \DeclareUnicodeCharacter{0107}{\'c}%
+ \DeclareUnicodeCharacter{0108}{\^C}%
+ \DeclareUnicodeCharacter{0109}{\^c}%
+ \DeclareUnicodeCharacter{010A}{\dotaccent{C}}%
+ \DeclareUnicodeCharacter{010B}{\dotaccent{c}}%
+ \DeclareUnicodeCharacter{010C}{\v{C}}%
+ \DeclareUnicodeCharacter{010D}{\v{c}}%
+ \DeclareUnicodeCharacter{010E}{\v{D}}%
+ \DeclareUnicodeCharacter{010F}{d'}%
+ %
+ \DeclareUnicodeCharacter{0110}{\DH}%
+ \DeclareUnicodeCharacter{0111}{\dh}%
+ \DeclareUnicodeCharacter{0112}{\=E}%
+ \DeclareUnicodeCharacter{0113}{\=e}%
+ \DeclareUnicodeCharacter{0114}{\u{E}}%
+ \DeclareUnicodeCharacter{0115}{\u{e}}%
+ \DeclareUnicodeCharacter{0116}{\dotaccent{E}}%
+ \DeclareUnicodeCharacter{0117}{\dotaccent{e}}%
+ \DeclareUnicodeCharacter{0118}{\ogonek{E}}%
+ \DeclareUnicodeCharacter{0119}{\ogonek{e}}%
+ \DeclareUnicodeCharacter{011A}{\v{E}}%
+ \DeclareUnicodeCharacter{011B}{\v{e}}%
+ \DeclareUnicodeCharacter{011C}{\^G}%
+ \DeclareUnicodeCharacter{011D}{\^g}%
+ \DeclareUnicodeCharacter{011E}{\u{G}}%
+ \DeclareUnicodeCharacter{011F}{\u{g}}%
+ %
+ \DeclareUnicodeCharacter{0120}{\dotaccent{G}}%
+ \DeclareUnicodeCharacter{0121}{\dotaccent{g}}%
+ \DeclareUnicodeCharacter{0122}{\cedilla{G}}%
+ \DeclareUnicodeCharacter{0123}{\cedilla{g}}%
+ \DeclareUnicodeCharacter{0124}{\^H}%
+ \DeclareUnicodeCharacter{0125}{\^h}%
+ \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}%
+ \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}%
+ \DeclareUnicodeCharacter{0128}{\~I}%
+ \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}%
+ \DeclareUnicodeCharacter{012A}{\=I}%
+ \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}%
+ \DeclareUnicodeCharacter{012C}{\u{I}}%
+ \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}%
+ \DeclareUnicodeCharacter{012E}{\ogonek{I}}%
+ \DeclareUnicodeCharacter{012F}{\ogonek{i}}%
+ %
+ \DeclareUnicodeCharacter{0130}{\dotaccent{I}}%
+ \DeclareUnicodeCharacter{0131}{\dotless{i}}%
+ \DeclareUnicodeCharacter{0132}{IJ}%
+ \DeclareUnicodeCharacter{0133}{ij}%
+ \DeclareUnicodeCharacter{0134}{\^J}%
+ \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}%
+ \DeclareUnicodeCharacter{0136}{\cedilla{K}}%
+ \DeclareUnicodeCharacter{0137}{\cedilla{k}}%
+ \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}%
+ \DeclareUnicodeCharacter{0139}{\'L}%
+ \DeclareUnicodeCharacter{013A}{\'l}%
+ \DeclareUnicodeCharacter{013B}{\cedilla{L}}%
+ \DeclareUnicodeCharacter{013C}{\cedilla{l}}%
\DeclareUnicodeCharacter{013D}{L'}% should kern
\DeclareUnicodeCharacter{013E}{l'}% should kern
- \DeclareUnicodeCharacter{013F}{L\U{00B7}}
- %
- \DeclareUnicodeCharacter{0140}{l\U{00B7}}
- \DeclareUnicodeCharacter{0141}{\L}
- \DeclareUnicodeCharacter{0142}{\l}
- \DeclareUnicodeCharacter{0143}{\'N}
- \DeclareUnicodeCharacter{0144}{\'n}
- \DeclareUnicodeCharacter{0145}{\cedilla{N}}
- \DeclareUnicodeCharacter{0146}{\cedilla{n}}
- \DeclareUnicodeCharacter{0147}{\v{N}}
- \DeclareUnicodeCharacter{0148}{\v{n}}
- \DeclareUnicodeCharacter{0149}{'n}
- \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}
- \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}
- \DeclareUnicodeCharacter{014C}{\=O}
- \DeclareUnicodeCharacter{014D}{\=o}
- \DeclareUnicodeCharacter{014E}{\u{O}}
- \DeclareUnicodeCharacter{014F}{\u{o}}
- %
- \DeclareUnicodeCharacter{0150}{\H{O}}
- \DeclareUnicodeCharacter{0151}{\H{o}}
- \DeclareUnicodeCharacter{0152}{\OE}
- \DeclareUnicodeCharacter{0153}{\oe}
- \DeclareUnicodeCharacter{0154}{\'R}
- \DeclareUnicodeCharacter{0155}{\'r}
- \DeclareUnicodeCharacter{0156}{\cedilla{R}}
- \DeclareUnicodeCharacter{0157}{\cedilla{r}}
- \DeclareUnicodeCharacter{0158}{\v{R}}
- \DeclareUnicodeCharacter{0159}{\v{r}}
- \DeclareUnicodeCharacter{015A}{\'S}
- \DeclareUnicodeCharacter{015B}{\'s}
- \DeclareUnicodeCharacter{015C}{\^S}
- \DeclareUnicodeCharacter{015D}{\^s}
- \DeclareUnicodeCharacter{015E}{\cedilla{S}}
- \DeclareUnicodeCharacter{015F}{\cedilla{s}}
- %
- \DeclareUnicodeCharacter{0160}{\v{S}}
- \DeclareUnicodeCharacter{0161}{\v{s}}
- \DeclareUnicodeCharacter{0162}{\cedilla{T}}
- \DeclareUnicodeCharacter{0163}{\cedilla{t}}
- \DeclareUnicodeCharacter{0164}{\v{T}}
- \DeclareUnicodeCharacter{0165}{\v{t}}
- \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}
- \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}
- \DeclareUnicodeCharacter{0168}{\~U}
- \DeclareUnicodeCharacter{0169}{\~u}
- \DeclareUnicodeCharacter{016A}{\=U}
- \DeclareUnicodeCharacter{016B}{\=u}
- \DeclareUnicodeCharacter{016C}{\u{U}}
- \DeclareUnicodeCharacter{016D}{\u{u}}
- \DeclareUnicodeCharacter{016E}{\ringaccent{U}}
- \DeclareUnicodeCharacter{016F}{\ringaccent{u}}
- %
- \DeclareUnicodeCharacter{0170}{\H{U}}
- \DeclareUnicodeCharacter{0171}{\H{u}}
- \DeclareUnicodeCharacter{0172}{\ogonek{U}}
- \DeclareUnicodeCharacter{0173}{\ogonek{u}}
- \DeclareUnicodeCharacter{0174}{\^W}
- \DeclareUnicodeCharacter{0175}{\^w}
- \DeclareUnicodeCharacter{0176}{\^Y}
- \DeclareUnicodeCharacter{0177}{\^y}
- \DeclareUnicodeCharacter{0178}{\"Y}
- \DeclareUnicodeCharacter{0179}{\'Z}
- \DeclareUnicodeCharacter{017A}{\'z}
- \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}
- \DeclareUnicodeCharacter{017C}{\dotaccent{z}}
- \DeclareUnicodeCharacter{017D}{\v{Z}}
- \DeclareUnicodeCharacter{017E}{\v{z}}
- \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}
- %
- \DeclareUnicodeCharacter{01C4}{D\v{Z}}
- \DeclareUnicodeCharacter{01C5}{D\v{z}}
- \DeclareUnicodeCharacter{01C6}{d\v{z}}
- \DeclareUnicodeCharacter{01C7}{LJ}
- \DeclareUnicodeCharacter{01C8}{Lj}
- \DeclareUnicodeCharacter{01C9}{lj}
- \DeclareUnicodeCharacter{01CA}{NJ}
- \DeclareUnicodeCharacter{01CB}{Nj}
- \DeclareUnicodeCharacter{01CC}{nj}
- \DeclareUnicodeCharacter{01CD}{\v{A}}
- \DeclareUnicodeCharacter{01CE}{\v{a}}
- \DeclareUnicodeCharacter{01CF}{\v{I}}
- %
- \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}
- \DeclareUnicodeCharacter{01D1}{\v{O}}
- \DeclareUnicodeCharacter{01D2}{\v{o}}
- \DeclareUnicodeCharacter{01D3}{\v{U}}
- \DeclareUnicodeCharacter{01D4}{\v{u}}
- %
- \DeclareUnicodeCharacter{01E2}{\={\AE}}
- \DeclareUnicodeCharacter{01E3}{\={\ae}}
- \DeclareUnicodeCharacter{01E6}{\v{G}}
- \DeclareUnicodeCharacter{01E7}{\v{g}}
- \DeclareUnicodeCharacter{01E8}{\v{K}}
- \DeclareUnicodeCharacter{01E9}{\v{k}}
- %
- \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}
- \DeclareUnicodeCharacter{01F1}{DZ}
- \DeclareUnicodeCharacter{01F2}{Dz}
- \DeclareUnicodeCharacter{01F3}{dz}
- \DeclareUnicodeCharacter{01F4}{\'G}
- \DeclareUnicodeCharacter{01F5}{\'g}
- \DeclareUnicodeCharacter{01F8}{\`N}
- \DeclareUnicodeCharacter{01F9}{\`n}
- \DeclareUnicodeCharacter{01FC}{\'{\AE}}
- \DeclareUnicodeCharacter{01FD}{\'{\ae}}
- \DeclareUnicodeCharacter{01FE}{\'{\O}}
- \DeclareUnicodeCharacter{01FF}{\'{\o}}
- %
- \DeclareUnicodeCharacter{021E}{\v{H}}
- \DeclareUnicodeCharacter{021F}{\v{h}}
- %
- \DeclareUnicodeCharacter{0226}{\dotaccent{A}}
- \DeclareUnicodeCharacter{0227}{\dotaccent{a}}
- \DeclareUnicodeCharacter{0228}{\cedilla{E}}
- \DeclareUnicodeCharacter{0229}{\cedilla{e}}
- \DeclareUnicodeCharacter{022E}{\dotaccent{O}}
- \DeclareUnicodeCharacter{022F}{\dotaccent{o}}
- %
- \DeclareUnicodeCharacter{0232}{\=Y}
- \DeclareUnicodeCharacter{0233}{\=y}
- \DeclareUnicodeCharacter{0237}{\dotless{j}}
- %
- \DeclareUnicodeCharacter{02DB}{\ogonek{ }}
+ \DeclareUnicodeCharacter{013F}{L\U{00B7}}%
+ %
+ \DeclareUnicodeCharacter{0140}{l\U{00B7}}%
+ \DeclareUnicodeCharacter{0141}{\L}%
+ \DeclareUnicodeCharacter{0142}{\l}%
+ \DeclareUnicodeCharacter{0143}{\'N}%
+ \DeclareUnicodeCharacter{0144}{\'n}%
+ \DeclareUnicodeCharacter{0145}{\cedilla{N}}%
+ \DeclareUnicodeCharacter{0146}{\cedilla{n}}%
+ \DeclareUnicodeCharacter{0147}{\v{N}}%
+ \DeclareUnicodeCharacter{0148}{\v{n}}%
+ \DeclareUnicodeCharacter{0149}{'n}%
+ \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}%
+ \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}%
+ \DeclareUnicodeCharacter{014C}{\=O}%
+ \DeclareUnicodeCharacter{014D}{\=o}%
+ \DeclareUnicodeCharacter{014E}{\u{O}}%
+ \DeclareUnicodeCharacter{014F}{\u{o}}%
+ %
+ \DeclareUnicodeCharacter{0150}{\H{O}}%
+ \DeclareUnicodeCharacter{0151}{\H{o}}%
+ \DeclareUnicodeCharacter{0152}{\OE}%
+ \DeclareUnicodeCharacter{0153}{\oe}%
+ \DeclareUnicodeCharacter{0154}{\'R}%
+ \DeclareUnicodeCharacter{0155}{\'r}%
+ \DeclareUnicodeCharacter{0156}{\cedilla{R}}%
+ \DeclareUnicodeCharacter{0157}{\cedilla{r}}%
+ \DeclareUnicodeCharacter{0158}{\v{R}}%
+ \DeclareUnicodeCharacter{0159}{\v{r}}%
+ \DeclareUnicodeCharacter{015A}{\'S}%
+ \DeclareUnicodeCharacter{015B}{\'s}%
+ \DeclareUnicodeCharacter{015C}{\^S}%
+ \DeclareUnicodeCharacter{015D}{\^s}%
+ \DeclareUnicodeCharacter{015E}{\cedilla{S}}%
+ \DeclareUnicodeCharacter{015F}{\cedilla{s}}%
+ %
+ \DeclareUnicodeCharacter{0160}{\v{S}}%
+ \DeclareUnicodeCharacter{0161}{\v{s}}%
+ \DeclareUnicodeCharacter{0162}{\cedilla{T}}%
+ \DeclareUnicodeCharacter{0163}{\cedilla{t}}%
+ \DeclareUnicodeCharacter{0164}{\v{T}}%
+ \DeclareUnicodeCharacter{0165}{\v{t}}%
+ \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}%
+ \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}%
+ \DeclareUnicodeCharacter{0168}{\~U}%
+ \DeclareUnicodeCharacter{0169}{\~u}%
+ \DeclareUnicodeCharacter{016A}{\=U}%
+ \DeclareUnicodeCharacter{016B}{\=u}%
+ \DeclareUnicodeCharacter{016C}{\u{U}}%
+ \DeclareUnicodeCharacter{016D}{\u{u}}%
+ \DeclareUnicodeCharacter{016E}{\ringaccent{U}}%
+ \DeclareUnicodeCharacter{016F}{\ringaccent{u}}%
+ %
+ \DeclareUnicodeCharacter{0170}{\H{U}}%
+ \DeclareUnicodeCharacter{0171}{\H{u}}%
+ \DeclareUnicodeCharacter{0172}{\ogonek{U}}%
+ \DeclareUnicodeCharacter{0173}{\ogonek{u}}%
+ \DeclareUnicodeCharacter{0174}{\^W}%
+ \DeclareUnicodeCharacter{0175}{\^w}%
+ \DeclareUnicodeCharacter{0176}{\^Y}%
+ \DeclareUnicodeCharacter{0177}{\^y}%
+ \DeclareUnicodeCharacter{0178}{\"Y}%
+ \DeclareUnicodeCharacter{0179}{\'Z}%
+ \DeclareUnicodeCharacter{017A}{\'z}%
+ \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}%
+ \DeclareUnicodeCharacter{017C}{\dotaccent{z}}%
+ \DeclareUnicodeCharacter{017D}{\v{Z}}%
+ \DeclareUnicodeCharacter{017E}{\v{z}}%
+ \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}%
+ %
+ \DeclareUnicodeCharacter{01C4}{D\v{Z}}%
+ \DeclareUnicodeCharacter{01C5}{D\v{z}}%
+ \DeclareUnicodeCharacter{01C6}{d\v{z}}%
+ \DeclareUnicodeCharacter{01C7}{LJ}%
+ \DeclareUnicodeCharacter{01C8}{Lj}%
+ \DeclareUnicodeCharacter{01C9}{lj}%
+ \DeclareUnicodeCharacter{01CA}{NJ}%
+ \DeclareUnicodeCharacter{01CB}{Nj}%
+ \DeclareUnicodeCharacter{01CC}{nj}%
+ \DeclareUnicodeCharacter{01CD}{\v{A}}%
+ \DeclareUnicodeCharacter{01CE}{\v{a}}%
+ \DeclareUnicodeCharacter{01CF}{\v{I}}%
+ %
+ \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}%
+ \DeclareUnicodeCharacter{01D1}{\v{O}}%
+ \DeclareUnicodeCharacter{01D2}{\v{o}}%
+ \DeclareUnicodeCharacter{01D3}{\v{U}}%
+ \DeclareUnicodeCharacter{01D4}{\v{u}}%
+ %
+ \DeclareUnicodeCharacter{01E2}{\={\AE}}%
+ \DeclareUnicodeCharacter{01E3}{\={\ae}}%
+ \DeclareUnicodeCharacter{01E6}{\v{G}}%
+ \DeclareUnicodeCharacter{01E7}{\v{g}}%
+ \DeclareUnicodeCharacter{01E8}{\v{K}}%
+ \DeclareUnicodeCharacter{01E9}{\v{k}}%
+ %
+ \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}%
+ \DeclareUnicodeCharacter{01F1}{DZ}%
+ \DeclareUnicodeCharacter{01F2}{Dz}%
+ \DeclareUnicodeCharacter{01F3}{dz}%
+ \DeclareUnicodeCharacter{01F4}{\'G}%
+ \DeclareUnicodeCharacter{01F5}{\'g}%
+ \DeclareUnicodeCharacter{01F8}{\`N}%
+ \DeclareUnicodeCharacter{01F9}{\`n}%
+ \DeclareUnicodeCharacter{01FC}{\'{\AE}}%
+ \DeclareUnicodeCharacter{01FD}{\'{\ae}}%
+ \DeclareUnicodeCharacter{01FE}{\'{\O}}%
+ \DeclareUnicodeCharacter{01FF}{\'{\o}}%
+ %
+ \DeclareUnicodeCharacter{021E}{\v{H}}%
+ \DeclareUnicodeCharacter{021F}{\v{h}}%
+ %
+ \DeclareUnicodeCharacter{0226}{\dotaccent{A}}%
+ \DeclareUnicodeCharacter{0227}{\dotaccent{a}}%
+ \DeclareUnicodeCharacter{0228}{\cedilla{E}}%
+ \DeclareUnicodeCharacter{0229}{\cedilla{e}}%
+ \DeclareUnicodeCharacter{022E}{\dotaccent{O}}%
+ \DeclareUnicodeCharacter{022F}{\dotaccent{o}}%
+ %
+ \DeclareUnicodeCharacter{0232}{\=Y}%
+ \DeclareUnicodeCharacter{0233}{\=y}%
+ \DeclareUnicodeCharacter{0237}{\dotless{j}}%
+ %
+ \DeclareUnicodeCharacter{02DB}{\ogonek{ }}%
%
% Greek letters upper case
- \DeclareUnicodeCharacter{0391}{{\it A}}
- \DeclareUnicodeCharacter{0392}{{\it B}}
- \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}
- \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}
- \DeclareUnicodeCharacter{0395}{{\it E}}
- \DeclareUnicodeCharacter{0396}{{\it Z}}
- \DeclareUnicodeCharacter{0397}{{\it H}}
- \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}
- \DeclareUnicodeCharacter{0399}{{\it I}}
- \DeclareUnicodeCharacter{039A}{{\it K}}
- \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}
- \DeclareUnicodeCharacter{039C}{{\it M}}
- \DeclareUnicodeCharacter{039D}{{\it N}}
- \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}
- \DeclareUnicodeCharacter{039F}{{\it O}}
- \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}
- \DeclareUnicodeCharacter{03A1}{{\it P}}
+ \DeclareUnicodeCharacter{0391}{{\it A}}%
+ \DeclareUnicodeCharacter{0392}{{\it B}}%
+ \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}%
+ \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}%
+ \DeclareUnicodeCharacter{0395}{{\it E}}%
+ \DeclareUnicodeCharacter{0396}{{\it Z}}%
+ \DeclareUnicodeCharacter{0397}{{\it H}}%
+ \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}%
+ \DeclareUnicodeCharacter{0399}{{\it I}}%
+ \DeclareUnicodeCharacter{039A}{{\it K}}%
+ \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}%
+ \DeclareUnicodeCharacter{039C}{{\it M}}%
+ \DeclareUnicodeCharacter{039D}{{\it N}}%
+ \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}%
+ \DeclareUnicodeCharacter{039F}{{\it O}}%
+ \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}%
+ \DeclareUnicodeCharacter{03A1}{{\it P}}%
%\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma
- \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}
- \DeclareUnicodeCharacter{03A4}{{\it T}}
- \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}
- \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}
- \DeclareUnicodeCharacter{03A7}{{\it X}}
- \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}
- \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}
+ \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}%
+ \DeclareUnicodeCharacter{03A4}{{\it T}}%
+ \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}%
+ \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}%
+ \DeclareUnicodeCharacter{03A7}{{\it X}}%
+ \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}%
+ \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}%
%
% Vowels with accents
- \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}
- \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}
- \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}
- \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}
- \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}
- \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}
+ \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}%
+ \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}%
+ \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}%
+ \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}%
+ \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}%
+ \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}%
%
% Standalone accent
- \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}
+ \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}%
%
% Greek letters lower case
- \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}
- \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}
- \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}
- \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}
- \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}
- \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}
- \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}
- \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}
- \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}
- \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}
- \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}
- \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}
- \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}
- \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}
- \DeclareUnicodeCharacter{03BF}{{\it o}} % omicron
- \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}
- \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}
- \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}
- \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}
- \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}
- \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}
- \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}
- \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}
- \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}
- \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}
+ \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}%
+ \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}%
+ \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}%
+ \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}%
+ \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}%
+ \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}%
+ \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}%
+ \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}%
+ \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}%
+ \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}%
+ \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}%
+ \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}%
+ \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}%
+ \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}%
+ \DeclareUnicodeCharacter{03BF}{{\it o}}% omicron
+ \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}%
+ \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}%
+ \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}%
+ \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}%
+ \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}%
+ \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}%
+ \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}%
+ \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}%
+ \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}%
+ \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}%
%
% More Greek vowels with accents
- \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}
- \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}
- \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}
- \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}
- \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}
+ \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}%
+ \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}%
+ \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}%
+ \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}%
+ \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}%
%
% Variant Greek letters
- \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}
- \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}
- \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}
- %
- \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}
- \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}
- \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}
- \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}
- \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}
- \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}
- \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}
- \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}
- \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}
- \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}
- \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}
- \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}
- %
- \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}
- \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}
- %
- \DeclareUnicodeCharacter{1E20}{\=G}
- \DeclareUnicodeCharacter{1E21}{\=g}
- \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}
- \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}
- \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}
- \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}
- \DeclareUnicodeCharacter{1E26}{\"H}
- \DeclareUnicodeCharacter{1E27}{\"h}
- %
- \DeclareUnicodeCharacter{1E30}{\'K}
- \DeclareUnicodeCharacter{1E31}{\'k}
- \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}
- \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}
- \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}
- \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}
- \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}
- \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}
- \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}
- \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}
- \DeclareUnicodeCharacter{1E3E}{\'M}
- \DeclareUnicodeCharacter{1E3F}{\'m}
- %
- \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}
- \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}
- \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}
- \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}
- \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}
- \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}
- \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}
- \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}
- \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}
- \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}
- %
- \DeclareUnicodeCharacter{1E54}{\'P}
- \DeclareUnicodeCharacter{1E55}{\'p}
- \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}
- \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}
- \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}
- \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}
- \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}
- \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}
- \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}
- \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}
- %
- \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}
- \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}
- \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}
- \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}
- \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}
- \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}
- \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}
- \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}
- \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}
- \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}
- %
- \DeclareUnicodeCharacter{1E7C}{\~V}
- \DeclareUnicodeCharacter{1E7D}{\~v}
- \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}
- \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}
- %
- \DeclareUnicodeCharacter{1E80}{\`W}
- \DeclareUnicodeCharacter{1E81}{\`w}
- \DeclareUnicodeCharacter{1E82}{\'W}
- \DeclareUnicodeCharacter{1E83}{\'w}
- \DeclareUnicodeCharacter{1E84}{\"W}
- \DeclareUnicodeCharacter{1E85}{\"w}
- \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}
- \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}
- \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}
- \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}
- \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}
- \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}
- \DeclareUnicodeCharacter{1E8C}{\"X}
- \DeclareUnicodeCharacter{1E8D}{\"x}
- \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}
- \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}
- %
- \DeclareUnicodeCharacter{1E90}{\^Z}
- \DeclareUnicodeCharacter{1E91}{\^z}
- \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}
- \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}
- \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}
- \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}
- \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}
- \DeclareUnicodeCharacter{1E97}{\"t}
- \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}
- \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}
- %
- \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}
- \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}
- %
- \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}
- \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}
- \DeclareUnicodeCharacter{1EBC}{\~E}
- \DeclareUnicodeCharacter{1EBD}{\~e}
- %
- \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}
- \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}
- \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}
- \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}
- %
- \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}
- \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}
- %
- \DeclareUnicodeCharacter{1EF2}{\`Y}
- \DeclareUnicodeCharacter{1EF3}{\`y}
- \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}
- %
- \DeclareUnicodeCharacter{1EF8}{\~Y}
- \DeclareUnicodeCharacter{1EF9}{\~y}
+ \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}%
+ \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}%
+ \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}%
+ %
+ \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}%
+ \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}%
+ \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}%
+ \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}%
+ \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}%
+ \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}%
+ \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}%
+ \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}%
+ \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}%
+ \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}%
+ \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}%
+ \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}%
+ %
+ \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}%
+ \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}%
+ %
+ \DeclareUnicodeCharacter{1E20}{\=G}%
+ \DeclareUnicodeCharacter{1E21}{\=g}%
+ \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}%
+ \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}%
+ \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}%
+ \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}%
+ \DeclareUnicodeCharacter{1E26}{\"H}%
+ \DeclareUnicodeCharacter{1E27}{\"h}%
+ %
+ \DeclareUnicodeCharacter{1E30}{\'K}%
+ \DeclareUnicodeCharacter{1E31}{\'k}%
+ \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}%
+ \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}%
+ \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}%
+ \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}%
+ \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}%
+ \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}%
+ \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}%
+ \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}%
+ \DeclareUnicodeCharacter{1E3E}{\'M}%
+ \DeclareUnicodeCharacter{1E3F}{\'m}%
+ %
+ \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}%
+ \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}%
+ \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}%
+ \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}%
+ \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}%
+ \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}%
+ \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}%
+ \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}%
+ \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}%
+ \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}%
+ %
+ \DeclareUnicodeCharacter{1E54}{\'P}%
+ \DeclareUnicodeCharacter{1E55}{\'p}%
+ \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}%
+ \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}%
+ \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}%
+ \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}%
+ \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}%
+ \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}%
+ \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}%
+ \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}%
+ %
+ \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}%
+ \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}%
+ \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}%
+ \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}%
+ \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}%
+ \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}%
+ \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}%
+ \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}%
+ \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}%
+ \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}%
+ %
+ \DeclareUnicodeCharacter{1E7C}{\~V}%
+ \DeclareUnicodeCharacter{1E7D}{\~v}%
+ \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}%
+ \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}%
+ %
+ \DeclareUnicodeCharacter{1E80}{\`W}%
+ \DeclareUnicodeCharacter{1E81}{\`w}%
+ \DeclareUnicodeCharacter{1E82}{\'W}%
+ \DeclareUnicodeCharacter{1E83}{\'w}%
+ \DeclareUnicodeCharacter{1E84}{\"W}%
+ \DeclareUnicodeCharacter{1E85}{\"w}%
+ \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}%
+ \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}%
+ \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}%
+ \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}%
+ \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}%
+ \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}%
+ \DeclareUnicodeCharacter{1E8C}{\"X}%
+ \DeclareUnicodeCharacter{1E8D}{\"x}%
+ \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}%
+ \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}%
+ %
+ \DeclareUnicodeCharacter{1E90}{\^Z}%
+ \DeclareUnicodeCharacter{1E91}{\^z}%
+ \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}%
+ \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}%
+ \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}%
+ \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}%
+ \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}%
+ \DeclareUnicodeCharacter{1E97}{\"t}%
+ \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}%
+ \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}%
+ %
+ \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}%
+ \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}%
+ %
+ \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}%
+ \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}%
+ \DeclareUnicodeCharacter{1EBC}{\~E}%
+ \DeclareUnicodeCharacter{1EBD}{\~e}%
+ %
+ \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}%
+ \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}%
+ \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}%
+ \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}%
+ %
+ \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}%
+ \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}%
+ %
+ \DeclareUnicodeCharacter{1EF2}{\`Y}%
+ \DeclareUnicodeCharacter{1EF3}{\`y}%
+ \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}%
+ %
+ \DeclareUnicodeCharacter{1EF8}{\~Y}%
+ \DeclareUnicodeCharacter{1EF9}{\~y}%
%
% Punctuation
- \DeclareUnicodeCharacter{2013}{--}
- \DeclareUnicodeCharacter{2014}{---}
- \DeclareUnicodeCharacter{2018}{\quoteleft}
- \DeclareUnicodeCharacter{2019}{\quoteright}
- \DeclareUnicodeCharacter{201A}{\quotesinglbase}
- \DeclareUnicodeCharacter{201C}{\quotedblleft}
- \DeclareUnicodeCharacter{201D}{\quotedblright}
- \DeclareUnicodeCharacter{201E}{\quotedblbase}
- \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}
- \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}
- \DeclareUnicodeCharacter{2022}{\bullet}
- \DeclareUnicodeCharacter{202F}{\thinspace}
- \DeclareUnicodeCharacter{2026}{\dots}
- \DeclareUnicodeCharacter{2039}{\guilsinglleft}
- \DeclareUnicodeCharacter{203A}{\guilsinglright}
- %
- \DeclareUnicodeCharacter{20AC}{\euro}
- %
- \DeclareUnicodeCharacter{2192}{\expansion}
- \DeclareUnicodeCharacter{21D2}{\result}
+ \DeclareUnicodeCharacter{2013}{--}%
+ \DeclareUnicodeCharacter{2014}{---}%
+ \DeclareUnicodeCharacter{2018}{\quoteleft{}}%
+ \DeclareUnicodeCharacter{2019}{\quoteright{}}%
+ \DeclareUnicodeCharacter{201A}{\quotesinglbase{}}%
+ \DeclareUnicodeCharacter{201C}{\quotedblleft{}}%
+ \DeclareUnicodeCharacter{201D}{\quotedblright{}}%
+ \DeclareUnicodeCharacter{201E}{\quotedblbase{}}%
+ \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}%
+ \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}%
+ \DeclareUnicodeCharacter{2022}{\bullet{}}%
+ \DeclareUnicodeCharacter{202F}{\thinspace}%
+ \DeclareUnicodeCharacter{2026}{\dots{}}%
+ \DeclareUnicodeCharacter{2039}{\guilsinglleft{}}%
+ \DeclareUnicodeCharacter{203A}{\guilsinglright{}}%
+ %
+ \DeclareUnicodeCharacter{20AC}{\euro{}}%
+ %
+ \DeclareUnicodeCharacter{2192}{\expansion{}}%
+ \DeclareUnicodeCharacter{21D2}{\result{}}%
%
% Mathematical symbols
- \DeclareUnicodeCharacter{2200}{\ensuremath\forall}
- \DeclareUnicodeCharacter{2203}{\ensuremath\exists}
- \DeclareUnicodeCharacter{2208}{\ensuremath\in}
- \DeclareUnicodeCharacter{2212}{\minus}
- \DeclareUnicodeCharacter{2217}{\ast}
- \DeclareUnicodeCharacter{221E}{\ensuremath\infty}
- \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}
- \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}
- \DeclareUnicodeCharacter{2229}{\ensuremath\cap}
- \DeclareUnicodeCharacter{2261}{\equiv}
- \DeclareUnicodeCharacter{2264}{\ensuremath\leq}
- \DeclareUnicodeCharacter{2265}{\ensuremath\geq}
- \DeclareUnicodeCharacter{2282}{\ensuremath\subset}
- \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}
- %
- \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}
- \DeclareUnicodeCharacter{2032}{\ensuremath\prime}
- \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}
- \DeclareUnicodeCharacter{2111}{\ensuremath\Im}
- \DeclareUnicodeCharacter{2113}{\ensuremath\ell}
- \DeclareUnicodeCharacter{2118}{\ensuremath\wp}
- \DeclareUnicodeCharacter{211C}{\ensuremath\Re}
- \DeclareUnicodeCharacter{2127}{\ensuremath\mho}
- \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}
- \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}
- \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}
- \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}
- \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}
- \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}
- \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}
- \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}
- \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}
- \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}
- \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}
- \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}
- \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}
- \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}
- \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}
- \DeclareUnicodeCharacter{21BE}{\ensuremath\upharpoonright}
- \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}
- \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}
- \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}
- \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}
- \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}
- \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}
- \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}
- \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}
- \DeclareUnicodeCharacter{21DD}{\ensuremath\leadsto}
- \DeclareUnicodeCharacter{2201}{\ensuremath\complement}
- \DeclareUnicodeCharacter{2202}{\ensuremath\partial}
- \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}
- \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}
- \DeclareUnicodeCharacter{2209}{\ensuremath\notin}
- \DeclareUnicodeCharacter{220B}{\ensuremath\owns}
- \DeclareUnicodeCharacter{220F}{\ensuremath\prod}
- \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}
- \DeclareUnicodeCharacter{2211}{\ensuremath\sum}
- \DeclareUnicodeCharacter{2213}{\ensuremath\mp}
- \DeclareUnicodeCharacter{2218}{\ensuremath\circ}
- \DeclareUnicodeCharacter{221A}{\ensuremath\surd}
- \DeclareUnicodeCharacter{221D}{\ensuremath\propto}
- \DeclareUnicodeCharacter{2220}{\ensuremath\angle}
- \DeclareUnicodeCharacter{2223}{\ensuremath\mid}
- \DeclareUnicodeCharacter{2228}{\ensuremath\vee}
- \DeclareUnicodeCharacter{222A}{\ensuremath\cup}
- \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}
- \DeclareUnicodeCharacter{222E}{\ensuremath\oint}
- \DeclareUnicodeCharacter{223C}{\ensuremath\sim}
- \DeclareUnicodeCharacter{2240}{\ensuremath\wr}
- \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}
- \DeclareUnicodeCharacter{2245}{\ensuremath\cong}
- \DeclareUnicodeCharacter{2248}{\ensuremath\approx}
- \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}
- \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}
- \DeclareUnicodeCharacter{2260}{\ensuremath\neq}
- \DeclareUnicodeCharacter{226A}{\ensuremath\ll}
- \DeclareUnicodeCharacter{226B}{\ensuremath\gg}
- \DeclareUnicodeCharacter{227A}{\ensuremath\prec}
- \DeclareUnicodeCharacter{227B}{\ensuremath\succ}
- \DeclareUnicodeCharacter{2283}{\ensuremath\supset}
- \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}
- \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}
- \DeclareUnicodeCharacter{228F}{\ensuremath\sqsubset}
- \DeclareUnicodeCharacter{2290}{\ensuremath\sqsupset}
- \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}
- \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}
- \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}
- \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}
- \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}
- \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}
- \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}
- \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}
- \DeclareUnicodeCharacter{2299}{\ensuremath\odot}
- \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}
- \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}
- \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}
- \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}
- \DeclareUnicodeCharacter{22A8}{\ensuremath\models}
- \DeclareUnicodeCharacter{22B4}{\ensuremath\unlhd}
- \DeclareUnicodeCharacter{22B5}{\ensuremath\unrhd}
- \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}
- \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}
- \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}
- \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}
- \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}
- \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}
- \DeclareUnicodeCharacter{22C6}{\ensuremath\star}
- \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}
- \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}
- \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}
- \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}
- \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}
- \DeclareUnicodeCharacter{2322}{\ensuremath\frown}
- \DeclareUnicodeCharacter{2323}{\ensuremath\smile}
- %
- \DeclareUnicodeCharacter{25A1}{\ensuremath\Box}
- \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}
- \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}
- \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}
- \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}
- \DeclareUnicodeCharacter{25C7}{\ensuremath\Diamond}
- \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}
- \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}
- \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}
- \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}
- \DeclareUnicodeCharacter{266D}{\ensuremath\flat}
- \DeclareUnicodeCharacter{266E}{\ensuremath\natural}
- \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}
- \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}
- \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}
- \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}
- \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}
- \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}
- \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}
- \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}
- \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}
- \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}
- \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}
- \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}
- \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}
- \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}
- \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}
- \DeclareUnicodeCharacter{2A1D}{\ensuremath\Join}
- \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}
- \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}
- \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}
- %
- \global\mathchardef\checkmark="1370 % actually the square root sign
- \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}
-}% end of \utfeightchardefs
+ \DeclareUnicodeCharacter{2200}{\ensuremath\forall}%
+ \DeclareUnicodeCharacter{2203}{\ensuremath\exists}%
+ \DeclareUnicodeCharacter{2208}{\ensuremath\in}%
+ \DeclareUnicodeCharacter{2212}{\minus{}}%
+ \DeclareUnicodeCharacter{2217}{\ast}%
+ \DeclareUnicodeCharacter{221E}{\ensuremath\infty}%
+ \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}%
+ \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}%
+ \DeclareUnicodeCharacter{2229}{\ensuremath\cap}%
+ \DeclareUnicodeCharacter{2261}{\equiv{}}%
+ \DeclareUnicodeCharacter{2264}{\ensuremath\leq}%
+ \DeclareUnicodeCharacter{2265}{\ensuremath\geq}%
+ \DeclareUnicodeCharacter{2282}{\ensuremath\subset}%
+ \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}%
+ %
+ \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}%
+ \DeclareUnicodeCharacter{2032}{\ensuremath\prime}%
+ \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}%
+ \DeclareUnicodeCharacter{2111}{\ensuremath\Im}%
+ \DeclareUnicodeCharacter{2113}{\ensuremath\ell}%
+ \DeclareUnicodeCharacter{2118}{\ensuremath\wp}%
+ \DeclareUnicodeCharacter{211C}{\ensuremath\Re}%
+ \DeclareUnicodeCharacter{2127}{\ensuremath\mho}%
+ \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}%
+ \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}%
+ \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}%
+ \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}%
+ \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}%
+ \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}%
+ \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}%
+ \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}%
+ \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}%
+ \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}%
+ \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}%
+ \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}%
+ \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}%
+ \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}%
+ \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}%
+ \DeclareUnicodeCharacter{21BE}{\ensuremath\upharpoonright}%
+ \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}%
+ \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}%
+ \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}%
+ \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}%
+ \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}%
+ \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}%
+ \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}%
+ \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}%
+ \DeclareUnicodeCharacter{21DD}{\ensuremath\leadsto}%
+ \DeclareUnicodeCharacter{2201}{\ensuremath\complement}%
+ \DeclareUnicodeCharacter{2202}{\ensuremath\partial}%
+ \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}%
+ \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}%
+ \DeclareUnicodeCharacter{2209}{\ensuremath\notin}%
+ \DeclareUnicodeCharacter{220B}{\ensuremath\owns}%
+ \DeclareUnicodeCharacter{220F}{\ensuremath\prod}%
+ \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}%
+ \DeclareUnicodeCharacter{2211}{\ensuremath\sum}%
+ \DeclareUnicodeCharacter{2213}{\ensuremath\mp}%
+ \DeclareUnicodeCharacter{2218}{\ensuremath\circ}%
+ \DeclareUnicodeCharacter{221A}{\ensuremath\surd}%
+ \DeclareUnicodeCharacter{221D}{\ensuremath\propto}%
+ \DeclareUnicodeCharacter{2220}{\ensuremath\angle}%
+ \DeclareUnicodeCharacter{2223}{\ensuremath\mid}%
+ \DeclareUnicodeCharacter{2228}{\ensuremath\vee}%
+ \DeclareUnicodeCharacter{222A}{\ensuremath\cup}%
+ \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}%
+ \DeclareUnicodeCharacter{222E}{\ensuremath\oint}%
+ \DeclareUnicodeCharacter{223C}{\ensuremath\sim}%
+ \DeclareUnicodeCharacter{2240}{\ensuremath\wr}%
+ \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}%
+ \DeclareUnicodeCharacter{2245}{\ensuremath\cong}%
+ \DeclareUnicodeCharacter{2248}{\ensuremath\approx}%
+ \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}%
+ \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}%
+ \DeclareUnicodeCharacter{2260}{\ensuremath\neq}%
+ \DeclareUnicodeCharacter{226A}{\ensuremath\ll}%
+ \DeclareUnicodeCharacter{226B}{\ensuremath\gg}%
+ \DeclareUnicodeCharacter{227A}{\ensuremath\prec}%
+ \DeclareUnicodeCharacter{227B}{\ensuremath\succ}%
+ \DeclareUnicodeCharacter{2283}{\ensuremath\supset}%
+ \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}%
+ \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}%
+ \DeclareUnicodeCharacter{228F}{\ensuremath\sqsubset}%
+ \DeclareUnicodeCharacter{2290}{\ensuremath\sqsupset}%
+ \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}%
+ \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}%
+ \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}%
+ \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}%
+ \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}%
+ \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}%
+ \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}%
+ \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}%
+ \DeclareUnicodeCharacter{2299}{\ensuremath\odot}%
+ \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}%
+ \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}%
+ \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}%
+ \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}%
+ \DeclareUnicodeCharacter{22A8}{\ensuremath\models}%
+ \DeclareUnicodeCharacter{22B4}{\ensuremath\unlhd}%
+ \DeclareUnicodeCharacter{22B5}{\ensuremath\unrhd}%
+ \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}%
+ \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}%
+ \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}%
+ \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}%
+ \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}%
+ \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}%
+ \DeclareUnicodeCharacter{22C6}{\ensuremath\star}%
+ \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}%
+ \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}%
+ \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}%
+ \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}%
+ \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}%
+ \DeclareUnicodeCharacter{2322}{\ensuremath\frown}%
+ \DeclareUnicodeCharacter{2323}{\ensuremath\smile}%
+ %
+ \DeclareUnicodeCharacter{25A1}{\ensuremath\Box}%
+ \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}%
+ \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}%
+ \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}%
+ \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}%
+ \DeclareUnicodeCharacter{25C7}{\ensuremath\Diamond}%
+ \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}%
+ \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}%
+ \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}%
+ \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}%
+ \DeclareUnicodeCharacter{266D}{\ensuremath\flat}%
+ \DeclareUnicodeCharacter{266E}{\ensuremath\natural}%
+ \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}%
+ \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}%
+ \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}%
+ \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}%
+ \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}%
+ \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}%
+ \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}%
+ \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}%
+ \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}%
+ \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}%
+ \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}%
+ \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}%
+ \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}%
+ \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}%
+ \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}%
+ \DeclareUnicodeCharacter{2A1D}{\ensuremath\Join}%
+ \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}%
+ \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}%
+ \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}%
+ %
+ \global\mathchardef\checkmark="1370% actually the square root sign
+ \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}%
+}% end of \unicodechardefs
+
+% UTF-8 byte sequence (pdfTeX) definitions (replacing and @U command)
+% It makes the setting that replace UTF-8 byte sequence.
+\def\utfeightchardefs{%
+ \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterUTFviii
+ \unicodechardefs
+}
-% US-ASCII character definitions.
-\def\asciichardefs{% nothing need be done
- \relax
+% Whether the active definitions of non-ASCII characters expand to
+% non-active tokens with the same character code. This is used to
+% write characters literally, instead of using active definitions for
+% printing the correct glyphs.
+\newif\ifpassthroughchars
+\passthroughcharsfalse
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro to replace/pass-through a Unicode character
+%
+\def\DeclareUnicodeCharacterNative#1#2{%
+ \catcode"#1=\active
+ \def\dodeclareunicodecharacternative##1##2##3{%
+ \begingroup
+ \uccode`\~="##2\relax
+ \uppercase{\gdef~}{%
+ \ifpassthroughchars
+ ##1%
+ \else
+ ##3%
+ \fi
+ }
+ \endgroup
+ }
+ \begingroup
+ \uccode`\.="#1\relax
+ \uppercase{\def\UTFNativeTmp{.}}%
+ \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}%
+ \endgroup
}
-% Latin1 (ISO-8859-1) character definitions.
-\def\nonasciistringdefs{%
- \setnonasciicharscatcode\active
- \def\defstringchar##1{\def##1{\string##1}}%
- %
- \defstringchar^^80\defstringchar^^81\defstringchar^^82\defstringchar^^83%
- \defstringchar^^84\defstringchar^^85\defstringchar^^86\defstringchar^^87%
- \defstringchar^^88\defstringchar^^89\defstringchar^^8a\defstringchar^^8b%
- \defstringchar^^8c\defstringchar^^8d\defstringchar^^8e\defstringchar^^8f%
- %
- \defstringchar^^90\defstringchar^^91\defstringchar^^92\defstringchar^^93%
- \defstringchar^^94\defstringchar^^95\defstringchar^^96\defstringchar^^97%
- \defstringchar^^98\defstringchar^^99\defstringchar^^9a\defstringchar^^9b%
- \defstringchar^^9c\defstringchar^^9d\defstringchar^^9e\defstringchar^^9f%
- %
- \defstringchar^^a0\defstringchar^^a1\defstringchar^^a2\defstringchar^^a3%
- \defstringchar^^a4\defstringchar^^a5\defstringchar^^a6\defstringchar^^a7%
- \defstringchar^^a8\defstringchar^^a9\defstringchar^^aa\defstringchar^^ab%
- \defstringchar^^ac\defstringchar^^ad\defstringchar^^ae\defstringchar^^af%
- %
- \defstringchar^^b0\defstringchar^^b1\defstringchar^^b2\defstringchar^^b3%
- \defstringchar^^b4\defstringchar^^b5\defstringchar^^b6\defstringchar^^b7%
- \defstringchar^^b8\defstringchar^^b9\defstringchar^^ba\defstringchar^^bb%
- \defstringchar^^bc\defstringchar^^bd\defstringchar^^be\defstringchar^^bf%
- %
- \defstringchar^^c0\defstringchar^^c1\defstringchar^^c2\defstringchar^^c3%
- \defstringchar^^c4\defstringchar^^c5\defstringchar^^c6\defstringchar^^c7%
- \defstringchar^^c8\defstringchar^^c9\defstringchar^^ca\defstringchar^^cb%
- \defstringchar^^cc\defstringchar^^cd\defstringchar^^ce\defstringchar^^cf%
- %
- \defstringchar^^d0\defstringchar^^d1\defstringchar^^d2\defstringchar^^d3%
- \defstringchar^^d4\defstringchar^^d5\defstringchar^^d6\defstringchar^^d7%
- \defstringchar^^d8\defstringchar^^d9\defstringchar^^da\defstringchar^^db%
- \defstringchar^^dc\defstringchar^^dd\defstringchar^^de\defstringchar^^df%
- %
- \defstringchar^^e0\defstringchar^^e1\defstringchar^^e2\defstringchar^^e3%
- \defstringchar^^e4\defstringchar^^e5\defstringchar^^e6\defstringchar^^e7%
- \defstringchar^^e8\defstringchar^^e9\defstringchar^^ea\defstringchar^^eb%
- \defstringchar^^ec\defstringchar^^ed\defstringchar^^ee\defstringchar^^ef%
- %
- \defstringchar^^f0\defstringchar^^f1\defstringchar^^f2\defstringchar^^f3%
- \defstringchar^^f4\defstringchar^^f5\defstringchar^^f6\defstringchar^^f7%
- \defstringchar^^f8\defstringchar^^f9\defstringchar^^fa\defstringchar^^fb%
- \defstringchar^^fc\defstringchar^^fd\defstringchar^^fe\defstringchar^^ff%
+% Native Unicode handling (XeTeX and LuaTeX) character replacing definition.
+% It activates the setting that replaces Unicode characters.
+\def\nativeunicodechardefs{%
+ \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNative
+ \unicodechardefs
+}
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% make the character token expand
+% to the sequences given in \unicodechardefs for printing.
+\def\DeclareUnicodeCharacterNativeAtU#1#2{%
+ \def\UTFAtUTmp{#2}
+ \expandafter\globallet\csname uni:#1\endcsname \UTFAtUTmp
+}
+
+% @U command definitions for native Unicode handling (XeTeX and LuaTeX).
+\def\nativeunicodechardefsatu{%
+ \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNativeAtU
+ \unicodechardefs
}
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+ \relax
+}
-% define all the unicode characters we know about, for the sake of @U.
-\utfeightchardefs
+% define all Unicode characters we know about, for the sake of @U.
+\iftxinativeunicodecapable
+ \nativeunicodechardefsatu
+\else
+ \utfeightchardefs
+\fi
% Make non-ASCII characters printable again for compatibility with
@@ -10787,12 +11265,12 @@ callback.register("process_output_buffer", convert_line_out)
\advance\vsize by \topskip
\outervsize = \vsize
\advance\outervsize by 2\topandbottommargin
- \pageheight = \vsize
+ \txipageheight = \vsize
%
\hsize = #2\relax
\outerhsize = \hsize
\advance\outerhsize by 0.5in
- \pagewidth = \hsize
+ \txipagewidth = \hsize
%
\normaloffset = #4\relax
\bindingoffset = #5\relax
@@ -10804,6 +11282,14 @@ callback.register("process_output_buffer", convert_line_out)
% whatever layout pdftex was dumped with.
\pdfhorigin = 1 true in
\pdfvorigin = 1 true in
+ \else
+ \ifx\XeTeXrevision\thisisundefined
+ \special{papersize=#8,#7}%
+ \else
+ \pdfpageheight #7\relax
+ \pdfpagewidth #8\relax
+ % XeTeX does not have \pdfhorigin and \pdfvorigin.
+ \fi
\fi
%
\setleading{\textleading}
@@ -10836,7 +11322,6 @@ callback.register("process_output_buffer", convert_line_out)
%
\lispnarrowing = 0.3in
\tolerance = 700
- \hfuzz = 1pt
\contentsrightmargin = 0pt
\defbodyindent = .5cm
}}
@@ -10854,7 +11339,6 @@ callback.register("process_output_buffer", convert_line_out)
%
\lispnarrowing = 0.25in
\tolerance = 700
- \hfuzz = 1pt
\contentsrightmargin = 0pt
\defbodyindent = .4cm
}}
@@ -10880,7 +11364,6 @@ callback.register("process_output_buffer", convert_line_out)
{297mm}{210mm}%
%
\tolerance = 700
- \hfuzz = 1pt
\contentsrightmargin = 0pt
\defbodyindent = 5mm
}}
@@ -10899,7 +11382,6 @@ callback.register("process_output_buffer", convert_line_out)
%
\lispnarrowing = 0.2in
\tolerance = 800
- \hfuzz = 1.2pt
\contentsrightmargin = 0pt
\defbodyindent = 2mm
\tableindent = 12mm
@@ -10955,6 +11437,9 @@ callback.register("process_output_buffer", convert_line_out)
%
\letterpaper
+% Default value of \hfuzz, for suppressing warnings about overfull hboxes.
+\hfuzz = 1pt
+
\message{and turning on texinfo input format.}
@@ -11078,7 +11563,7 @@ callback.register("process_output_buffer", convert_line_out)
%
{@catcode`- = @active
@gdef@normalturnoffactive{%
- @nonasciistringdefs
+ @passthroughcharstrue
@let-=@normaldash
@let"=@normaldoublequote
@let$=@normaldollar %$ font-lock fix
@@ -11116,9 +11601,13 @@ callback.register("process_output_buffer", convert_line_out)
@global@let\ = @eatinput%
@catcode`@^^M=13%
@def@c{@fixbackslash@c}%
+ % Definition for the newline at the end of this file.
@def ^^M{@let^^M@secondlinenl}%
- @gdef @secondlinenl{@let^^M@thirdlinenl}%
- @gdef @thirdlinenl{@fixbackslash}%
+ % Definition for a newline in the main Texinfo file.
+ @gdef @secondlinenl{@fixbackslash}%
+ % In case the first line has a whole-line command on it
+ @let@originalparsearg@parsearg
+ @def@parsearg{@fixbackslash@originalparsearg}
}}
{@catcode`@^=7 @catcode`@^^M=13%
@@ -11139,6 +11628,7 @@ callback.register("process_output_buffer", convert_line_out)
@catcode13=5 % regular end of line
@enableemergencynewline
@let@c=@texinfoc
+ @let@parsearg@originalparsearg
% Also turn back on active characters that might appear in the input
% file name, in case not using a pre-dumped format.
@catcode`+=@active
@@ -11192,7 +11682,4 @@ callback.register("process_output_buffer", convert_line_out)
@c vim:sw=2:
-@ignore
- arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115
-@end ignore
@enablebackslashhack
diff --git a/doc/wordlist b/doc/wordlist
index 37e1552c..d0464dc9 100644
--- a/doc/wordlist
+++ b/doc/wordlist
@@ -390,6 +390,7 @@ POS
POSIX
POSIXLY
PP
+PQgetvalue
PREC
PROCINFO
PVERSION
@@ -421,6 +422,7 @@ Quicksort
QuikTrim
RANLIB
README
+REGEX
RELICENSING
REVOUT
RLENGTH
@@ -436,6 +438,7 @@ Readfile
Readline
Redirections
Redis
+Regex
Regexp
Regexps
Reimplementing
@@ -483,6 +486,7 @@ Solaris
Stallman
Stepan
Stewartson's
+Strnum
Strtonum
Subarrays
Sublicensing
@@ -879,6 +883,7 @@ dir
dircategory
direntry
distributable
+div
djgpp
dl
dlload
@@ -969,6 +974,7 @@ fdata
fe
ferror
fffffffffff
+fffffffffffd
fflush
fi
fieldlist
@@ -988,6 +994,7 @@ filetype
filll
finalout
findpat
+finfo
finx
firstname
flac
@@ -1700,6 +1707,7 @@ strerror
strftime
strlen
strnum
+strnums
strtod
strtonum
struct
@@ -1902,6 +1910,7 @@ xdeadBEEF
xdigit
xfcc
xfcd
+xffffffffffffffd
xgawk
xgettext
xnrkb
diff --git a/doc/wordlist2 b/doc/wordlist2
new file mode 100644
index 00000000..0d2db288
--- /dev/null
+++ b/doc/wordlist2
@@ -0,0 +1,178 @@
+Autoconf
+Automake
+Autotools
+Awk
+Bernat
+CFLAGS
+ChangeLog
+Ctrl
+FIXME
+FSF
+FSF's
+Gettext
+GitHub
+ISBN
+Kahrs
+Libtool
+PCC
+PDF
+Rebase
+Rebasing
+Repo
+SVN
+TODO
+Texinfo
+UsingGit
+Workflow
+Yehezkel
+ac
+api
+arnold
+arnoldrobbins
+async
+autoconf
+autocrlf
+automake
+autotools
+awk
+awkgram
+builtin
+cd
+cindex
+com
+config
+const
+cp
+cvs
+cz
+da
+detailmenu
+dfn
+diff
+diffs
+difftool
+dircategory
+direntry
+distclean
+docbook
+du
+dvi
+emph
+en
+env
+evenheading
+expandtab
+filetype
+filll
+finalout
+fn
+gawktexi
+gawkworkflow
+gc
+gcc
+gdef
+gettext
+gitconfig
+github
+gvim
+html
+http
+https
+iface
+ifdocbook
+ifhtml
+ifinfo
+ifnotdocbook
+ifnothtml
+ifnotinfo
+ifnottex
+ifnotxml
+ifplaintext
+iftex
+ifxml
+inlineraw
+insertcopying
+jpdev
+kbd
+libtool
+lineannotation
+linkcolor
+listinfo
+literallayout
+llvm
+ltu
+ludd
+makeinfo
+mpfr
+multiplestates
+mychange
+newfile
+noindent
+nongnu
+oddheading
+oldfile
+org
+ourfile
+overfulls
+para
+pc
+pcc
+po
+printindex
+pt
+pxref
+rebase
+rebasing
+regexp
+repo
+repo's
+samp
+scm
+se
+setchapternewpage
+setfilename
+settitle
+shiftwidth
+shorttitlepage
+smallbook
+smallexample
+sp
+srv
+ssh
+stderr
+stdout
+summarycontents
+sv
+syncodeindex
+synindex
+tabstop
+tcc
+tex
+texi
+texinfo
+thischapter
+thispage
+titlepage
+tmp
+toto
+ui
+ulink
+unnumberedsec
+upstream's
+uref
+urefurlonlylinktrue
+urgen
+url
+urlcolor
+var
+vms
+vr
+vskip
+wordpress
+workflow
+worthwile
+www
+xref
+xxx
+xxxxxx
+yourname
diff --git a/eval.c b/eval.c
index 36dab2fb..afa37891 100644
--- a/eval.c
+++ b/eval.c
@@ -1,23 +1,23 @@
/*
- * eval.c - gawk bytecode interpreter
+ * eval.c - gawk bytecode interpreter
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -25,7 +25,6 @@
#include "awk.h"
-extern void after_beginfile(IOBUF **curfile);
extern double pow(double x, double y);
extern double modf(double x, double *yp);
extern double fmod(double x, double y);
@@ -54,7 +53,7 @@ static NODE *node_Boolean[2];
#ifdef C
#undef C
#endif
-#define C(c) ((char)c)
+#define C(c) ((char)c)
/*
* This table is used by the regexp routines to do case independent
* matching. Basically, every ascii character maps to itself, except
@@ -243,7 +242,6 @@ static const char *const nodetypes[] = {
"Node_param_list",
"Node_func",
"Node_ext_func",
- "Node_old_ext_func",
"Node_builtin_func",
"Node_array_ref",
"Node_array_tree",
@@ -289,6 +287,7 @@ static struct optypetab {
{ "Op_postincrement", "++" },
{ "Op_postdecrement", "--" },
{ "Op_unary_minus", "-" },
+ { "Op_unary_plus", "+" },
{ "Op_field_spec", "$" },
{ "Op_not", "! " },
{ "Op_assign", " = " },
@@ -315,7 +314,7 @@ static struct optypetab {
{ "Op_match", " ~ " },
{ "Op_match_rec", NULL },
{ "Op_nomatch", " !~ " },
- { "Op_rule", NULL },
+ { "Op_rule", NULL },
{ "Op_K_case", "case" },
{ "Op_K_default", "default" },
{ "Op_K_break", "break" },
@@ -334,12 +333,12 @@ static struct optypetab {
{ "Op_builtin", NULL },
{ "Op_sub_builtin", NULL },
{ "Op_ext_builtin", NULL },
- { "Op_old_ext_builtin", NULL }, /* temporary */
{ "Op_in_array", " in " },
{ "Op_func_call", NULL },
{ "Op_indirect_func_call", NULL },
{ "Op_push", NULL },
{ "Op_push_arg", NULL },
+ { "Op_push_arg_untyped", NULL },
{ "Op_push_i", NULL },
{ "Op_push_re", NULL },
{ "Op_push_array", NULL },
@@ -364,6 +363,7 @@ static struct optypetab {
{ "Op_after_beginfile", NULL },
{ "Op_after_endfile", NULL },
{ "Op_func", NULL },
+ { "Op_comment", NULL },
{ "Op_exec_count", NULL },
{ "Op_breakpoint", NULL },
{ "Op_lint", NULL },
@@ -381,6 +381,7 @@ static struct optypetab {
{ "Op_K_else", "else" },
{ "Op_K_function", "function" },
{ "Op_cond_exp", NULL },
+ { "Op_parens", NULL },
{ "Op_final --- this should never appear", NULL },
{ NULL, NULL },
};
@@ -436,18 +437,20 @@ flags2str(int flagval)
{ STRCUR, "STRCUR" },
{ NUMCUR, "NUMCUR" },
{ NUMBER, "NUMBER" },
- { MAYBE_NUM, "MAYBE_NUM" },
- { FIELD, "FIELD" },
+ { USER_INPUT, "USER_INPUT" },
{ INTLSTR, "INTLSTR" },
{ NUMINT, "NUMINT" },
{ INTIND, "INTIND" },
{ WSTRCUR, "WSTRCUR" },
{ MPFN, "MPFN" },
{ MPZN, "MPZN" },
+ { NO_EXT_SET, "NO_EXT_SET" },
{ NULL_FIELD, "NULL_FIELD" },
{ ARRAYMAXED, "ARRAYMAXED" },
{ HALFHAT, "HALFHAT" },
{ XARRAY, "XARRAY" },
+ { NUMCONSTSTR, "NUMCONSTSTR" },
+ { REGEX, "REGEX" },
{ 0, NULL },
};
@@ -575,7 +578,7 @@ posix_compare(NODE *s1, NODE *s2)
/* cmp_nodes --- compare two nodes, returning negative, 0, positive */
int
-cmp_nodes(NODE *t1, NODE *t2)
+cmp_nodes(NODE *t1, NODE *t2, bool use_strcmp)
{
int ret = 0;
size_t len1, len2;
@@ -584,14 +587,8 @@ cmp_nodes(NODE *t1, NODE *t2)
if (t1 == t2)
return 0;
- if ((t1->flags & MAYBE_NUM) != 0)
- (void) force_number(t1);
- if ((t2->flags & MAYBE_NUM) != 0)
- (void) force_number(t2);
- if ((t1->flags & INTIND) != 0)
- t1 = force_string(t1);
- if ((t2->flags & INTIND) != 0)
- t2 = force_string(t2);
+ (void) fixtype(t1);
+ (void) fixtype(t2);
if ((t1->flags & NUMBER) != 0 && (t2->flags & NUMBER) != 0)
return cmp_numbers(t1, t2);
@@ -604,17 +601,23 @@ cmp_nodes(NODE *t1, NODE *t2)
if (len1 == 0 || len2 == 0)
return ldiff;
- if (do_posix)
+ if (do_posix && ! use_strcmp)
return posix_compare(t1, t2);
l = (ldiff <= 0 ? len1 : len2);
if (IGNORECASE) {
const unsigned char *cp1 = (const unsigned char *) t1->stptr;
const unsigned char *cp2 = (const unsigned char *) t2->stptr;
+ char save1 = t1->stptr[t1->stlen];
+ char save2 = t2->stptr[t2->stlen];
+
if (gawk_mb_cur_max > 1) {
+ t1->stptr[t1->stlen] = t2->stptr[t2->stlen] = '\0';
ret = strncasecmpmbs((const unsigned char *) cp1,
(const unsigned char *) cp2, l);
+ t1->stptr[t1->stlen] = save1;
+ t2->stptr[t2->stlen] = save2;
} else {
/* Could use tolower() here; see discussion above. */
for (ret = 0; l-- > 0 && ret == 0; cp1++, cp2++)
@@ -646,7 +649,7 @@ push_frame(NODE *f)
}
if (fcall_count > 1)
- memmove(fcall_list + 2, fcall_list + 1, (fcall_count - 1) * sizeof(NODE *));
+ memmove(fcall_list + 2, fcall_list + 1, (fcall_count - 1) * sizeof(NODE *));
fcall_list[1] = f;
}
@@ -657,7 +660,7 @@ static void
pop_frame()
{
if (fcall_count > 1)
- memmove(fcall_list + 1, fcall_list + 2, (fcall_count - 1) * sizeof(NODE *));
+ memmove(fcall_list + 1, fcall_list + 2, (fcall_count - 1) * sizeof(NODE *));
fcall_count--;
assert(fcall_count >= 0);
if (do_debug)
@@ -700,7 +703,6 @@ void
set_IGNORECASE()
{
static bool warned = false;
- NODE *n = IGNORECASE_node->var_value;
if ((do_lint || do_traditional) && ! warned) {
warned = true;
@@ -709,19 +711,8 @@ set_IGNORECASE()
load_casetable();
if (do_traditional)
IGNORECASE = false;
- else if ((n->flags & (NUMCUR|NUMBER)) != 0)
- IGNORECASE = ! iszero(n);
- else if ((n->flags & (STRING|STRCUR)) != 0) {
- if ((n->flags & MAYBE_NUM) == 0) {
- (void) force_string(n);
- IGNORECASE = (n->stlen > 0);
- } else {
- (void) force_number(n);
- IGNORECASE = ! iszero(n);
- }
- } else
- IGNORECASE = false; /* shouldn't happen */
-
+ else
+ IGNORECASE = boolval(IGNORECASE_node->var_value);
set_RS(); /* set_RS() calls set_FS() if need be, for us */
}
@@ -732,7 +723,7 @@ set_BINMODE()
{
static bool warned = false;
char *p;
- NODE *v = BINMODE_node->var_value;
+ NODE *v = fixtype(BINMODE_node->var_value);
if ((do_lint || do_traditional) && ! warned) {
warned = true;
@@ -741,7 +732,6 @@ set_BINMODE()
if (do_traditional)
BINMODE = TEXT_TRANSLATE;
else if ((v->flags & NUMBER) != 0) {
- (void) force_number(v);
BINMODE = get_number_si(v);
/* Make sure the value is rational. */
if (BINMODE < TEXT_TRANSLATE)
@@ -829,9 +819,9 @@ set_OFS()
new_ofs_len = OFS_node->var_value->stlen;
if (OFS == NULL)
- emalloc(OFS, char *, new_ofs_len + 2, "set_OFS");
+ emalloc(OFS, char *, new_ofs_len + 1, "set_OFS");
else if (OFSlen < new_ofs_len)
- erealloc(OFS, char *, new_ofs_len + 2, "set_OFS");
+ erealloc(OFS, char *, new_ofs_len + 1, "set_OFS");
memcpy(OFS, OFS_node->var_value->stptr, OFS_node->var_value->stlen);
OFSlen = new_ofs_len;
@@ -846,7 +836,6 @@ set_ORS()
ORS_node->var_value = force_string(ORS_node->var_value);
ORS = ORS_node->var_value->stptr;
ORSlen = ORS_node->var_value->stlen;
- ORS[ORSlen] = '\0';
}
/* fmt_ok --- is the conversion format a valid one? */
@@ -872,6 +861,8 @@ fmt_ok(NODE *n)
static const char flags[] = " +-#";
#endif
+ // We rely on the caller to zero-terminate n->stptr.
+
if (*p++ != '%')
return 0;
while (*p && strchr(flags, *p) != NULL) /* flags */
@@ -899,23 +890,30 @@ fmt_index(NODE *n)
int ix = 0;
static int fmt_num = 4;
static int fmt_hiwater = 0;
+ char save;
if (fmt_list == NULL)
emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index");
n = force_string(n);
+
+ save = n->stptr[n->stlen];
+ n->stptr[n->stlen] = '\0';
+
while (ix < fmt_hiwater) {
- if (cmp_nodes(fmt_list[ix], n) == 0)
+ if (cmp_nodes(fmt_list[ix], n, true) == 0)
return ix;
ix++;
}
+
/* not found */
- n->stptr[n->stlen] = '\0';
if (do_lint && ! fmt_ok(n))
lintwarn(_("bad `%sFMT' specification `%s'"),
n == CONVFMT_node->var_value ? "CONV"
: n == OFMT_node->var_value ? "O"
: "", n->stptr);
+ n->stptr[n->stlen] = save;
+
if (fmt_hiwater >= fmt_num) {
fmt_num *= 2;
erealloc(fmt_list, NODE **, fmt_num * sizeof(*fmt_list), "fmt_index");
@@ -949,36 +947,28 @@ set_LINT()
{
#ifndef NO_LINT
int old_lint = do_lint;
- NODE *n = LINT_node->var_value;
+ NODE *n = fixtype(LINT_node->var_value);
/* start with clean defaults */
lintfunc = r_warning;
do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
- if ((n->flags & (STRING|STRCUR)) != 0) {
- if ((n->flags & MAYBE_NUM) == 0) {
- const char *lintval;
- size_t lintlen;
-
- n = force_string(LINT_node->var_value);
- lintval = n->stptr;
- lintlen = n->stlen;
- if (lintlen > 0) {
- if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0)
- do_flags |= DO_LINT_INVALID;
- else {
- do_flags |= DO_LINT_ALL;
- if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0)
- lintfunc = r_fatal;
- }
- }
- } else {
- (void) force_number(n);
- if (! iszero(n))
+ if ((n->flags & STRING) != 0) {
+ const char *lintval;
+ size_t lintlen;
+
+ lintval = n->stptr;
+ lintlen = n->stlen;
+ if (lintlen > 0) {
+ if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0)
+ do_flags |= DO_LINT_INVALID;
+ else {
do_flags |= DO_LINT_ALL;
+ if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0)
+ lintfunc = r_fatal;
+ }
}
- } else if ((n->flags & (NUMCUR|NUMBER)) != 0) {
- (void) force_number(n);
+ } else {
if (! iszero(n))
do_flags |= DO_LINT_ALL;
}
@@ -997,13 +987,10 @@ set_LINT()
void
set_TEXTDOMAIN()
{
- int len;
NODE *tmp;
tmp = TEXTDOMAIN_node->var_value = force_string(TEXTDOMAIN_node->var_value);
TEXTDOMAIN = tmp->stptr;
- len = tmp->stlen;
- TEXTDOMAIN[len] = '\0';
/*
* Note: don't call textdomain(); this value is for
* the awk program, not for gawk itself.
@@ -1017,6 +1004,7 @@ update_ERRNO_int(int errcode)
{
char *cp;
+ update_PROCINFO_num("errno", errcode);
if (errcode) {
cp = strerror(errcode);
cp = gettext(cp);
@@ -1031,6 +1019,7 @@ update_ERRNO_int(int errcode)
void
update_ERRNO_string(const char *string)
{
+ update_PROCINFO_num("errno", 0);
unref(ERRNO_node->var_value);
ERRNO_node->var_value = make_string(string, strlen(string));
}
@@ -1040,6 +1029,7 @@ update_ERRNO_string(const char *string)
void
unset_ERRNO(void)
{
+ update_PROCINFO_num("errno", 0);
unref(ERRNO_node->var_value);
ERRNO_node->var_value = dupnode(Nnull_string);
}
@@ -1099,7 +1089,7 @@ STACK_ITEM *stack_bottom;
STACK_ITEM *stack_top;
static unsigned long STACK_SIZE = 256; /* initial size of stack */
int max_args = 0; /* maximum # of arguments to printf, print, sprintf,
- * or # of array subscripts, or adjacent strings
+ * or # of array subscripts, or adjacent strings
* to be concatenated.
*/
NODE **args_array = NULL;
@@ -1171,7 +1161,7 @@ r_get_lhs(NODE *n, bool reference)
/* r_get_field --- get the address of a field node */
-
+
NODE **
r_get_field(NODE *n, Func_ptr *assign, bool reference)
{
@@ -1181,7 +1171,7 @@ r_get_field(NODE *n, Func_ptr *assign, bool reference)
if (assign)
*assign = NULL;
if (do_lint) {
- if ((n->flags & NUMBER) == 0) {
+ if ((fixtype(n)->flags & NUMBER) == 0) {
lintwarn(_("attempt to field reference from non-numeric value"));
if (n->stlen == 0)
lintwarn(_("attempt to field reference from null string"));
@@ -1243,7 +1233,7 @@ calc_exp(AWKNUM x1, AWKNUM x2)
}
-/* setup_frame --- setup new frame for function call */
+/* setup_frame --- setup new frame for function call */
static INSTRUCTION *
setup_frame(INSTRUCTION *pc)
@@ -1280,12 +1270,11 @@ setup_frame(INSTRUCTION *pc)
sp = frame_ptr->stack;
} else if (pcount > 0) {
- emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
- memset(sp, 0, pcount * sizeof(NODE *));
+ ezalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
}
- /* check for extra args */
+ /* check for extra args */
if (arg_count > pcount) {
warning(
_("function `%s' called with more arguments than declared"),
@@ -1379,7 +1368,7 @@ setup_frame(INSTRUCTION *pc)
/* setup new frame */
getnode(frame_ptr);
- frame_ptr->type = Node_frame;
+ frame_ptr->type = Node_frame;
frame_ptr->stack = sp;
frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the previous stack frame */
frame_ptr->func_node = f;
@@ -1497,7 +1486,7 @@ unwind_stack(long n)
if (in_main_context() && ! exiting)
fatal(_("unwind_stack: unexpected type `%s'"),
nodetype2str(r->type));
- /* else
+ /* else
* Node_var_array,
* Node_param_list,
* Node_var (e.g: trying to use scalar for array)
@@ -1511,7 +1500,7 @@ unwind_stack(long n)
break;
}
return cp;
-}
+}
/* pop_fcall --- pop off the innermost frame */
@@ -1521,7 +1510,7 @@ unwind_stack(long n)
#define pop_stack() (void) unwind_stack(0)
-static inline int
+static inline bool
eval_condition(NODE *t)
{
if (t == node_Boolean[false])
@@ -1530,21 +1519,18 @@ eval_condition(NODE *t)
if (t == node_Boolean[true])
return true;
- if ((t->flags & MAYBE_NUM) != 0)
- force_number(t);
- else if ((t->flags & INTIND) != 0)
- force_string(t);
-
- if ((t->flags & NUMBER) != 0)
- return ! iszero(t);
-
- return (t->stlen != 0);
+ return boolval(t);
}
+typedef enum {
+ SCALAR_EQ_NEQ,
+ SCALAR_RELATIONAL
+} scalar_cmp_t;
+
/* cmp_scalars -- compare two nodes on the stack */
static inline int
-cmp_scalars()
+cmp_scalars(scalar_cmp_t comparison_type)
{
NODE *t1, *t2;
int di;
@@ -1555,14 +1541,14 @@ cmp_scalars()
DEREF(t2);
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t1));
}
- di = cmp_nodes(t1, t2);
+ di = cmp_nodes(t1, t2, comparison_type == SCALAR_EQ_NEQ);
DEREF(t1);
DEREF(t2);
return di;
}
/* op_assign --- assignment operators excluding = */
-
+
static void
op_assign(OPCODE op)
{
@@ -1664,9 +1650,9 @@ POP_CODE()
typedef struct exec_state {
struct exec_state *next;
- INSTRUCTION *cptr; /* either getline (Op_K_getline) or the
+ INSTRUCTION *cptr; /* either getline (Op_K_getline) or the
* implicit "open-file, read-record" loop (Op_newfile).
- */
+ */
int rule; /* rule for the INSTRUCTION */
@@ -1732,7 +1718,7 @@ register_exec_hook(Func_pre_exec preh, Func_post_exec posth)
/*
* multiple post-exec hooks aren't supported. post-exec hook is mainly
* for use by the debugger.
- */
+ */
if (! preh || (post_execute && posth))
return false;
@@ -1760,7 +1746,7 @@ register_exec_hook(Func_pre_exec preh, Func_post_exec posth)
}
-/* interpreter routine when not debugging */
+/* interpreter routine when not debugging */
#include "interpret.h"
/* interpreter routine with exec hook(s). Used when debugging and/or with MPFR. */
@@ -1808,6 +1794,6 @@ init_interpret()
if (num_exec_hook > 0)
interpret = h_interpret;
else
- interpret = r_interpret;
+ interpret = r_interpret;
}
diff --git a/ext.c b/ext.c
index 45f1e6de..609b3b2b 100644
--- a/ext.c
+++ b/ext.c
@@ -9,20 +9,20 @@
/*
* Copyright (C) 1995 - 2001, 2003-2014, 2016,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -33,9 +33,6 @@ extern SRCFILE *srcfiles;
#ifdef DYNAMIC
-#define OLD_INIT_FUNC "dlload"
-#define OLD_FINI_FUNC "dlunload"
-
#include <dlfcn.h>
/*
@@ -92,95 +89,6 @@ load_ext(const char *lib_name)
lib_name, INIT_FUNC);
}
-/* do_ext --- load an extension at run-time: interface to load_ext */
-
-NODE *
-do_ext(int nargs)
-{
- NODE *obj, *init = NULL, *fini = NULL, *ret = NULL;
- SRCFILE *s;
- char *init_func = NULL;
- char *fini_func = NULL;
-
- if (nargs == 3) {
- fini = POP_STRING();
- fini_func = fini->stptr;
- }
- if (nargs >= 2) {
- init = POP_STRING();
- init_func = init->stptr;
- }
- obj = POP_STRING();
-
- s = add_srcfile(SRC_EXTLIB, obj->stptr, srcfiles, NULL, NULL);
- if (s != NULL)
- ret = load_old_ext(s, init_func, fini_func, obj);
-
- DEREF(obj);
- if (fini != NULL)
- DEREF(fini);
- if (init != NULL)
- DEREF(init);
- if (ret == NULL)
- ret = dupnode(Nnull_string);
- return ret;
-}
-
-/* load_old_ext --- load an external library */
-
-NODE *
-load_old_ext(SRCFILE *s, const char *init_func, const char *fini_func, NODE *obj)
-{
- NODE *(*func)(NODE *, void *);
- NODE *tmp;
- void *dl;
- int flags = RTLD_LAZY;
- int *gpl_compat;
- const char *lib_name = s->fullpath;
-
- if (init_func == NULL || init_func[0] == '\0')
- init_func = OLD_INIT_FUNC;
-
- if (fini_func == NULL || fini_func[0] == '\0')
- fini_func = OLD_FINI_FUNC;
-
- if (do_sandbox)
- fatal(_("extensions are not allowed in sandbox mode"));
-
- if (do_traditional || do_posix)
- fatal(_("`extension' is a gawk extension"));
-
- if (lib_name == NULL)
- fatal(_("extension: received NULL lib_name"));
-
- if ((dl = dlopen(lib_name, flags)) == NULL)
- fatal(_("extension: cannot open library `%s' (%s)"), lib_name,
- dlerror());
-
- /* Per the GNU Coding standards */
- gpl_compat = (int *) dlsym(dl, "plugin_is_GPL_compatible");
- if (gpl_compat == NULL)
- fatal(_("extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)"),
- lib_name, dlerror());
- func = (NODE *(*)(NODE *, void *)) dlsym(dl, init_func);
- if (func == NULL)
- fatal(_("extension: library `%s': cannot call function `%s' (%s)"),
- lib_name, init_func, dlerror());
-
- if (obj == NULL) {
- obj = make_string(lib_name, strlen(lib_name));
- tmp = (*func)(obj, dl);
- unref(tmp);
- unref(obj);
- tmp = NULL;
- } else
- tmp = (*func)(obj, dl);
-
- s->fini_func = (void (*)(void)) dlsym(dl, fini_func);
- return tmp;
-}
-
-
/* make_builtin --- register name to be called as func with a builtin body */
awk_bool_t
@@ -191,7 +99,7 @@ make_builtin(const awk_ext_func_t *funcinfo)
const char *sp;
char c;
const char *name = funcinfo->name;
- int count = funcinfo->num_expected_args;
+ int count = funcinfo->max_expected_args;
sp = name;
if (sp == NULL || *sp == '\0')
@@ -212,15 +120,15 @@ make_builtin(const awk_ext_func_t *funcinfo)
/* user-defined function */
fatal(_("make_builtin: can't redefine function `%s'"), name);
} else if (f->type == Node_ext_func) {
- /* multiple extension() calls etc. */
+ /* multiple extension() calls etc. */
if (do_lint)
lintwarn(_("make_builtin: function `%s' already defined"), name);
return awk_false;
} else
- /* variable name etc. */
+ /* variable name etc. */
fatal(_("make_builtin: function name `%s' previously defined"), name);
} else if (check_special(name) >= 0)
- fatal(_("make_builtin: can't use gawk built-in `%s' as function name"), name);
+ fatal(_("make_builtin: can't use gawk built-in `%s' as function name"), name);
if (count < 0)
fatal(_("make_builtin: negative argument count for function `%s'"),
@@ -228,7 +136,7 @@ make_builtin(const awk_ext_func_t *funcinfo)
b = bcalloc(Op_symbol, 1, 0);
b->extfunc = funcinfo->function;
- b->expr_count = count;
+ b->c_func = (awk_ext_func_t *) funcinfo;
/* NB: extension sub must return something */
@@ -238,75 +146,19 @@ make_builtin(const awk_ext_func_t *funcinfo)
return awk_true;
}
-/* make_old_builtin --- register name to be called as func with a builtin body */
-
-void
-make_old_builtin(const char *name, NODE *(*func)(int), int count) /* temporary */
-{
- NODE *symbol, *f;
- INSTRUCTION *b;
- const char *sp;
- char c;
-
- sp = name;
- if (sp == NULL || *sp == '\0')
- fatal(_("extension: missing function name"));
-
- if (! is_letter(*sp))
- fatal(_("extension: illegal character `%c' in function name `%s'"), *sp, name);
-
- for (sp++; (c = *sp++) != '\0';) {
- if (! is_identchar(c))
- fatal(_("extension: illegal character `%c' in function name `%s'"), c, name);
- }
-
- f = lookup(name);
-
- if (f != NULL) {
- if (f->type == Node_func) {
- /* user-defined function */
- fatal(_("extension: can't redefine function `%s'"), name);
- } else if (f->type == Node_ext_func) {
- /* multiple extension() calls etc. */
- if (do_lint)
- lintwarn(_("extension: function `%s' already defined"), name);
- return;
- } else
- /* variable name etc. */
- fatal(_("extension: function name `%s' previously defined"), name);
- } else if (check_special(name) >= 0)
- fatal(_("extension: can't use gawk built-in `%s' as function name"), name);
-
- if (count < 0)
- fatal(_("make_builtin: negative argument count for function `%s'"),
- name);
-
- b = bcalloc(Op_symbol, 1, 0);
- b->builtin = func;
- b->expr_count = count;
-
- /* NB: extension sub must return something */
-
- symbol = install_symbol(estrdup(name, strlen(name)), Node_old_ext_func);
- symbol->code_ptr = b;
- track_ext_func(name);
-}
-
-
/* get_argument --- get the i'th argument of a dynamically linked function */
NODE *
get_argument(int i)
{
NODE *t;
- int arg_count, pcount;
+ int arg_count;
INSTRUCTION *pc;
-
+
pc = TOP()->code_ptr; /* Op_ext_builtin instruction */
- pcount = (pc + 1)->expr_count; /* max # of arguments */
arg_count = pc->expr_count; /* # of arguments supplied */
- if (i < 0 || i >= pcount || i >= arg_count)
+ if (i < 0 || i >= arg_count)
return NULL;
t = PEEK(arg_count - i);
@@ -315,7 +167,7 @@ get_argument(int i)
if (t->type == Node_array_ref) {
if (t->orig_array->type == Node_var) {
- /* already a scalar, can no longer use it as array */
+ /* already a scalar, can no longer use it as array */
t->type = Node_var;
t->var_value = Nnull_string;
return t;
@@ -339,10 +191,10 @@ get_actual_argument(NODE *t, int i, bool want_array)
{
char *fname;
INSTRUCTION *pc;
-
+
pc = TOP()->code_ptr; /* Op_ext_builtin instruction */
fname = (pc + 1)->func_name;
-
+
if (t->type == Node_var_new) {
if (want_array)
return force_array(t, false);
@@ -387,7 +239,7 @@ close_extensions()
if (srcfiles == NULL)
return;
- for (s = srcfiles->next; s != srcfiles; s = s->next)
+ for (s = srcfiles->next; s != srcfiles; s = s->next)
if (s->stype == SRC_EXTLIB && s->fini_func)
(*s->fini_func)();
}
diff --git a/extension/CMakeLists.txt b/extension/CMakeLists.txt
new file mode 100644
index 00000000..1bb4ceb1
--- /dev/null
+++ b/extension/CMakeLists.txt
@@ -0,0 +1,84 @@
+#
+# extension/CMakeLists.txt --- CMake input file for gawk
+#
+# Copyright (C) 2013
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with CMake to produce Makefile
+
+# Remove the definition of GAWK because of gawkapi.h.
+remove_definitions(-DGAWK)
+
+MACRO(BuildExtension name sources)
+ add_library (${name} MODULE ${sources} ${ARGN})
+ target_link_libraries(${name} ${EXTRA_LIBS})
+ set_target_properties(${name} PROPERTIES PREFIX "")
+ install(PROGRAMS ${CMAKE_BINARY_DIR}/extension/${name}${CMAKE_SHARED_LIBRARY_SUFFIX} DESTINATION lib)
+ENDMACRO(BuildExtension)
+
+if (${HAVE_STRUCT_STAT_ST_BLKSIZE})
+ BuildExtension(filefuncs filefuncs.c stack.c gawkfts.c)
+else()
+ message(STATUS "extension filefuncs cannot be built because HAVE_STRUCT_STAT_ST_BLKSIZE is missing")
+endif()
+
+if (HAVE_FNMATCH AND HAVE_FNMATCH_H)
+ BuildExtension(fnmatch fnmatch.c)
+else()
+ message(STATUS "extension fnmatch cannot be built because function fnmatch or fnmatch.h is missing")
+endif()
+
+if (${HAVE_SYS_WAIT_H})
+ BuildExtension(fork fork.c)
+else()
+ message(STATUS "extension fork cannot be built because HAVE_SYS_WAIT_H is missing")
+endif()
+
+if (${HAVE_MKSTEMP})
+ BuildExtension(inplace inplace.c)
+else()
+ message(STATUS "extension inplace cannot be built because HAVE_MKSTEMP is missing")
+endif()
+
+BuildExtension(ordchr ordchr.c)
+
+if (HAVE_DIRENT_H AND HAVE_DIRFD)
+ BuildExtension(readdir readdir.c)
+else()
+ message(STATUS "extension readdir cannot be built because function readdir is missing")
+endif()
+
+BuildExtension(readfile readfile.c)
+
+BuildExtension(revoutput revoutput.c)
+
+if (${HAVE_GETDTABLESIZE})
+ BuildExtension(revtwoway revtwoway.c)
+else()
+ message(STATUS "extension revtwoway cannot be built because function getdtablesize is missing")
+endif()
+
+BuildExtension(rwarray rwarray.c)
+
+BuildExtension(time time.c)
+
+BuildExtension(testext testext.c)
+
diff --git a/extension/ChangeLog b/extension/ChangeLog
index f8d1517e..8bb97590 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,156 @@
+2017-06-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * rwarray.c (read_value): Use malloc instead of calloc, since
+ we immediately overwrite the buffer with data from the file.
+ * rwarray0.c (read_value): Ditto.
+
+2017-06-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * readfile.c (read_file_to_buffer): Use emalloc instead of ezalloc,
+ since there's no need to initialize the memory to zero before
+ overwriting it with the file's contents.
+
+2017-06-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * filefuncs.c (do_fts): Replace emalloc+memset with ezalloc.
+ * readfile.c (read_file_to_buffer): Ditto.
+ * rwarray.c (read_value): Replace gawk_malloc+memset with gawk_calloc.
+ * gawkfts.c (fts_open): Replace malloc+memset with calloc.
+ * rwarray0.c (read_value): Ditto.
+
+2017-04-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * inplace.c (inplace_end): Correct the function name in the
+ wrong argument count error message. Thanks to Dan Neilsen
+ for the report.
+
+2017-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * readdir.c: Minor edits.
+ * readdir_test.c: Same minor edits, update copyright year,
+ bump version of extension in case this ever becomes the real one.
+
+2017-03-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * readdir.c (dir_get_record): Add additional parameter to make types
+ match and remove compiler warning.
+ * readfile.c (readfile_get_record): Ditto.
+ * revtwoway.c (rev2way_get_record): Ditto.
+
+2017-03-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * readdir_test.c (open_directory_t): Replace field_width array
+ with new awk_fieldwidth_info_t structure. Wrap it in a union so
+ we can allocate the proper size.
+ (dir_get_record): Update field_width type from
+ 'const awk_input_field_info_t **' to 'const awk_fieldwidth_info_t **'.
+ Update new fieldwidth parsing info appropriately.
+ (dir_take_control_of): Populate new fieldwidth parsing structure
+ with initial values.
+
+2017-03-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * readdir_test.c (open_directory_t): Update field_width type from an
+ array of integers to an array of awk_input_field_info_t.
+ (dir_get_record): Ditto.
+ (dir_take_control_of): Ditto.
+
+2017-03-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (pkgextension_LTLIBRARIES): Remove testext.la, since it
+ does not make sense to install this library.
+ (noinst_LTLIBRARIES): New variable containing list of libraries to
+ build for testing purposes only. These libraries will not be installed.
+ Initially, it contains only testext.la.
+ (testext_la_LDFLAGS): Add "-rpath /foo" to convince automake/libtool
+ to build a shared version of this library. Since it is not being
+ installed, automake cannot use the final destination directory to
+ determine -rpath by itself. The value doesn't matter.
+
+2017-03-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * readdir_test.c: Test extension using new get_record field_width
+ parsing feature.
+ * Makefile.am (noinst_LTLIBRARIES): Add readdir_test.la.
+ (readdir_test_la_*): Configure building of new extension library.
+
+2017-01-21 Eli Zaretskii <eliz@gnu.org>
+
+ * testext.c (getuid) [__MINGW32__]: New function, mirrors what
+ pc/getid.c does in Gawk.
+ * rwarray.c [__MINGW32__]: Include stdint.h, otherwise using
+ uint32_t causes compilation errors.
+ * inplace.c (_XOPEN_SOURCE): Define to 1, not to nothing. MinGW
+ system headers assume that if this is defined, it must have a
+ numeric value.
+
+2016-12-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * testext.c (valrep2str): Update for new API types.
+
+2016-12-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * filefuncs.c: Update func_table again.
+
+2016-12-14 Arnold D. Robbins <arnold@skeeve.com>
+
+ * filefuncs.c: Update do_xxx to match new API. Update func_table.
+ * fnmatch.c: Ditto.
+ * fork.c: Ditto.
+ * inplace.c: Ditto.
+ * ordchr.c: Ditto.
+ * readdir.c: Ditto.
+ * readfile.c: Ditto.
+ * revoutput.c: Ditto.
+ * revtwoway.c: Ditto.
+ * rwarray.c: Ditto.
+ * rwarray0.c: Ditto.
+ * testext.c: Ditto.
+ * time.c: Ditto.
+
+2016-12-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * filefuncs.c (func_table): Adjust ordering of min and max
+ for stat.
+
+2016-12-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ Add minimum required and maximum expected number of arguments
+ to the API.
+
+ * filefuncs.c: Update with max expected value. Remove lint
+ checks since that's now done by gawk.
+ * fnmatch.c: Ditto.
+ * fork.c: Ditto.
+ * inplace.c: Ditto.
+ * ordchr.c: Ditto.
+ * readdir.c: Ditto.
+ * readfile.c: Ditto.
+ * rwarray.c: Ditto.
+ * rwarray0.c: Ditto.
+ * testext.c: Ditto.
+ * time.c: Ditto.
+
+2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * rwarray.c: Adjust to read and write strnum values.
+ (write_value): When writing a string value, code should use htonl.
+ There are now 3 string types: string, strnum, and regex.
+ (read_value): Support 3 string types: string, strnum, and regex.
+
+2016-11-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * rwarray.c: Restore read comparion of major and minor versions
+ to use !=.
+
+2016-11-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ * rwarray.c: Adjust to read and write regexes also.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.4: Release tar ball made.
@@ -11,6 +164,11 @@
where configure didn't work correctly. Thanks to Nelson Beebe.
Update copyright year.
+2016-05-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * filefuncs.c (func_table): Update "stat" to indicate that the
+ max # of expected args is 3, not 2.
+
2016-01-27 Arnold D. Robbins <arnold@skeeve.com>
* filefuncs.c (do_statvfs): Define out f_fsid on AIX.
@@ -81,11 +239,19 @@
* 4.1.2: Release tar ball made.
+2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * configure.ac: Updated by autoupdate.
+
2015-04-08 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am, filefuncs.c, inplace.3am, inplace.c:
Update copyright years.
+2015-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * testext.c: Move test for deferred variables here.
+
2015-03-18 Arnold D. Robbins <arnold@skeeve.com>
* configure: Updated to libtool 2.4.6.
@@ -122,11 +288,86 @@
* testext.c (var_test): Adjust for PROCINFO now being there.
+2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * testext.c (test_deferred): New function to help with testing
+ of deferred variable instantiation.
+ (do_get_file): Remove unused variable array.
+ (func_table): Add test_deferred.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * testext.c (test_get_file): Fix error message.
+ (do_get_file): Implement new function providing low-level access
+ to the get_file API.
+ (func_table): Add "get_file" -> do_get_file.
+ (init_testext): If TESTEXT_QUIET has been set to a numeric value,
+ return quietly.
+
+2015-01-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * testext.c (test_get_file): The get_file hook no longer takes a
+ typelen argument.
+
+2015-01-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Remove the select extension, since it will be part of gawkextlib.
+ * select.c, siglist.h: Deleted.
+ * Makefile.am (pkgextension_LTLIBRARIES): Remove select.la.
+ (select_la_SOURCES, select_la_LDFLAGS, select_la_LIBADD): Remove.
+ (EXTRA_DIST): Remove siglist.h.
+ * configure.ac (AC_CHECK_HEADERS): Remove signal.h.
+ (AC_CHECK_FUNCS): Remove fcntl, kill, sigaction, and sigprocmask.
+
+2014-12-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Remove the errno extension, since it is now part of gawkextlib.
+ * errno.c, errlist.h: Deleted.
+ * Makefile.am (pkgextension_LTLIBRARIES): Remove errno.la.
+ (errno_la_SOURCES, errno_la_LDFLAGS, errno_la_LIBADD): Remove.
+ (EXTRA_DIST): Remove errlist.h.
+
+2014-12-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * readfile.c (read_file_to_buffer): Do not waste a byte at the end of
+ a string.
+ * rwarray.c (read_value): Ditto.
+ * rwarray0.c (read_value): Ditto.
+
2014-11-23 Arnold D. Robbins <arnold@skeeve.com>
* inplace.c (do_inplace_begin): Jump through hoops to silence
GCC warnings about return value of chown.
+2014-11-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (do_input_fd): New function to return the input file
+ descriptor associated with a file/command.
+ (do_output_fd): New function to return the output file descriptor
+ associated with a file/command.
+ (func_table): Add new functions "input_fd" and "output_fd".
+ * testext.c (test_get_file): Do not use __func__, since it is a C99
+ feature, and gawk does not assume C99.
+
+2014-11-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * errno.c (do_errno2name, do_name2errno): Remove unused variable 'str'.
+ * select.c (do_signal): Remove unused variable 'override'.
+ (grabfd): New helper function to map a gawk file to the appropriate
+ fd for use in the arguments to selectd.
+ (do_select): get_file has 3 new arguments and returns info about both
+ the input and output buf.
+ (do_set_non_blocking): Support changes to get_file API.
+ * testext.c (test_get_file): New test function to check that extension
+ file creation via the get_file API is working.
+
+2014-11-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (set_retry): New function to set PROCINFO[<name>, "RETRY"].
+ (do_set_non_blocking): If called with a file name as opposed to a file
+ descriptor, call the set_retry function to configure PROCINFO to tell
+ io.c to retry I/O for temporary failures.
+
2014-10-12 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (uninstall-so): Remove *.lib too, per suggestion
@@ -298,6 +539,108 @@
* gawkdirfd.h (FAKE_FD_VALUE): Move definition up in the file to give
clean compile on MinGW.
+2013-07-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * configure.ac (AC_CHECK_FUNCS): Check for fcntl.
+ * select.c (set_non_blocking): Check that fcntl and O_NONBLOCK are
+ available.
+
+2013-07-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (signal_handler): On platforms lacking sigaction, reset
+ the signal handler each time a signal is trapped to protect in case
+ the system resets it to default.
+
+2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (signal_result): New function to set result string from
+ signal function and detect when we need to roll back.
+ (do_signal): Now takes an optional 3rd override argument. Instead
+ of returning -1 or 0, we now return information about the previously
+ installed signal handler: default, ignore, trap, or unknown. An
+ empty string is returned on error. If it is an unknown handler,
+ and override is not non-zero, we roll back the handler and return "".
+
+2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (set_non_blocking): Do not attempt F_SETFL if F_GETFL fails.
+ (do_set_non_blocking): Add support for case when called with a single
+ "" argument.
+
+2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (do_signal): If sigaction is unavailable, fall back to
+ signal and hope that it does the right thing.
+
+2013-07-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * configure.ac (AC_CHECK_FUNCS): Add kill and sigprocmask.
+ * select.c (get_signal_number): Change error messages since now may
+ be called by "kill" as well as "select_signal".
+ (do_signal): Add a lint warning if there are more than 2 args.
+ (do_kill): Add new function to send a signal.
+ (do_select): Support platforms where sigprocmask is not available.
+ There will be a race condition on such platforms, but that is not
+ easily avoided.
+
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (do_select): Now that the API flatten_array call has been
+ patched to ensure that the index values are strings, we can remove
+ the code to check for the AWK_NUMBER case.
+
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (do_select): Do not treat a numeric command value as a
+ file descriptor unless the command type is empty.
+
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add errlist.h and siglist.h.
+
+2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (set_non_blocking): New helper function to call fcntl.
+ (do_set_non_blocking): Add support for the case where there's a single
+ integer fd argument.
+
+2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * select.c (do_set_non_blocking): Implement new set_non_blocking
+ function.
+ (func_table): Add set_non_blocking.
+
+2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * errlist.h: New file containing a list of all the errno values I could
+ find.
+ * errno.c: Implement a new errno extension providing strerror,
+ errno2name, and name2errno.
+ * Makefile.am (pkgextension_LTLIBRARIES): Add errno.la.
+ (errno_la_SOURCES, errno_la_LDFLAGS, errno_la_LIBADD): Build new errno
+ extension.
+ * select.c (ext_version): Fix version string.
+ * siglist.h: Update to newest glibc version.
+
+2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * siglist.h: New file copied from glibc to provide a mapping between
+ signal number and name.
+ * select.c: Add a new "select_signal" function and provide support
+ for trapping signals.
+ (do_select): Add support for a 5th argument to contain an array
+ of returned signals. Improve the argument processing, and add
+ better warning messages.
+
+2013-06-30 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (pkgextension_LTLIBRARIES): Add select.la.
+ (select_la_SOURCES, select_la_LDFLAGS, select_la_LIBADD): Build new
+ select extension.
+ * configure.ac (AC_CHECK_HEADERS): Add signal.h.
+ (AC_CHECK_FUNCS): Add sigaction.
+ * select.c: Implement the new select extension.
+
2013-06-10 Arnold D. Robbins <arnold@skeeve.com>
* configure.ac (AC_HEADER_MAJOR): New macro added.
diff --git a/extension/Makefile.am b/extension/Makefile.am
index 59c5cb8e..6ea16f5d 100644
--- a/extension/Makefile.am
+++ b/extension/Makefile.am
@@ -45,9 +45,12 @@ pkgextension_LTLIBRARIES = \
revoutput.la \
revtwoway.la \
rwarray.la \
- testext.la \
time.la
+noinst_LTLIBRARIES = \
+ readdir_test.la \
+ testext.la
+
MY_MODULE_FLAGS = -module -avoid-version -no-undefined
# on Cygwin, gettext requires that we link with -lintl
MY_LIBS = $(LTLIBINTL)
@@ -97,10 +100,20 @@ time_la_SOURCES = time.c
time_la_LDFLAGS = $(MY_MODULE_FLAGS)
time_la_LIBADD = $(MY_LIBS)
+# N.B. Becaues we are not installing testext, we must specify -rpath in
+# LDFLAGS to get automake to build a shared library, since it needs
+# an installation path.
testext_la_SOURCES = testext.c
-testext_la_LDFLAGS = $(MY_MODULE_FLAGS)
+testext_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo
testext_la_LIBADD = $(MY_LIBS)
+# N.B. Because we are not installing readdir_test, we must specify -rpath in
+# LDFLAGS to get automake to build a shared library, since it needs
+# an installation path.
+readdir_test_la_SOURCES = readdir_test.c
+readdir_test_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo
+readdir_test_la_LIBADD = $(MY_LIBS)
+
install-data-hook:
for i in $(pkgextension_LTLIBRARIES) ; do \
$(RM) $(DESTDIR)$(pkgextensiondir)/$$i ; \
diff --git a/extension/Makefile.in b/extension/Makefile.in
index 23bb5cf1..c0e2676b 100644
--- a/extension/Makefile.in
+++ b/extension/Makefile.in
@@ -157,7 +157,7 @@ am__uninstall_files_from_dir = { \
}
am__installdirs = "$(DESTDIR)$(pkgextensiondir)" \
"$(DESTDIR)$(man3dir)"
-LTLIBRARIES = $(pkgextension_LTLIBRARIES)
+LTLIBRARIES = $(noinst_LTLIBRARIES) $(pkgextension_LTLIBRARIES)
am__DEPENDENCIES_1 =
filefuncs_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_filefuncs_la_OBJECTS = filefuncs.lo stack.lo gawkfts.lo
@@ -199,6 +199,13 @@ readdir_la_OBJECTS = $(am_readdir_la_OBJECTS)
readdir_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(readdir_la_LDFLAGS) $(LDFLAGS) -o $@
+readdir_test_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_readdir_test_la_OBJECTS = readdir_test.lo
+readdir_test_la_OBJECTS = $(am_readdir_test_la_OBJECTS)
+readdir_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(readdir_test_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
readfile_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_readfile_la_OBJECTS = readfile.lo
readfile_la_OBJECTS = $(am_readfile_la_OBJECTS)
@@ -271,14 +278,16 @@ am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \
$(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \
- $(readdir_la_SOURCES) $(readfile_la_SOURCES) \
- $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \
- $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES)
+ $(readdir_la_SOURCES) $(readdir_test_la_SOURCES) \
+ $(readfile_la_SOURCES) $(revoutput_la_SOURCES) \
+ $(revtwoway_la_SOURCES) $(rwarray_la_SOURCES) \
+ $(testext_la_SOURCES) $(time_la_SOURCES)
DIST_SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \
$(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \
- $(readdir_la_SOURCES) $(readfile_la_SOURCES) \
- $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \
- $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES)
+ $(readdir_la_SOURCES) $(readdir_test_la_SOURCES) \
+ $(readfile_la_SOURCES) $(revoutput_la_SOURCES) \
+ $(revtwoway_la_SOURCES) $(rwarray_la_SOURCES) \
+ $(testext_la_SOURCES) $(time_la_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
install-data-recursive install-dvi-recursive \
@@ -517,9 +526,12 @@ pkgextension_LTLIBRARIES = \
revoutput.la \
revtwoway.la \
rwarray.la \
- testext.la \
time.la
+noinst_LTLIBRARIES = \
+ readdir_test.la \
+ testext.la
+
MY_MODULE_FLAGS = -module -avoid-version -no-undefined
# on Cygwin, gettext requires that we link with -lintl
MY_LIBS = $(LTLIBINTL)
@@ -558,9 +570,20 @@ rwarray_la_LIBADD = $(MY_LIBS)
time_la_SOURCES = time.c
time_la_LDFLAGS = $(MY_MODULE_FLAGS)
time_la_LIBADD = $(MY_LIBS)
+
+# N.B. Becaues we are not installing testext, we must specify -rpath in
+# LDFLAGS to get automake to build a shared library, since it needs
+# an installation path.
testext_la_SOURCES = testext.c
-testext_la_LDFLAGS = $(MY_MODULE_FLAGS)
+testext_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo
testext_la_LIBADD = $(MY_LIBS)
+
+# N.B. Because we are not installing readdir_test, we must specify -rpath in
+# LDFLAGS to get automake to build a shared library, since it needs
+# an installation path.
+readdir_test_la_SOURCES = readdir_test.c
+readdir_test_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo
+readdir_test_la_LIBADD = $(MY_LIBS)
EXTRA_DIST = build-aux/config.rpath \
ChangeLog \
ChangeLog.0 \
@@ -632,6 +655,17 @@ $(srcdir)/configh.in: $(am__configure_deps)
distclean-hdr:
-rm -f config.h stamp-h1
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
install-pkgextensionLTLIBRARIES: $(pkgextension_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(pkgextension_LTLIBRARIES)'; test -n "$(pkgextensiondir)" || list=; \
@@ -685,6 +719,9 @@ ordchr.la: $(ordchr_la_OBJECTS) $(ordchr_la_DEPENDENCIES) $(EXTRA_ordchr_la_DEPE
readdir.la: $(readdir_la_OBJECTS) $(readdir_la_DEPENDENCIES) $(EXTRA_readdir_la_DEPENDENCIES)
$(AM_V_CCLD)$(readdir_la_LINK) -rpath $(pkgextensiondir) $(readdir_la_OBJECTS) $(readdir_la_LIBADD) $(LIBS)
+readdir_test.la: $(readdir_test_la_OBJECTS) $(readdir_test_la_DEPENDENCIES) $(EXTRA_readdir_test_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(readdir_test_la_LINK) $(readdir_test_la_OBJECTS) $(readdir_test_la_LIBADD) $(LIBS)
+
readfile.la: $(readfile_la_OBJECTS) $(readfile_la_DEPENDENCIES) $(EXTRA_readfile_la_DEPENDENCIES)
$(AM_V_CCLD)$(readfile_la_LINK) -rpath $(pkgextensiondir) $(readfile_la_OBJECTS) $(readfile_la_LIBADD) $(LIBS)
@@ -698,7 +735,7 @@ rwarray.la: $(rwarray_la_OBJECTS) $(rwarray_la_DEPENDENCIES) $(EXTRA_rwarray_la_
$(AM_V_CCLD)$(rwarray_la_LINK) -rpath $(pkgextensiondir) $(rwarray_la_OBJECTS) $(rwarray_la_LIBADD) $(LIBS)
testext.la: $(testext_la_OBJECTS) $(testext_la_DEPENDENCIES) $(EXTRA_testext_la_DEPENDENCIES)
- $(AM_V_CCLD)$(testext_la_LINK) -rpath $(pkgextensiondir) $(testext_la_OBJECTS) $(testext_la_LIBADD) $(LIBS)
+ $(AM_V_CCLD)$(testext_la_LINK) $(testext_la_OBJECTS) $(testext_la_LIBADD) $(LIBS)
time.la: $(time_la_OBJECTS) $(time_la_DEPENDENCIES) $(EXTRA_time_la_DEPENDENCIES)
$(AM_V_CCLD)$(time_la_LINK) -rpath $(pkgextensiondir) $(time_la_OBJECTS) $(time_la_LIBADD) $(LIBS)
@@ -716,6 +753,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inplace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ordchr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdir.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdir_test.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readfile.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/revoutput.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/revtwoway.Plo@am__quote@
@@ -1131,8 +1169,8 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
-clean-am: clean-generic clean-libtool clean-pkgextensionLTLIBRARIES \
- mostlyclean-am
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-pkgextensionLTLIBRARIES mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
@@ -1211,13 +1249,14 @@ uninstall-man: uninstall-man3
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
am--refresh check check-am clean clean-cscope clean-generic \
- clean-libtool clean-pkgextensionLTLIBRARIES cscope \
- cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
- dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
- distcheck distclean distclean-compile distclean-generic \
- distclean-hdr distclean-libtool distclean-tags distcleancheck \
- distdir distuninstallcheck dvi dvi-am html html-am info \
- info-am install install-am install-data install-data-am \
+ clean-libtool clean-noinstLTLIBRARIES \
+ clean-pkgextensionLTLIBRARIES cscope cscopelist-am ctags \
+ ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \
+ dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \
+ distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags distcleancheck distdir \
+ distuninstallcheck dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
install-data-hook install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-man3 install-pdf \
diff --git a/extension/build-aux/ChangeLog b/extension/build-aux/ChangeLog
index b6e8cc11..4e4f0387 100644
--- a/extension/build-aux/ChangeLog
+++ b/extension/build-aux/ChangeLog
@@ -1,3 +1,21 @@
+2017-06-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * config.guess, config.sub: Update to latest from GNULIB.
+
+2017-03-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * config.sub: Updated again.
+
+2017-03-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * config.guess, config.rpath, config.sub, install-sh:
+ Sync with GNULIB.
+
+2017-01-04 Arnold Robbins <arnold@skeeve.com>
+
+ * config.guess, config.sub, compile, depcomp: Sync from latest
+ in GNULIB.
+
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.4: Release tar ball made.
diff --git a/extension/build-aux/compile b/extension/build-aux/compile
index a85b723c..2ab71e4e 100755
--- a/extension/build-aux/compile
+++ b/extension/build-aux/compile
@@ -1,9 +1,9 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
-scriptversion=2012-10-14.11; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
@@ -255,7 +255,8 @@ EOF
echo "compile $scriptversion"
exit $?
;;
- cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
@@ -342,6 +343,6 @@ exit $ret
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/extension/build-aux/config.guess b/extension/build-aux/config.guess
index c4bd827a..2193702b 100755
--- a/extension/build-aux/config.guess
+++ b/extension/build-aux/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2016-05-15'
+timestamp='2017-05-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright 1992-2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -837,10 +837,11 @@ EOF
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
esac
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -1000,6 +1001,9 @@ EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
+ mips64el:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
openrisc*:Linux:*:*)
echo or1k-unknown-linux-${LIBC}
exit ;;
@@ -1032,6 +1036,9 @@ EOF
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
@@ -1297,14 +1304,21 @@ EOF
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
# Avoid executing cc on OS X 10.9, as it ships with a stub
@@ -1328,15 +1342,18 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
- NEO-?:NONSTOP_KERNEL:*:*)
+ NEO-*:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
- NSR-?:NONSTOP_KERNEL:*:*)
+ NSR-*:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk${UNAME_RELEASE}
+ exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
exit ;;
diff --git a/extension/build-aux/config.rpath b/extension/build-aux/config.rpath
index 98183ff2..af3c4155 100755
--- a/extension/build-aux/config.rpath
+++ b/extension/build-aux/config.rpath
@@ -2,7 +2,7 @@
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
-# Copyright 1996-2016 Free Software Foundation, Inc.
+# Copyright 1996-2017 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
diff --git a/extension/build-aux/config.sub b/extension/build-aux/config.sub
index 9feb73bf..40ea5dfe 100755
--- a/extension/build-aux/config.sub
+++ b/extension/build-aux/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2016-06-20'
+timestamp='2017-04-02'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright 1992-2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +117,7 @@ case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
- kopensolaris*-gnu* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -263,7 +263,7 @@ case $basic_machine in
| fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
- | i370 | i860 | i960 | ia64 \
+ | i370 | i860 | i960 | ia16 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
@@ -301,6 +301,7 @@ case $basic_machine in
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
@@ -314,6 +315,7 @@ case $basic_machine in
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \
+ | wasm32 \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
@@ -387,7 +389,7 @@ case $basic_machine in
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
- | i*86-* | i860-* | i960-* | ia64-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
@@ -428,6 +430,7 @@ case $basic_machine in
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
| pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
@@ -444,6 +447,7 @@ case $basic_machine in
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| visium-* \
+ | wasm32-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
@@ -946,6 +950,9 @@ case $basic_machine in
nsr-tandem)
basic_machine=nsr-tandem
;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
@@ -1030,7 +1037,7 @@ case $basic_machine in
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
+ ppcle | powerpclittle)
basic_machine=powerpcle-unknown
;;
ppcle-* | powerpclittle-*)
@@ -1040,7 +1047,7 @@ case $basic_machine in
;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ ppc64le | powerpc64little)
basic_machine=powerpc64le-unknown
;;
ppc64le-* | powerpc64little-*)
@@ -1241,6 +1248,9 @@ case $basic_machine in
basic_machine=a29k-wrs
os=-vxworks
;;
+ wasm32)
+ basic_machine=wasm32-unknown
+ ;;
w65*)
basic_machine=w65-wdc
os=-none
@@ -1395,7 +1405,7 @@ case $os in
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* | -cegcc* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
@@ -1407,7 +1417,7 @@ case $os in
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
- | -onefs* | -tirtos* | -phoenix*)
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1636,6 +1646,9 @@ case $basic_machine in
sparc-* | *-sun)
os=-sunos4.1.1
;;
+ pru-*)
+ os=-elf
+ ;;
*-be)
os=-beos
;;
diff --git a/extension/build-aux/depcomp b/extension/build-aux/depcomp
index fc98710e..b6872321 100755
--- a/extension/build-aux/depcomp
+++ b/extension/build-aux/depcomp
@@ -1,9 +1,9 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
-scriptversion=2013-05-30.07; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -251,41 +251,6 @@ hp)
exit 1
;;
-sgi)
- if test "$libtool" = yes; then
- "$@" "-Wp,-MDupdate,$tmpdepfile"
- else
- "$@" -MDupdate "$tmpdepfile"
- fi
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
-
- if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
- echo "$object : \\" > "$depfile"
- # Clip off the initial element (the dependent). Don't try to be
- # clever and replace this with sed code, as IRIX sed won't handle
- # lines with more than a fixed number of characters (4096 in
- # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
- # the IRIX cc adds comments like '#:fec' to the end of the
- # dependency line.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
- | tr "$nl" ' ' >> "$depfile"
- echo >> "$depfile"
- # The second pass generates a dummy entry for each header file.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
- >> "$depfile"
- else
- make_dummy_depfile
- fi
- rm -f "$tmpdepfile"
- ;;
-
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
@@ -786,6 +751,6 @@ exit 0
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/extension/build-aux/install-sh b/extension/build-aux/install-sh
index 0b0fdcbb..0360b79e 100755
--- a/extension/build-aux/install-sh
+++ b/extension/build-aux/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2013-12-25.23; # UTC
+scriptversion=2016-01-11.22; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -496,6 +496,6 @@ done
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/extension/configure.ac b/extension/configure.ac
index d0eed3cc..b5b27d03 100644
--- a/extension/configure.ac
+++ b/extension/configure.ac
@@ -23,7 +23,7 @@ dnl
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([GNU Awk Bundled Extensions], 4.1.4, bug-gawk@gnu.org, gawk-extensions)
+AC_INIT([GNU Awk Bundled Extensions],[4.1.4],[bug-gawk@gnu.org],[gawk-extensions])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
@@ -42,7 +42,7 @@ AC_CHECK_MEMBERS([struct stat.st_blksize])
AM_PROG_AR
AC_SYS_LARGEFILE
AC_DISABLE_STATIC
-AC_PROG_LIBTOOL
+LT_INIT
dnl AC_PROG_INSTALL
AC_SUBST([pkgextensiondir], ['${libdir}/gawk'])
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index b33fcf1f..9ca22de8 100644
--- a/extension/filefuncs.c
+++ b/extension/filefuncs.c
@@ -12,20 +12,20 @@
/*
* Copyright (C) 2001, 2004, 2005, 2010-2016
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -153,16 +153,13 @@ int plugin_is_GPL_compatible;
/* do_chdir --- provide dynamically loaded chdir() function for gawk */
static awk_value_t *
-do_chdir(int nargs, awk_value_t *result)
+do_chdir(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t newdir;
int ret = -1;
assert(result != NULL);
- if (do_lint && nargs != 1)
- lintwarn(ext_id, _("chdir: called with incorrect number of arguments, expecting 1"));
-
if (get_argument(0, AWK_STRING, & newdir)) {
ret = chdir(newdir.str_value.str);
if (ret < 0)
@@ -461,7 +458,7 @@ fill_stat_array(const char *name, awk_array_t array, struct stat *sbuf)
/* do_stat --- provide a stat() function for gawk */
static awk_value_t *
-do_stat(int nargs, awk_value_t *result)
+do_stat(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t file_param, array_param;
char *name;
@@ -472,19 +469,13 @@ do_stat(int nargs, awk_value_t *result)
assert(result != NULL);
- if (nargs != 2 && nargs != 3) {
- if (do_lint)
- lintwarn(ext_id, _("stat: called with wrong number of arguments"));
- return make_number(-1, result);
- }
-
/* file is first arg, array to hold results is second */
if ( ! get_argument(0, AWK_STRING, & file_param)
|| ! get_argument(1, AWK_ARRAY, & array_param)) {
warning(ext_id, _("stat: bad parameters"));
return make_number(-1, result);
}
-
+
if (nargs == 3) {
statfunc = stat;
}
@@ -512,7 +503,7 @@ do_stat(int nargs, awk_value_t *result)
/* do_statvfs --- provide a statvfs() function for gawk */
static awk_value_t *
-do_statvfs(int nargs, awk_value_t *result)
+do_statvfs(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t file_param, array_param;
char *name;
@@ -522,12 +513,6 @@ do_statvfs(int nargs, awk_value_t *result)
assert(result != NULL);
- if (nargs != 2) {
- if (do_lint)
- lintwarn(ext_id, _("statvfs: called with wrong number of arguments"));
- return make_number(-1, result);
- }
-
/* file is first arg, array to hold results is second */
if ( ! get_argument(0, AWK_STRING, & file_param)
|| ! get_argument(1, AWK_ARRAY, & array_param)) {
@@ -561,7 +546,7 @@ do_statvfs(int nargs, awk_value_t *result)
#endif
array_set_numeric(array, "flag", vfsbuf.f_flag); /* mount flags */
array_set_numeric(array, "namemax", vfsbuf.f_namemax); /* maximum filename length */
-
+
return make_number(ret, result);
}
@@ -614,7 +599,7 @@ init_filefuncs(void)
*/
static awk_value_t *
-do_fts(int nargs, awk_value_t *result)
+do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
fatal(ext_id, _("fts is not supported on this system"));
@@ -829,7 +814,7 @@ process(FTS *heirarchy, awk_array_t destarray, int seedot)
*/
static awk_value_t *
-do_fts(int nargs, awk_value_t *result)
+do_fts(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t pathlist, flagval, dest;
awk_flat_array_t *path_array = NULL;
@@ -845,7 +830,7 @@ do_fts(int nargs, awk_value_t *result)
assert(result != NULL);
fts_errors = 0; /* ensure a fresh start */
- if (do_lint && nargs != 3)
+ if (nargs > 3)
lintwarn(ext_id, _("fts: called with incorrect number of arguments, expecting 3"));
if (! get_argument(0, AWK_ARRAY, & pathlist)) {
@@ -892,8 +877,7 @@ do_fts(int nargs, awk_value_t *result)
/* make pathvector */
count = path_array->count + 1;
- emalloc(pathvector, char **, count * sizeof(char *), "do_fts");
- memset(pathvector, 0, count * sizeof(char *));
+ ezalloc(pathvector, char **, count * sizeof(char *), "do_fts");
/* fill it in */
count--; /* ignore final NULL at end of vector */
@@ -928,13 +912,13 @@ out:
#endif /* ! __MINGW32__ */
static awk_ext_func_t func_table[] = {
- { "chdir", do_chdir, 1 },
- { "stat", do_stat, 2 },
+ { "chdir", do_chdir, 1, 1, awk_false, NULL },
+ { "stat", do_stat, 3, 2, awk_false, NULL },
#ifndef __MINGW32__
- { "fts", do_fts, 3 },
+ { "fts", do_fts, 3, 3, awk_false, NULL },
#endif
#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
- { "statvfs", do_statvfs, 2 },
+ { "statvfs", do_statvfs, 2, 2, awk_false, NULL },
#endif
};
diff --git a/extension/fnmatch.c b/extension/fnmatch.c
index a85bcc78..5382e4bc 100644
--- a/extension/fnmatch.c
+++ b/extension/fnmatch.c
@@ -8,20 +8,20 @@
/*
* Copyright (C) 2012, 2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -95,7 +95,7 @@ int plugin_is_GPL_compatible;
/* do_fnmatch --- implement the fnmatch interface */
static awk_value_t *
-do_fnmatch(int nargs, awk_value_t *result)
+do_fnmatch(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
#ifdef HAVE_FNMATCH_H
static int flags_mask =
@@ -107,13 +107,8 @@ do_fnmatch(int nargs, awk_value_t *result)
int int_flags, retval;
make_number(-1.0, result); /* default return */
-#ifdef HAVE_FNMATCH
- if (nargs < 3) {
- warning(ext_id, _("fnmatch: called with less than three arguments"));
- goto out;
- } else if (do_lint && nargs > 3)
- lintwarn(ext_id, _("fnmatch: called with more than three arguments"));
+#ifdef HAVE_FNMATCH
if (! get_argument(0, AWK_STRING, & pattern)) {
warning(ext_id, _("fnmatch: could not get first argument"));
goto out;
@@ -199,7 +194,7 @@ init_fnmatch(void)
}
static awk_ext_func_t func_table[] = {
- { "fnmatch", do_fnmatch, 3 },
+ { "fnmatch", do_fnmatch, 3, 3, awk_false, NULL },
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/fork.c b/extension/fork.c
index 0ca0a0e0..823506dd 100644
--- a/extension/fork.c
+++ b/extension/fork.c
@@ -7,20 +7,20 @@
/*
* Copyright (C) 2001, 2004, 2011, 2012, 2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -71,15 +71,12 @@ array_set_numeric(awk_array_t array, const char *sub, double num)
/* do_fork --- provide dynamically loaded fork() builtin for gawk */
static awk_value_t *
-do_fork(int nargs, awk_value_t *result)
+do_fork(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
int ret = -1;
assert(result != NULL);
- if (do_lint && nargs > 0)
- lintwarn(ext_id, _("fork: called with too many arguments"));
-
ret = fork();
if (ret < 0)
@@ -106,7 +103,7 @@ do_fork(int nargs, awk_value_t *result)
/* do_waitpid --- provide dynamically loaded waitpid() builtin for gawk */
static awk_value_t *
-do_waitpid(int nargs, awk_value_t *result)
+do_waitpid(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t pid;
int ret = -1;
@@ -114,16 +111,12 @@ do_waitpid(int nargs, awk_value_t *result)
assert(result != NULL);
- if (do_lint && nargs > 1)
- lintwarn(ext_id, _("waitpid: called with too many arguments"));
-
if (get_argument(0, AWK_NUMBER, &pid)) {
options = WNOHANG|WUNTRACED;
ret = waitpid(pid.num_value, NULL, options);
if (ret < 0)
update_ERRNO_int(errno);
- } else if (do_lint)
- lintwarn(ext_id, _("wait: called with no arguments"));
+ }
/* Set the return value */
return make_number(ret, result);
@@ -133,15 +126,12 @@ do_waitpid(int nargs, awk_value_t *result)
/* do_wait --- provide dynamically loaded wait() builtin for gawk */
static awk_value_t *
-do_wait(int nargs, awk_value_t *result)
+do_wait(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
int ret;
assert(result != NULL);
- if (do_lint && nargs > 0)
- lintwarn(ext_id, _("wait: called with too many arguments"));
-
ret = wait(NULL);
if (ret < 0)
update_ERRNO_int(errno);
@@ -151,9 +141,9 @@ do_wait(int nargs, awk_value_t *result)
}
static awk_ext_func_t func_table[] = {
- { "fork", do_fork, 0 },
- { "waitpid", do_waitpid, 1 },
- { "wait", do_wait, 0 },
+ { "fork", do_fork, 0, 0, awk_false, NULL },
+ { "waitpid", do_waitpid, 1, 1, awk_false, NULL },
+ { "wait", do_wait, 0, 0, awk_false, NULL },
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/gawkfts.c b/extension/gawkfts.c
index 4a712153..d9edd87f 100644
--- a/extension/gawkfts.c
+++ b/extension/gawkfts.c
@@ -162,9 +162,8 @@ fts_open(char * const *argv, int options,
}
/* Allocate/initialize the stream */
- if ((sp = malloc((unsigned int)sizeof(FTS))) == NULL)
+ if ((sp = calloc(1, (unsigned int)sizeof(FTS))) == NULL)
return (NULL);
- memset(sp, 0, sizeof(FTS));
sp->fts_compar = compar;
sp->fts_options = options;
diff --git a/extension/inplace.c b/extension/inplace.c
index c7eb5564..f89017b7 100644
--- a/extension/inplace.c
+++ b/extension/inplace.c
@@ -4,20 +4,20 @@
/*
* Copyright (C) 2013-2015 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -28,7 +28,7 @@
#endif
#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE
+# define _XOPEN_SOURCE 1
#endif
#ifndef _XOPEN_SOURCE_EXTENDED
# define _XOPEN_SOURCE_EXTENDED 1
@@ -118,7 +118,7 @@ invalid_filename(const awk_string_t *filename)
/* do_inplace_begin --- start in-place editing */
static awk_value_t *
-do_inplace_begin(int nargs, awk_value_t *result)
+do_inplace_begin(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename;
struct stat sbuf;
@@ -132,7 +132,7 @@ do_inplace_begin(int nargs, awk_value_t *result)
if (nargs != 2)
fatal(ext_id, _("inplace_begin: expects 2 arguments but called with %d"), nargs);
-
+
if (! get_argument(0, AWK_STRING, &filename))
fatal(ext_id, _("inplace_begin: cannot retrieve 1st argument as a string filename"));
@@ -201,14 +201,14 @@ do_inplace_begin(int nargs, awk_value_t *result)
/* do_inplace_end --- finish in-place editing */
static awk_value_t *
-do_inplace_end(int nargs, awk_value_t *result)
+do_inplace_end(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename, suffix;
assert(result != NULL);
if (nargs != 2)
- fatal(ext_id, _("inplace_begin: expects 2 arguments but called with %d"), nargs);
+ fatal(ext_id, _("inplace_end: expects 2 arguments but called with %d"), nargs);
if (! get_argument(0, AWK_STRING, &filename))
fatal(ext_id, _("inplace_end: cannot retrieve 1st argument as a string filename"));
@@ -262,8 +262,8 @@ do_inplace_end(int nargs, awk_value_t *result)
}
static awk_ext_func_t func_table[] = {
- { "inplace_begin", do_inplace_begin, 2 },
- { "inplace_end", do_inplace_end, 2 },
+ { "inplace_begin", do_inplace_begin, 2, 2, awk_false, NULL },
+ { "inplace_end", do_inplace_end, 2, 2, awk_false, NULL },
};
static awk_bool_t init_inplace(void)
diff --git a/extension/ordchr.c b/extension/ordchr.c
index 8ec9de3f..c7451f6d 100644
--- a/extension/ordchr.c
+++ b/extension/ordchr.c
@@ -10,20 +10,20 @@
/*
* Copyright (C) 2001, 2004, 2011, 2012, 2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -58,24 +58,17 @@ int plugin_is_GPL_compatible;
/* do_ord --- return numeric value of first char of string */
static awk_value_t *
-do_ord(int nargs, awk_value_t *result)
+do_ord(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t str;
double ret = -1;
assert(result != NULL);
- if (do_lint && nargs > 1)
- lintwarn(ext_id, _("ord: called with too many arguments"));
-
if (get_argument(0, AWK_STRING, & str)) {
ret = str.str_value.str[0];
- } else if (do_lint) {
- if (nargs == 0)
- lintwarn(ext_id, _("ord: called with no arguments"));
- else
- lintwarn(ext_id, _("ord: called with inappropriate argument(s)"));
- }
+ } else if (do_lint)
+ lintwarn(ext_id, _("ord: called with inappropriate argument(s)"));
/* Set the return value */
return make_number(ret, result);
@@ -84,7 +77,7 @@ do_ord(int nargs, awk_value_t *result)
/* do_chr --- turn numeric value into a string */
static awk_value_t *
-do_chr(int nargs, awk_value_t *result)
+do_chr(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t num;
unsigned int ret = 0;
@@ -95,29 +88,22 @@ do_chr(int nargs, awk_value_t *result)
assert(result != NULL);
- if (do_lint && nargs > 1)
- lintwarn(ext_id, _("chr: called with too many arguments"));
-
if (get_argument(0, AWK_NUMBER, & num)) {
val = num.num_value;
ret = val; /* convert to int */
ret &= 0xff;
str[0] = ret;
str[1] = '\0';
- } else if (do_lint) {
- if (nargs == 0)
- lintwarn(ext_id, _("chr: called with no arguments"));
- else
- lintwarn(ext_id, _("chr: called with inappropriate argument(s)"));
- }
+ } else if (do_lint)
+ lintwarn(ext_id, _("chr: called with inappropriate argument(s)"));
/* Set the return value */
return make_const_string(str, 1, result);
}
static awk_ext_func_t func_table[] = {
- { "ord", do_ord, 1 },
- { "chr", do_chr, 1 },
+ { "ord", do_ord, 1, 1, awk_false, NULL },
+ { "chr", do_chr, 1, 1, awk_false, NULL },
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/readdir.c b/extension/readdir.c
index 4578b864..2e34456e 100644
--- a/extension/readdir.c
+++ b/extension/readdir.c
@@ -11,20 +11,20 @@
/*
* Copyright (C) 2012-2014 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -51,7 +51,7 @@
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#else
-#error Cannot compile the dirent extension on this system!
+#error Cannot compile the readdir extension on this system!
#endif
#ifdef __MINGW32__
@@ -137,6 +137,7 @@ ftype(struct dirent *entry, const char *dirname)
}
/* get_inode --- get the inode of a file */
+
static long long
get_inode(struct dirent *entry, const char *dirname)
{
@@ -168,7 +169,8 @@ get_inode(struct dirent *entry, const char *dirname)
static int
dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
- char **rt_start, size_t *rt_len)
+ char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **unused)
{
DIR *dp;
struct dirent *dirent;
@@ -198,7 +200,7 @@ dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
return EOF;
}
- ino = get_inode (dirent, iobuf->name);
+ ino = get_inode(dirent, iobuf->name);
#if __MINGW32__
len = sprintf(the_dir->buf, "%I64u/%s", ino, dirent->d_name);
@@ -316,7 +318,7 @@ init_readdir()
}
static awk_ext_func_t func_table[] = {
- { NULL, NULL, 0 }
+ { NULL, NULL, 0, 0, awk_false, NULL }
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/readdir_test.c b/extension/readdir_test.c
new file mode 100644
index 00000000..6d6ee134
--- /dev/null
+++ b/extension/readdir_test.c
@@ -0,0 +1,343 @@
+/*
+ * readdir.c --- Provide an input parser to read directories
+ *
+ * Arnold Robbins
+ * arnold@skeeve.com
+ * Written 7/2012
+ *
+ * Andrew Schorr and Arnold Robbins: further fixes 8/2012.
+ * Simplified 11/2012.
+ */
+
+/*
+ * Copyright (C) 2012-2014, 2017 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _BSD_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#else
+#error Cannot compile the readdir extension on this system!
+#endif
+
+#ifdef __MINGW32__
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#include "gawkapi.h"
+
+#include "gawkdirfd.h"
+
+#include "gettext.h"
+#define _(msgid) gettext(msgid)
+#define N_(msgid) msgid
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* a good guess */
+#endif
+
+static const gawk_api_t *api; /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
+static const char *ext_version = "readdir extension: version 2.0";
+
+static awk_bool_t init_readdir(void);
+static awk_bool_t (*init_func)(void) = init_readdir;
+
+int plugin_is_GPL_compatible;
+
+/* data type for the opaque pointer: */
+
+typedef struct open_directory {
+ DIR *dp;
+ char *buf;
+ union {
+ awk_fieldwidth_info_t fw;
+ char buf[awk_fieldwidth_info_size(3)];
+ } u;
+} open_directory_t;
+#define fw u.fw
+
+/* ftype --- return type of file as a single character string */
+
+static const char *
+ftype(struct dirent *entry, const char *dirname)
+{
+#ifdef DT_BLK
+ (void) dirname; /* silence warnings */
+ switch (entry->d_type) {
+ case DT_BLK: return "b";
+ case DT_CHR: return "c";
+ case DT_DIR: return "d";
+ case DT_FIFO: return "p";
+ case DT_LNK: return "l";
+ case DT_REG: return "f";
+ case DT_SOCK: return "s";
+ default:
+ case DT_UNKNOWN: return "u";
+ }
+#else
+ char fname[PATH_MAX];
+ struct stat sbuf;
+
+ strcpy(fname, dirname);
+ strcat(fname, "/");
+ strcat(fname, entry->d_name);
+ if (stat(fname, &sbuf) == 0) {
+ if (S_ISBLK(sbuf.st_mode))
+ return "b";
+ if (S_ISCHR(sbuf.st_mode))
+ return "c";
+ if (S_ISDIR(sbuf.st_mode))
+ return "d";
+ if (S_ISFIFO(sbuf.st_mode))
+ return "p";
+ if (S_ISREG(sbuf.st_mode))
+ return "f";
+#ifdef S_ISLNK
+ if (S_ISLNK(sbuf.st_mode))
+ return "l";
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK(sbuf.st_mode))
+ return "s";
+#endif
+ }
+ return "u";
+#endif
+}
+
+/* get_inode --- get the inode of a file */
+
+static long long
+get_inode(struct dirent *entry, const char *dirname)
+{
+#ifdef __MINGW32__
+ char fname[PATH_MAX];
+ HANDLE fh;
+ BY_HANDLE_FILE_INFORMATION info;
+
+ sprintf(fname, "%s\\%s", dirname, entry->d_name);
+ fh = CreateFile(fname, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (fh == INVALID_HANDLE_VALUE)
+ return 0;
+ if (GetFileInformationByHandle(fh, &info)) {
+ long long inode = info.nFileIndexHigh;
+
+ inode <<= 32;
+ inode += info.nFileIndexLow;
+ return inode;
+ }
+ return 0;
+#else
+ (void) dirname; /* silence warnings */
+ return entry->d_ino;
+#endif
+}
+
+/* dir_get_record --- get one record at a time out of a directory */
+
+static int
+dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
+ char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **field_width)
+{
+ DIR *dp;
+ struct dirent *dirent;
+ int len, flen;
+ open_directory_t *the_dir;
+ const char *ftstr;
+ unsigned long long ino;
+
+ /*
+ * The caller sets *errcode to 0, so we should set it only if an
+ * error occurs.
+ */
+
+ if (out == NULL || iobuf == NULL || iobuf->opaque == NULL)
+ return EOF;
+
+ the_dir = (open_directory_t *) iobuf->opaque;
+ dp = the_dir->dp;
+
+ /*
+ * Initialize errno, since readdir does not set it to zero on EOF.
+ */
+ errno = 0;
+ dirent = readdir(dp);
+ if (dirent == NULL) {
+ *errcode = errno; /* in case there was an error */
+ return EOF;
+ }
+
+ ino = get_inode(dirent, iobuf->name);
+
+#if __MINGW32__
+ len = sprintf(the_dir->buf, "%I64u", ino);
+#else
+ len = sprintf(the_dir->buf, "%llu", ino);
+#endif
+ the_dir->fw.fields[0].len = len;
+ len += (flen = sprintf(the_dir->buf + len, "/%s", dirent->d_name));
+ the_dir->fw.fields[1].len = flen-1;
+
+ ftstr = ftype(dirent, iobuf->name);
+ len += (flen = sprintf(the_dir->buf + len, "/%s", ftstr));
+ the_dir->fw.fields[2].len = flen-1;
+
+ *out = the_dir->buf;
+
+ *rt_start = NULL;
+ *rt_len = 0; /* set RT to "" */
+ if (field_width)
+ *field_width = & the_dir->fw;
+ return len;
+}
+
+/* dir_close --- close up when done */
+
+static void
+dir_close(awk_input_buf_t *iobuf)
+{
+ open_directory_t *the_dir;
+
+ if (iobuf == NULL || iobuf->opaque == NULL)
+ return;
+
+ the_dir = (open_directory_t *) iobuf->opaque;
+
+ closedir(the_dir->dp);
+ gawk_free(the_dir->buf);
+ gawk_free(the_dir);
+
+ iobuf->fd = -1;
+}
+
+/* dir_can_take_file --- return true if we want the file */
+
+static awk_bool_t
+dir_can_take_file(const awk_input_buf_t *iobuf)
+{
+ if (iobuf == NULL)
+ return awk_false;
+
+ return (iobuf->fd != INVALID_HANDLE && S_ISDIR(iobuf->sbuf.st_mode));
+}
+
+/*
+ * dir_take_control_of --- set up input parser.
+ * We can assume that dir_can_take_file just returned true,
+ * and no state has changed since then.
+ */
+
+static awk_bool_t
+dir_take_control_of(awk_input_buf_t *iobuf)
+{
+ DIR *dp;
+ open_directory_t *the_dir;
+ size_t size;
+
+ errno = 0;
+#ifdef HAVE_FDOPENDIR
+ dp = fdopendir(iobuf->fd);
+#else
+ dp = opendir(iobuf->name);
+ if (dp != NULL)
+ iobuf->fd = dirfd(dp);
+#endif
+ if (dp == NULL) {
+ warning(ext_id, _("dir_take_control_of: opendir/fdopendir failed: %s"),
+ strerror(errno));
+ update_ERRNO_int(errno);
+ return awk_false;
+ }
+
+ emalloc(the_dir, open_directory_t *, sizeof(open_directory_t), "dir_take_control_of");
+ the_dir->dp = dp;
+ /* pre-populate the field_width struct with constant values: */
+ the_dir->fw.use_chars = awk_false;
+ the_dir->fw.nf = 3;
+ the_dir->fw.fields[0].skip = 0; /* no leading space */
+ the_dir->fw.fields[1].skip = 1; /* single '/' separator */
+ the_dir->fw.fields[2].skip = 1; /* single '/' separator */
+ size = sizeof(struct dirent) + 21 /* max digits in inode */ + 2 /* slashes */;
+ emalloc(the_dir->buf, char *, size, "dir_take_control_of");
+
+ iobuf->opaque = the_dir;
+ iobuf->get_record = dir_get_record;
+ iobuf->close_func = dir_close;
+
+ return awk_true;
+}
+
+static awk_input_parser_t readdir_parser = {
+ "readdir",
+ dir_can_take_file,
+ dir_take_control_of,
+ NULL
+};
+
+#ifdef TEST_DUPLICATE
+static awk_input_parser_t readdir_parser2 = {
+ "readdir2",
+ dir_can_take_file,
+ dir_take_control_of,
+ NULL
+};
+#endif
+
+/* init_readdir --- set things ups */
+
+static awk_bool_t
+init_readdir()
+{
+ register_input_parser(& readdir_parser);
+#ifdef TEST_DUPLICATE
+ register_input_parser(& readdir_parser2);
+#endif
+
+ return awk_true;
+}
+
+static awk_ext_func_t func_table[] = {
+ { NULL, NULL, 0, 0, awk_false, NULL }
+};
+
+/* define the dl_load function using the boilerplate macro */
+
+dl_load_func(func_table, readdir, "")
diff --git a/extension/readfile.c b/extension/readfile.c
index d4b4aef9..b600f27a 100644
--- a/extension/readfile.c
+++ b/extension/readfile.c
@@ -14,20 +14,20 @@
/*
* Copyright (C) 2002, 2003, 2004, 2011, 2012, 2013, 2014
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -73,32 +73,29 @@ int plugin_is_GPL_compatible;
static char *
read_file_to_buffer(int fd, const struct stat *sbuf)
{
- char *text = NULL;
- int ret;
+ char *text;
if ((sbuf->st_mode & S_IFMT) != S_IFREG) {
errno = EINVAL;
update_ERRNO_int(errno);
- goto done;
+ return NULL;
}
- emalloc(text, char *, sbuf->st_size + 2, "do_readfile");
- memset(text, '\0', sbuf->st_size + 2);
+ emalloc(text, char *, sbuf->st_size + 1, "do_readfile");
- if ((ret = read(fd, text, sbuf->st_size)) != sbuf->st_size) {
+ if (read(fd, text, sbuf->st_size) != sbuf->st_size) {
update_ERRNO_int(errno);
gawk_free(text);
- text = NULL;
- /* fall through to return */
+ return NULL;
}
-done:
+ text[sbuf->st_size] = '\0';
return text;
}
/* do_readfile --- read a file into memory */
static awk_value_t *
-do_readfile(int nargs, awk_value_t *result)
+do_readfile(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename;
int ret;
@@ -109,9 +106,6 @@ do_readfile(int nargs, awk_value_t *result)
assert(result != NULL);
make_null_string(result); /* default return value */
- if (do_lint && nargs > 1)
- lintwarn(ext_id, _("readfile: called with too many arguments"));
-
unset_ERRNO();
if (get_argument(0, AWK_STRING, &filename)) {
@@ -134,7 +128,7 @@ do_readfile(int nargs, awk_value_t *result)
make_malloced_string(text, sbuf.st_size, result);
goto done;
} else if (do_lint)
- lintwarn(ext_id, _("readfile: called with no arguments"));
+ lintwarn(ext_id, _("readfile: called with wrong kind of argument"));
done:
/* Set the return value */
@@ -145,7 +139,8 @@ done:
static int
readfile_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
- char **rt_start, size_t *rt_len)
+ char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **unused)
{
char *text;
@@ -241,7 +236,7 @@ init_readfile()
}
static awk_ext_func_t func_table[] = {
- { "readfile", do_readfile, 1 },
+ { "readfile", do_readfile, 1, 1, awk_false, NULL },
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/revoutput.c b/extension/revoutput.c
index 69257167..5862ed6e 100644
--- a/extension/revoutput.c
+++ b/extension/revoutput.c
@@ -8,20 +8,20 @@
/*
* Copyright (C) 2012, 2013, 2015 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -134,7 +134,7 @@ init_revoutput()
}
static awk_ext_func_t func_table[] = {
- { NULL, NULL, 0 }
+ { NULL, NULL, 0, 0, awk_false, NULL }
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/revtwoway.c b/extension/revtwoway.c
index dfe58a1e..84989bfc 100644
--- a/extension/revtwoway.c
+++ b/extension/revtwoway.c
@@ -8,20 +8,20 @@
/*
* Copyright (C) 2012-2014, 2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -133,7 +133,8 @@ close_two_proc_data(two_way_proc_data_t *proc_data)
static int
rev2way_get_record(char **out, awk_input_buf_t *iobuf, int *errcode,
- char **rt_start, size_t *rt_len)
+ char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **unused)
{
int len = 0; /* for now */
two_way_proc_data_t *proc_data;
@@ -336,7 +337,7 @@ init_revtwoway()
}
static awk_ext_func_t func_table[] = {
- { NULL, NULL, 0 }
+ { NULL, NULL, 0, 0, awk_false, NULL }
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extension/rwarray.c b/extension/rwarray.c
index 155cc47c..53c908df 100644
--- a/extension/rwarray.c
+++ b/extension/rwarray.c
@@ -8,20 +8,20 @@
/*
* Copyright (C) 2009-2014 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -41,6 +41,7 @@
#ifdef __MINGW32__
#include <winsock2.h>
+#include <stdint.h>
#else
#include <arpa/inet.h>
#endif
@@ -55,11 +56,11 @@
#define MAGIC "awkrulz\n"
#define MAJOR 3
-#define MINOR 0
+#define MINOR 1
static const gawk_api_t *api; /* for convenience macros to work */
static awk_ext_id_t *ext_id;
-static const char *ext_version = "rwarray extension: version 1.0";
+static const char *ext_version = "rwarray extension: version 1.1";
static awk_bool_t (*init_func)(void) = NULL;
int plugin_is_GPL_compatible;
@@ -80,11 +81,11 @@ static awk_bool_t read_value(FILE *fp, awk_value_t *value);
* Minor version 4 bytes - network order
* Element count 4 bytes - network order
* Elements
- *
+ *
* For each element:
* Length of index val: 4 bytes - network order
* Index val as characters (N bytes)
- * Value type 4 bytes (0 = string, 1 = number, 2 = array)
+ * Value type 4 bytes (0 = string, 1 = number, 2 = array, 3 = regex, 4 = strnum)
* IF string:
* Length of value 4 bytes
* Value as characters (N bytes)
@@ -99,7 +100,7 @@ static awk_bool_t read_value(FILE *fp, awk_value_t *value);
/* do_writea --- write an array */
static awk_value_t *
-do_writea(int nargs, awk_value_t *result)
+do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename, array;
FILE *fp = NULL;
@@ -109,9 +110,6 @@ do_writea(int nargs, awk_value_t *result)
assert(result != NULL);
make_number(0.0, result);
- if (do_lint && nargs > 2)
- lintwarn(ext_id, _("writea: called with too many arguments"));
-
if (nargs < 2)
goto out;
@@ -213,7 +211,7 @@ write_elem(FILE *fp, awk_element_t *element)
return write_value(fp, & element->value);
}
-/* write_value --- write a number or a string or a array */
+/* write_value --- write a number or a string or a strnum or a regex or an array */
static awk_bool_t
write_value(FILE *fp, awk_value_t *val)
@@ -235,7 +233,22 @@ write_value(FILE *fp, awk_value_t *val)
if (fwrite(& val->num_value, 1, sizeof(val->num_value), fp) != sizeof(val->num_value))
return awk_false;
} else {
- code = 0;
+ switch (val->val_type) {
+ case AWK_STRING:
+ code = htonl(0);
+ break;
+ case AWK_STRNUM:
+ code = htonl(4);
+ break;
+ case AWK_REGEX:
+ code = htonl(3);
+ break;
+ default:
+ /* XXX can this happen? */
+ code = htonl(0);
+ warning(ext_id, _("array value has unknown type %d"), val->val_type);
+ break;
+ }
if (fwrite(& code, 1, sizeof(code), fp) != sizeof(code))
return awk_false;
@@ -254,7 +267,7 @@ write_value(FILE *fp, awk_value_t *val)
/* do_reada --- read an array */
static awk_value_t *
-do_reada(int nargs, awk_value_t *result)
+do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename, array;
FILE *fp = NULL;
@@ -265,9 +278,6 @@ do_reada(int nargs, awk_value_t *result)
assert(result != NULL);
make_number(0.0, result);
- if (do_lint && nargs > 2)
- lintwarn(ext_id, _("reada: called with too many arguments"));
-
if (nargs < 2)
goto out;
@@ -436,7 +446,7 @@ read_value(FILE *fp, awk_value_t *value)
awk_array_t array = create_array();
if (! read_array(fp, array))
- return awk_false;
+ return awk_false;
/* hook into value */
value->val_type = AWK_ARRAY;
@@ -455,23 +465,38 @@ read_value(FILE *fp, awk_value_t *value)
return awk_false;
}
len = ntohl(len);
- value->val_type = AWK_STRING;
+ switch (code) {
+ case 0:
+ value->val_type = AWK_STRING;
+ break;
+ case 3:
+ value->val_type = AWK_REGEX;
+ break;
+ case 4:
+ value->val_type = AWK_STRNUM;
+ break;
+ default:
+ /* this cannot happen! */
+ warning(ext_id, _("treating recovered value with unknown type code %d as a string"), code);
+ value->val_type = AWK_STRING;
+ break;
+ }
value->str_value.len = len;
- value->str_value.str = gawk_malloc(len + 2);
- memset(value->str_value.str, '\0', len + 2);
+ value->str_value.str = gawk_malloc(len + 1);
if (fread(value->str_value.str, 1, len, fp) != (ssize_t) len) {
gawk_free(value->str_value.str);
return awk_false;
}
+ value->str_value.str[len] = '\0';
}
return awk_true;
}
static awk_ext_func_t func_table[] = {
- { "writea", do_writea, 2 },
- { "reada", do_reada, 2 },
+ { "writea", do_writea, 2, 2, awk_false, NULL },
+ { "reada", do_reada, 2, 2, awk_false, NULL },
};
diff --git a/extension/rwarray0.c b/extension/rwarray0.c
index e2de3cf5..79dee79e 100644
--- a/extension/rwarray0.c
+++ b/extension/rwarray0.c
@@ -8,20 +8,20 @@
/*
* Copyright (C) 2009, 2010, 2011, 2012, 2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -76,7 +76,7 @@ static awk_bool_t read_value(int fd, awk_value_t *value);
* Minor version 4 bytes - network order
* Element count 4 bytes - network order
* Elements
- *
+ *
* For each element:
* Length of index val: 4 bytes - network order
* Index val as characters (N bytes)
@@ -95,7 +95,7 @@ static awk_bool_t read_value(int fd, awk_value_t *value);
/* do_writea --- write an array */
static awk_value_t *
-do_writea(int nargs, awk_value_t *result)
+do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename, array;
int fd = -1;
@@ -105,9 +105,6 @@ do_writea(int nargs, awk_value_t *result)
assert(result != NULL);
make_number(0.0, result);
- if (do_lint && nargs > 2)
- lintwarn(ext_id, _("writea: called with too many arguments"));
-
if (nargs < 2)
goto out;
@@ -250,7 +247,7 @@ write_value(int fd, awk_value_t *val)
/* do_reada --- read an array */
static awk_value_t *
-do_reada(int nargs, awk_value_t *result)
+do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t filename, array;
int fd = -1;
@@ -261,9 +258,6 @@ do_reada(int nargs, awk_value_t *result)
assert(result != NULL);
make_number(0.0, result);
- if (do_lint && nargs > 2)
- lintwarn(ext_id, _("reada: called with too many arguments"));
-
if (nargs < 2)
goto out;
@@ -431,7 +425,7 @@ read_value(int fd, awk_value_t *value)
awk_array_t array = create_array();
if (read_array(fd, array) != 0)
- return awk_false;
+ return awk_false;
/* hook into value */
value->val_type = AWK_ARRAY;
@@ -452,21 +446,21 @@ read_value(int fd, awk_value_t *value)
len = ntohl(len);
value->val_type = AWK_STRING;
value->str_value.len = len;
- value->str_value.str = malloc(len + 2);
- memset(value->str_value.str, '\0', len + 2);
+ value->str_value.str = malloc(len + 1);
if (read(fd, value->str_value.str, len) != (ssize_t) len) {
free(value->str_value.str);
return awk_false;
}
+ value->str_value.str[len] = '\0';
}
return awk_true;
}
static awk_ext_func_t func_table[] = {
- { "writea", do_writea, 2 },
- { "reada", do_reada, 2 },
+ { "writea", do_writea, 2, 2, awk_false, NULL },
+ { "reada", do_reada, 2, 2, awk_false, NULL },
};
diff --git a/extension/stack.c b/extension/stack.c
index 6150442c..637378e2 100644
--- a/extension/stack.c
+++ b/extension/stack.c
@@ -2,22 +2,22 @@
* stack.c -- Implementation for stack functions for use by extensions.
*/
-/*
+/*
* Copyright (C) 2012, 2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
diff --git a/extension/testext.c b/extension/testext.c
index 4a1e7032..572475e0 100644
--- a/extension/testext.c
+++ b/extension/testext.c
@@ -5,20 +5,20 @@
/*
* Copyright (C) 2012, 2013, 2014, 2015
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -37,6 +37,7 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include "gawkapi.h"
@@ -48,6 +49,15 @@ int plugin_is_GPL_compatible;
static void fill_in_array(awk_value_t *value);
+#ifdef __MINGW32__
+unsigned int
+getuid (void)
+{
+ /* See pc/getid.c. */
+ return 0;
+}
+#endif
+
/* valrep2str --- turn a value into a string */
static const char *
@@ -69,6 +79,8 @@ valrep2str(const awk_value_t *value)
case AWK_VALUE_COOKIE:
strcpy(buf, "<value-cookie>");
break;
+ case AWK_REGEX:
+ case AWK_STRNUM:
case AWK_STRING:
if (value->str_value.len < size)
size = value->str_value.len;
@@ -106,7 +118,7 @@ BEGIN {
}
*/
static awk_value_t *
-dump_array_and_delete(int nargs, awk_value_t *result)
+dump_array_and_delete(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t value, value2, value3;
awk_flat_array_t *flat_array;
@@ -200,7 +212,7 @@ BEGIN {
*/
static awk_value_t *
-try_modify_environ(int nargs, awk_value_t *result)
+try_modify_environ(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t value, index, newvalue;
awk_flat_array_t *flat_array;
@@ -289,7 +301,7 @@ BEGIN {
*/
static awk_value_t *
-var_test(int nargs, awk_value_t *result)
+var_test(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t value, value2;
awk_value_t *valp;
@@ -356,7 +368,7 @@ BEGIN {
}
*/
static awk_value_t *
-test_errno(int nargs, awk_value_t *result)
+test_errno(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
assert(result != NULL);
make_number(0.0, result);
@@ -374,6 +386,84 @@ out:
}
/*
+ * 3/2015: This test is no longer strictly necessary,
+ * since PROCINFO is no longer a deferred variable.
+ * But we leave it in for safety, anyway.
+ */
+/*
+BEGIN {
+ print "test_deferred returns", test_deferred()
+ print ""
+}
+*/
+static awk_value_t *
+test_deferred(int nargs, awk_value_t *result, struct awk_ext_func *unused)
+{
+ awk_value_t arr;
+ awk_value_t index, value;
+ const struct nval {
+ const char *name;
+ double val;
+ } seed[] = {
+ { "fubar", 9.0, },
+ { "rumpus", -5.0, },
+ };
+ struct nval sysval[] = {
+ { "uid", getuid(), },
+ { "api_major", GAWK_API_MAJOR_VERSION, },
+ };
+ size_t i;
+
+ assert(result != NULL);
+ make_number(0.0, result);
+
+ if (nargs != 0) {
+ printf("test_deferred: nargs not right (%d should be 0)\n", nargs);
+ goto out;
+ }
+
+ if (! sym_lookup("PROCINFO", AWK_ARRAY, & arr)) {
+ printf("test_deferred: %d: sym_lookup failed\n", __LINE__);
+ goto out;
+ }
+
+ for (i = 0; i < sizeof(seed)/sizeof(seed[0]); i++) {
+ make_const_string(seed[i].name, strlen(seed[i].name), & index);
+ make_number(seed[i].val, & value);
+ if (! set_array_element(arr.array_cookie, & index, & value)) {
+ printf("test_deferred: %d: set_array_element(%s) failed\n", __LINE__, seed[i].name);
+ goto out;
+ }
+ }
+
+ /* test that it still contains the values we loaded */
+ for (i = 0; i < sizeof(seed)/sizeof(seed[0]); i++) {
+ make_const_string(seed[i].name, strlen(seed[i].name), & index);
+ make_null_string(& value);
+ if (! get_array_element(arr.array_cookie, &index, AWK_NUMBER, & value)) {
+ printf("test_deferred: %d: get_array_element(%s) failed\n", __LINE__, seed[i].name);
+ goto out;
+ }
+ printf("%s = %g\n", seed[i].name, value.num_value);
+ }
+
+ /* check a few automatically-supplied values */
+ for (i = 0; i < sizeof(sysval)/sizeof(sysval[0]); i++) {
+ make_const_string(sysval[i].name, strlen(sysval[i].name), & index);
+ make_null_string(& value);
+ if (! get_array_element(arr.array_cookie, &index, AWK_NUMBER, & value)) {
+ printf("test_deferred: %d: get_array_element(%s) failed\n", __LINE__, sysval[i].name);
+ goto out;
+ }
+ printf("%s matches %d\n", sysval[i].name, (value.num_value == sysval[i].val));
+ }
+
+ make_number(1.0, result);
+out:
+ return result;
+}
+
+/*
BEGIN {
for (i = 1; i <= 10; i++)
test_array[i] = i + 2
@@ -386,7 +476,7 @@ BEGIN {
*/
static awk_value_t *
-test_array_size(int nargs, awk_value_t *result)
+test_array_size(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t value;
size_t count = 0;
@@ -450,7 +540,7 @@ BEGIN {
}
*/
static awk_value_t *
-test_array_elem(int nargs, awk_value_t *result)
+test_array_elem(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t array, index, index2, value;
@@ -538,7 +628,7 @@ BEGIN {
*/
static awk_value_t *
-test_array_param(int nargs, awk_value_t *result)
+test_array_param(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t new_array;
awk_value_t arg0;
@@ -581,7 +671,7 @@ BEGIN {
}
*/
static awk_value_t *
-print_do_lint(int nargs, awk_value_t *result)
+print_do_lint(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
assert(result != NULL);
make_number(0.0, result);
@@ -617,7 +707,7 @@ BEGIN {
/* test_scalar --- test scalar cookie */
static awk_value_t *
-test_scalar(int nargs, awk_value_t *result)
+test_scalar(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t new_value, new_value2;
awk_value_t the_scalar;
@@ -664,7 +754,7 @@ BEGIN {
/* test_scalar_reserved --- test scalar cookie on special variable */
static awk_value_t *
-test_scalar_reserved(int nargs, awk_value_t *result)
+test_scalar_reserved(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t new_value;
awk_value_t the_scalar;
@@ -710,13 +800,14 @@ BEGIN {
ret = test_indirect_vars() # should get correct value of NR
printf("test_indirect_var() return %d\n", ret)
delete ARGV[1]
+ print ""
}
*/
/* test_indirect_vars --- test that access to NR, NF, get correct vales */
static awk_value_t *
-test_indirect_vars(int nargs, awk_value_t *result)
+test_indirect_vars(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t value;
char *name = "NR";
@@ -742,6 +833,124 @@ out:
return result;
}
+/*
+BEGIN {
+ outfile = "testexttmp.txt"
+ alias = ".test.alias"
+ print "line 1" > outfile
+ print "line 2" > outfile
+ print "line 3" > outfile
+ close(outfile)
+ ret = test_get_file(outfile, alias)
+ printf "test_get_file returned %d\n", ret
+ nr = 0
+ while ((getline < alias) > 0)
+ printf "File [%s] nr [%s]: %s\n", alias, ++nr, $0
+ close(alias)
+ system("rm " outfile)
+ print ""
+}
+*/
+
+/* test_get_file --- test that we can create a file */
+
+static awk_value_t *
+test_get_file(int nargs, awk_value_t *result, struct awk_ext_func *unused)
+{
+ awk_value_t filename, alias;
+ int fd;
+ const awk_input_buf_t *ibuf;
+ const awk_output_buf_t *obuf;
+
+ if (nargs != 2) {
+ printf("%s: nargs not right (%d should be 2)\n", "test_get_file", nargs);
+ return make_number(-1.0, result);
+ }
+
+ if (! get_argument(0, AWK_STRING, & filename)) {
+ printf("%s: cannot get first arg\n", "test_get_file");
+ return make_number(-1.0, result);
+ }
+ if (! get_argument(1, AWK_STRING, & alias)) {
+ printf("%s: cannot get second arg\n", "test_get_file");
+ return make_number(-1.0, result);
+ }
+ if ((fd = open(filename.str_value.str, O_RDONLY)) < 0) {
+ printf("%s: open(%s) failed\n", "test_get_file", filename.str_value.str);
+ return make_number(-1.0, result);
+ }
+ if (! get_file(alias.str_value.str, strlen(alias.str_value.str), "<", fd, &ibuf, &obuf)) {
+ printf("%s: get_file(%s) failed\n", "test_get_file", alias.str_value.str);
+ return make_number(-1.0, result);
+ }
+ if (! ibuf || ibuf->fd != fd) {
+ printf("%s: get_file(%s) returned fd %d instead of %d\n", "test_get_file", alias.str_value.str, ibuf ? ibuf->fd : -1, fd);
+ return make_number(-1.0, result);
+ }
+ return make_number(0.0, result);
+}
+
+/* do_get_file --- provide access to get_file API */
+
+static awk_value_t *
+do_get_file(int nargs, awk_value_t *result, struct awk_ext_func *unused)
+{
+ awk_value_t filename, filetype, fd, res;
+ const awk_input_buf_t *ibuf;
+ const awk_output_buf_t *obuf;
+
+ if (nargs != 4) {
+ printf("%s: nargs not right (%d should be 4)\n", "get_file", nargs);
+ return make_number(-1.0, result);
+ }
+
+ if (! get_argument(0, AWK_STRING, & filename)) {
+ printf("%s: cannot get first arg\n", "get_file");
+ return make_number(-1.0, result);
+ }
+ if (! get_argument(1, AWK_STRING, & filetype)) {
+ printf("%s: cannot get second arg\n", "get_file");
+ return make_number(-1.0, result);
+ }
+ if (! get_argument(2, AWK_NUMBER, & fd)) {
+ printf("%s: cannot get third arg\n", "get_file");
+ return make_number(-1.0, result);
+ }
+ if (! get_argument(3, AWK_ARRAY, & res)) {
+ printf("%s: cannot get fourth arg\n", "get_file");
+ return make_number(-1.0, result);
+ }
+ clear_array(res.array_cookie);
+
+ if (! get_file(filename.str_value.str, strlen(filename.str_value.str), filetype.str_value.str, fd.num_value, &ibuf, &obuf)) {
+ printf("%s: get_file(%s, %s, %d) failed\n", "get_file", filename.str_value.str, filetype.str_value.str, (int)(fd.num_value));
+ return make_number(0.0, result);
+ }
+
+ if (ibuf) {
+ awk_value_t idx, val;
+ set_array_element(res.array_cookie,
+ make_const_string("input", 5, & idx),
+ make_number(ibuf->fd, & val));
+ if (ibuf->name)
+ set_array_element(res.array_cookie,
+ make_const_string("input_name", 10, & idx),
+ make_const_string(ibuf->name, strlen(ibuf->name), & val));
+ }
+ if (obuf) {
+ awk_value_t idx, val;
+ set_array_element(res.array_cookie,
+ make_const_string("output", 6, & idx),
+ make_number(obuf->fp ? fileno(obuf->fp) : -1,
+ & val));
+ if (obuf->name)
+ set_array_element(res.array_cookie,
+ make_const_string("output_name", 11, & idx),
+ make_const_string(obuf->name, strlen(obuf->name), & val));
+ }
+ return make_number(1.0, result);
+}
+
/* fill_in_array --- fill in a new array */
static void
@@ -826,17 +1035,20 @@ static void at_exit2(void *data, int exit_status)
}
static awk_ext_func_t func_table[] = {
- { "dump_array_and_delete", dump_array_and_delete, 2 },
- { "try_modify_environ", try_modify_environ, 0 },
- { "var_test", var_test, 1 },
- { "test_errno", test_errno, 0 },
- { "test_array_size", test_array_size, 1 },
- { "test_array_elem", test_array_elem, 2 },
- { "test_array_param", test_array_param, 1 },
- { "print_do_lint", print_do_lint, 0 },
- { "test_scalar", test_scalar, 1 },
- { "test_scalar_reserved", test_scalar_reserved, 0 },
- { "test_indirect_vars", test_indirect_vars, 0 },
+ { "dump_array_and_delete", dump_array_and_delete, 2, 2, awk_false, NULL },
+ { "try_modify_environ", try_modify_environ, 0, 0, awk_false, NULL },
+ { "var_test", var_test, 1, 1, awk_false, NULL },
+ { "test_deferred", test_deferred, 0, 0, awk_false, NULL },
+ { "test_errno", test_errno, 0, 0, awk_false, NULL },
+ { "test_array_size", test_array_size, 1, 1, awk_false, NULL },
+ { "test_array_elem", test_array_elem, 2, 2, awk_false, NULL },
+ { "test_array_param", test_array_param, 1, 1, awk_false, NULL },
+ { "print_do_lint", print_do_lint, 0, 0, awk_false, NULL },
+ { "test_scalar", test_scalar, 1, 1, awk_false, NULL },
+ { "test_scalar_reserved", test_scalar_reserved, 0, 0, awk_false, NULL },
+ { "test_indirect_vars", test_indirect_vars, 0, 0, awk_false, NULL },
+ { "test_get_file", test_get_file, 2, 2, awk_false, NULL },
+ { "get_file", do_get_file, 4, 4, awk_false, NULL },
};
/* init_testext --- additional initialization function */
@@ -847,6 +1059,10 @@ static awk_bool_t init_testext(void)
static const char message[] = "hello, world"; /* of course */
static const char message2[] = "i am a scalar";
+ /* This is used by the getfile test */
+ if (sym_lookup("TESTEXT_QUIET", AWK_NUMBER, & value))
+ return awk_true;
+
/* add at_exit functions */
awk_atexit(at_exit0, NULL);
awk_atexit(at_exit1, & data_for_1);
diff --git a/extension/time.c b/extension/time.c
index e6b2b39f..01be7784 100644
--- a/extension/time.c
+++ b/extension/time.c
@@ -103,15 +103,12 @@ int plugin_is_GPL_compatible;
* on the platform
*/
static awk_value_t *
-do_gettimeofday(int nargs, awk_value_t *result)
+do_gettimeofday(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
double curtime;
assert(result != NULL);
- if (do_lint && nargs > 0)
- lintwarn(ext_id, _("gettimeofday: ignoring arguments"));
-
#if defined(HAVE_GETTIMEOFDAY)
{
struct timeval tv;
@@ -153,7 +150,7 @@ do_gettimeofday(int nargs, awk_value_t *result)
* did not complete successfully (perhaps interrupted)
*/
static awk_value_t *
-do_sleep(int nargs, awk_value_t *result)
+do_sleep(int nargs, awk_value_t *result, struct awk_ext_func *unused)
{
awk_value_t num;
double secs;
@@ -161,9 +158,6 @@ do_sleep(int nargs, awk_value_t *result)
assert(result != NULL);
- if (do_lint && nargs > 1)
- lintwarn(ext_id, _("sleep: called with too many arguments"));
-
if (! get_argument(0, AWK_NUMBER, &num)) {
update_ERRNO_string(_("sleep: missing required numeric argument"));
return make_number(-1, result);
@@ -212,8 +206,8 @@ do_sleep(int nargs, awk_value_t *result)
}
static awk_ext_func_t func_table[] = {
- { "gettimeofday", do_gettimeofday, 0 },
- { "sleep", do_sleep, 1 },
+ { "gettimeofday", do_gettimeofday, 0, 0, awk_false, NULL },
+ { "sleep", do_sleep, 1, 1, awk_false, NULL },
};
/* define the dl_load function using the boilerplate macro */
diff --git a/extras/ChangeLog b/extras/ChangeLog
new file mode 100644
index 00000000..5f7d33ad
--- /dev/null
+++ b/extras/ChangeLog
@@ -0,0 +1,3 @@
+2014-10-29 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am, gawk.sh, gawk.csh: New files.
diff --git a/extras/Makefile.am b/extras/Makefile.am
new file mode 100644
index 00000000..6a33ae04
--- /dev/null
+++ b/extras/Makefile.am
@@ -0,0 +1,29 @@
+#
+# extras/Makefile.am --- automake input file for gawk
+#
+# Copyright (C) 2014 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## Process this file with automake to produce Makefile.in.
+
+profiledir = $(sysconfdir)/profile.d
+profile_DATA = gawk.sh gawk.csh
+
+EXTRA_DIST = $(profile_DATA)
diff --git a/extras/Makefile.in b/extras/Makefile.in
new file mode 100644
index 00000000..5c92819b
--- /dev/null
+++ b/extras/Makefile.in
@@ -0,0 +1,529 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# extras/Makefile.am --- automake input file for gawk
+#
+# Copyright (C) 2014 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = extras
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libsigsegv.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(profiledir)"
+DATA = $(profile_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/mkinstalldirs \
+ ChangeLog
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GAWKLIBEXT = @GAWKLIBEXT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_LIBSIGSEGV = @HAVE_LIBSIGSEGV@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMPFR = @LIBMPFR@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBSIGSEGV = @LIBSIGSEGV@
+LIBSIGSEGV_PREFIX = @LIBSIGSEGV_PREFIX@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBSIGSEGV = @LTLIBSIGSEGV@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+acl_shlibext = @acl_shlibext@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgextensiondir = @pkgextensiondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+profiledir = $(sysconfdir)/profile.d
+profile_DATA = gawk.sh gawk.csh
+EXTRA_DIST = $(profile_DATA)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu extras/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu extras/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-profileDATA: $(profile_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(profile_DATA)'; test -n "$(profiledir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(profiledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(profiledir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(profiledir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(profiledir)" || exit $$?; \
+ done
+
+uninstall-profileDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(profile_DATA)'; test -n "$(profiledir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(profiledir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(profiledir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-profileDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-profileDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
+ ctags-am distclean distclean-generic distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-profileDATA install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags-am uninstall uninstall-am \
+ uninstall-profileDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/extras/gawk.csh b/extras/gawk.csh
new file mode 100644
index 00000000..583d5bcd
--- /dev/null
+++ b/extras/gawk.csh
@@ -0,0 +1,11 @@
+alias gawkpath_default 'unsetenv AWKPATH; setenv AWKPATH `gawk -v x=AWKPATH "BEGIN {print ENVIRON[x]}"`'
+
+alias gawkpath_prepend 'if (! $?AWKPATH) setenv AWKPATH ""; if ($AWKPATH == "") then; unsetenv AWKPATH; setenv AWKPATH `gawk -v x=AWKPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKPATH "\!*"":$AWKPATH"'
+
+alias gawkpath_append 'if (! $?AWKPATH) setenv AWKPATH ""; if ($AWKPATH == "") then; unsetenv AWKPATH; setenv AWKPATH `gawk -v x=AWKPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKPATH "$AWKPATH"":\!*"'
+
+alias gawklibpath_default 'unsetenv AWKLIBPATH; setenv AWKLIBPATH `gawk -v x=AWKLIBPATH "BEGIN {print ENVIRON[x]}"`'
+
+alias gawklibpath_prepend 'if (! $?AWKLIBPATH) setenv AWKLIBPATH ""; if ($AWKLIBPATH == "") then; unsetenv AWKLIBPATH; setenv AWKLIBPATH `gawk -v x=AWKLIBPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKLIBPATH "\!*"":$AWKLIBPATH"'
+
+alias gawklibpath_append 'if (! $?AWKLIBPATH) setenv AWKLIBPATH ""; if ($AWKLIBPATH == "") then; unsetenv AWKLIBPATH; setenv AWKLIBPATH `gawk -v x=AWKLIBPATH "BEGIN {print ENVIRON[x]}"`; endif; setenv AWKLIBPATH "$AWKLIBPATH"":\!*"'
diff --git a/extras/gawk.sh b/extras/gawk.sh
new file mode 100644
index 00000000..c35471fa
--- /dev/null
+++ b/extras/gawk.sh
@@ -0,0 +1,31 @@
+gawkpath_default () {
+ unset AWKPATH
+ export AWKPATH=`gawk 'BEGIN {print ENVIRON["AWKPATH"]}'`
+}
+
+gawkpath_prepend () {
+ [ -z "$AWKPATH" ] && AWKPATH=`gawk 'BEGIN {print ENVIRON["AWKPATH"]}'`
+ export AWKPATH="$*:$AWKPATH"
+}
+
+gawkpath_append () {
+ [ -z "$AWKPATH" ] && AWKPATH=`gawk 'BEGIN {print ENVIRON["AWKPATH"]}'`
+ export AWKPATH="$AWKPATH:$*"
+}
+
+gawklibpath_default () {
+ unset AWKLIBPATH
+ export AWKLIBPATH=`gawk 'BEGIN {print ENVIRON["AWKLIBPATH"]}'`
+}
+
+gawklibpath_prepend () {
+ [ -z "$AWKLIBPATH" ] && \
+ AWKLIBPATH=`gawk 'BEGIN {print ENVIRON["AWKLIBPATH"]}'`
+ export AWKLIBPATH="$*:$AWKLIBPATH"
+}
+
+gawklibpath_append () {
+ [ -z "$AWKLIBPATH" ] && \
+ AWKLIBPATH=`gawk 'BEGIN {print ENVIRON["AWKLIBPATH"]}'`
+ export AWKLIBPATH="$AWKLIBPATH:$*"
+}
diff --git a/field.c b/field.c
index 5f5b2b65..d8c97413 100644
--- a/field.c
+++ b/field.c
@@ -2,22 +2,22 @@
* field.c - routines for dealing with fields and record parsing
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -38,25 +38,34 @@ is_blank(int c)
typedef void (* Setfunc)(long, char *, long, NODE *);
-static long (*parse_field)(long, char **, int, NODE *,
+/* is the API currently overriding the default parsing mechanism? */
+static bool api_parser_override = false;
+typedef long (*parse_field_func_t)(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
+static parse_field_func_t parse_field;
+/*
+ * N.B. The normal_parse_field function pointer contains the parse_field value
+ * that should be used except when API field parsing is overriding the default
+ * field parsing mechanism.
+ */
+static parse_field_func_t normal_parse_field;
static long re_parse_field(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
static long def_parse_field(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
-static long posix_def_parse_field(long, char **, int, NODE *,
- Regexp *, Setfunc, NODE *, NODE *, bool);
static long null_parse_field(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
static long sc_parse_field(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
static long fw_parse_field(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
+static const awk_fieldwidth_info_t *api_fw = NULL;
static long fpat_parse_field(long, char **, int, NODE *,
Regexp *, Setfunc, NODE *, NODE *, bool);
static void set_element(long num, char * str, long len, NODE *arr);
static void grow_fields_arr(long num);
static void set_field(long num, char *str, long len, NODE *dummy);
+static void purge_record(void);
static char *parse_extent; /* marks where to restart parse of record */
static long parse_high_water = 0; /* field number that we have parsed so far */
@@ -65,7 +74,7 @@ static bool resave_fs;
static NODE *save_FS; /* save current value of FS when line is read,
* to be used in deferred parsing
*/
-static int *FIELDWIDTHS = NULL;
+static awk_fieldwidth_info_t *FIELDWIDTHS = NULL;
NODE **fields_arr; /* array of pointers to the field nodes */
bool field0_valid; /* $(>0) has not been changed yet */
@@ -95,7 +104,7 @@ init_fields()
getnode(Null_field);
*Null_field = *Nnull_string;
Null_field->valref = 1;
- Null_field->flags = (FIELD|STRCUR|STRING|NULL_FIELD);
+ Null_field->flags = (STRCUR|STRING|NULL_FIELD); /* do not set MALLOC */
field0_valid = true;
}
@@ -133,7 +142,7 @@ set_field(long num,
n = fields_arr[num];
n->stptr = str;
n->stlen = len;
- n->flags = (STRCUR|STRING|MAYBE_NUM|FIELD);
+ n->flags = (STRCUR|STRING|USER_INPUT); /* do not set MALLOC */
}
/* rebuild_record --- Someone assigned a value to $(something).
@@ -163,7 +172,7 @@ rebuild_record()
tlen += (NF - 1) * OFSlen;
if ((long) tlen < 0)
tlen = 0;
- emalloc(ops, char *, tlen + 2, "rebuild_record");
+ emalloc(ops, char *, tlen + 1, "rebuild_record");
cops = ops;
ops[0] = '\0';
for (i = 1; i <= NF; i++) {
@@ -196,29 +205,32 @@ rebuild_record()
*/
for (cops = ops, i = 1; i <= NF; i++) {
NODE *r = fields_arr[i];
- if (r->stlen > 0) {
+ /*
+ * There is no reason to copy malloc'ed fields to point into
+ * the new $0 buffer, although that's how previous versions did
+ * it. It seems faster to leave the malloc'ed fields in place.
+ */
+ if (r->stlen > 0 && (r->flags & MALLOC) == 0) {
NODE *n;
getnode(n);
- if ((r->flags & FIELD) == 0) {
- *n = *Null_field;
- n->stlen = r->stlen;
- if ((r->flags & (NUMCUR|NUMBER)) != 0) {
- n->flags |= (r->flags & (MPFN|MPZN|NUMCUR|NUMBER));
-#ifdef HAVE_MPFR
- if (is_mpg_float(r)) {
- mpfr_init(n->mpg_numbr);
- mpfr_set(n->mpg_numbr, r->mpg_numbr, ROUND_MODE);
- } else if (is_mpg_integer(r)) {
- mpz_init(n->mpg_i);
- mpz_set(n->mpg_i, r->mpg_i);
- } else
-#endif
- n->numbr = r->numbr;
- }
- } else {
- *n = *r;
- n->flags &= ~(MALLOC|STRING);
+ *n = *r;
+ if (r->valref > 1) {
+ /*
+ * This probably never happens, since it
+ * was not considered by previous versions of
+ * this function. But it seems clear that
+ * we can't leave r's stptr pointing into the
+ * old $0 buffer that we are about to unref.
+ * It's not a priori obvious that valref must be
+ * 1 in all cases, so it seems wise to suppport
+ * this corner case. The only question is
+ * whether to add a warning message.
+ */
+ emalloc(r->stptr, char *, r->stlen + 1, "rebuild_record");
+ memcpy(r->stptr, cops, r->stlen);
+ r->stptr[r->stlen] = '\0';
+ r->flags |= MALLOC;
}
n->stptr = cops;
@@ -229,6 +241,10 @@ rebuild_record()
cops += fields_arr[i]->stlen + OFSlen;
}
+ assert((fields_arr[0]->flags & MALLOC) == 0
+ ? fields_arr[0]->valref == 1
+ : true);
+
unref(fields_arr[0]);
fields_arr[0] = tmp;
@@ -246,7 +262,7 @@ rebuild_record()
* but better correct than fast.
*/
void
-set_record(const char *buf, int cnt)
+set_record(const char *buf, int cnt, const awk_fieldwidth_info_t *fw)
{
NODE *n;
static char *databuf;
@@ -254,14 +270,12 @@ set_record(const char *buf, int cnt)
#define INITIAL_SIZE 512
#define MAX_SIZE ((unsigned long) ~0) /* maximally portable ... */
- reset_record();
+ purge_record();
/* buffer management: */
if (databuf_size == 0) { /* first time */
- emalloc(databuf, char *, INITIAL_SIZE, "set_record");
+ ezalloc(databuf, char *, INITIAL_SIZE, "set_record");
databuf_size = INITIAL_SIZE;
- memset(databuf, '\0', INITIAL_SIZE);
-
}
/*
* Make sure there's enough room. Since we sometimes need
@@ -269,8 +283,11 @@ set_record(const char *buf, int cnt)
* databuf_size is > cnt after allocation.
*/
if (cnt >= databuf_size) {
- while (cnt >= databuf_size && databuf_size <= MAX_SIZE)
+ do {
+ if (databuf_size > MAX_SIZE/2)
+ fatal(_("input record too large"));
databuf_size *= 2;
+ } while (cnt >= databuf_size);
erealloc(databuf, char *, databuf_size, "set_record");
memset(databuf, '\0', databuf_size);
}
@@ -278,21 +295,38 @@ set_record(const char *buf, int cnt)
memcpy(databuf, buf, cnt);
/*
- * Add terminating '\0' so that C library routines
+ * Add terminating '\0' so that C library routines
* will know when to stop.
*/
databuf[cnt] = '\0';
/* manage field 0: */
+ assert((fields_arr[0]->flags & MALLOC) == 0
+ ? fields_arr[0]->valref == 1
+ : true);
+
unref(fields_arr[0]);
getnode(n);
n->stptr = databuf;
n->stlen = cnt;
n->valref = 1;
n->type = Node_val;
- n->stfmt = -1;
- n->flags = (STRING|STRCUR|MAYBE_NUM|FIELD);
+ n->stfmt = STFMT_UNUSED;
+ n->flags = (STRING|STRCUR|USER_INPUT); /* do not set MALLOC */
fields_arr[0] = n;
+ if (fw != api_fw) {
+ if ((api_fw = fw) != NULL) {
+ if (! api_parser_override) {
+ api_parser_override = true;
+ parse_field = fw_parse_field;
+ update_PROCINFO_str("FS", "API");
+ }
+ } else if (api_parser_override) {
+ api_parser_override = false;
+ parse_field = normal_parse_field;
+ update_PROCINFO_str("FS", current_field_sep_str());
+ }
+ }
#undef INITIAL_SIZE
#undef MAX_SIZE
@@ -303,13 +337,21 @@ set_record(const char *buf, int cnt)
void
reset_record()
{
+ fields_arr[0] = force_string(fields_arr[0]);
+ purge_record();
+}
+
+static void
+purge_record()
+{
int i;
NODE *n;
- fields_arr[0] = force_string(fields_arr[0]);
-
NF = -1;
for (i = 1; i <= parse_high_water; i++) {
+ assert((fields_arr[i]->flags & MALLOC) == 0
+ ? fields_arr[i]->valref == 1
+ : true);
unref(fields_arr[i]);
getnode(n);
*n = *Null_field;
@@ -341,7 +383,7 @@ set_NF()
assert(NF != -1);
(void) force_number(NF_node->var_value);
- nf = get_number_si(NF_node->var_value);
+ nf = get_number_si(NF_node->var_value);
if (nf < 0)
fatal(_("NF set to negative value"));
NF = nf;
@@ -409,7 +451,7 @@ re_parse_field(long up_to, /* parse only up to this field number */
sep = scan;
while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
scan++;
- if (sep_arr != NULL && sep < scan)
+ if (sep_arr != NULL && sep < scan)
set_element(nf, sep, (long)(scan - sep), sep_arr);
}
@@ -441,8 +483,8 @@ re_parse_field(long up_to, /* parse only up to this field number */
}
(*set)(++nf, field,
(long)(scan + RESTART(rp, scan) - field), n);
- if (sep_arr != NULL)
- set_element(nf, scan + RESTART(rp, scan),
+ if (sep_arr != NULL)
+ set_element(nf, scan + RESTART(rp, scan),
(long) (REEND(rp, scan) - RESTART(rp, scan)), sep_arr);
scan += REEND(rp, scan);
field = scan;
@@ -506,7 +548,7 @@ def_parse_field(long up_to, /* parse only up to this field number */
sep = scan;
for (; nf < up_to; scan++) {
/*
- * special case: fs is single space, strip leading whitespace
+ * special case: fs is single space, strip leading whitespace
*/
while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
scan++;
@@ -538,75 +580,6 @@ def_parse_field(long up_to, /* parse only up to this field number */
}
/*
- * posix_def_parse_field --- default field parsing.
- *
- * This is called both from get_field() and from do_split()
- * via (*parse_field)(). This variation is for when FS is a single space
- * character. The only difference between this and def_parse_field()
- * is that this one does not allow newlines to separate fields.
- */
-
-static long
-posix_def_parse_field(long up_to, /* parse only up to this field number */
- char **buf, /* on input: string to parse; on output: point to start next */
- int len,
- NODE *fs,
- Regexp *rp ATTRIBUTE_UNUSED,
- Setfunc set, /* routine to set the value of the parsed field */
- NODE *n,
- NODE *dummy ATTRIBUTE_UNUSED, /* sep_arr not needed here: hence dummy */
- bool in_middle ATTRIBUTE_UNUSED)
-{
- char *scan = *buf;
- long nf = parse_high_water;
- char *field;
- char *end = scan + len;
- char sav;
-
- if (up_to == UNLIMITED)
- nf = 0;
- if (len == 0)
- return nf;
-
- /*
- * Nasty special case. If FS set to "", return whole record
- * as first field. This is not worth a separate function.
- */
- if (fs->stlen == 0) {
- (*set)(++nf, *buf, len, n);
- *buf += len;
- return nf;
- }
-
- /* before doing anything save the char at *end */
- sav = *end;
- /* because it will be destroyed now: */
-
- *end = ' '; /* sentinel character */
- for (; nf < up_to; scan++) {
- /*
- * special case: fs is single space, strip leading whitespace
- */
- while (scan < end && (*scan == ' ' || *scan == '\t'))
- scan++;
- if (scan >= end)
- break;
- field = scan;
- while (*scan != ' ' && *scan != '\t')
- scan++;
- (*set)(++nf, field, (long)(scan - field), n);
- if (scan == end)
- break;
- }
-
- /* everything done, restore original char at *end */
- *end = sav;
-
- *buf = scan;
- return nf;
-}
-
-/*
* null_parse_field --- each character is a separate field
*
* This is called both from get_field() and from do_split()
@@ -739,6 +712,31 @@ sc_parse_field(long up_to, /* parse only up to this field number */
}
/*
+ * calc_mbslen --- calculate the length in bytes of a multi-byte string
+ * containing len characters.
+ */
+
+static size_t
+calc_mbslen(char *scan, char *end, size_t len, mbstate_t *mbs)
+{
+
+ size_t mbclen;
+ char *mbscan = scan;
+
+ while (len-- > 0 && mbscan < end) {
+ mbclen = mbrlen(mbscan, end - mbscan, mbs);
+ if (!(mbclen > 0 && mbclen <= (size_t)(end - mbscan)))
+ /*
+ * We treat it as a singlebyte character. This should
+ * catch error codes 0, (size_t) -1, and (size_t) -2.
+ */
+ mbclen = 1;
+ mbscan += mbclen;
+ }
+ return mbscan - scan;
+}
+
+/*
* fw_parse_field --- field parsing using FIELDWIDTHS spec
*
* This is called from get_field() via (*parse_field)().
@@ -758,53 +756,53 @@ fw_parse_field(long up_to, /* parse only up to this field number */
char *scan = *buf;
long nf = parse_high_water;
char *end = scan + len;
- int nmbc;
- size_t mbclen;
- size_t mbslen;
- size_t lenrest;
- char *mbscan;
+ const awk_fieldwidth_info_t *fw;
mbstate_t mbs;
+ size_t skiplen;
+ size_t flen;
- memset(&mbs, 0, sizeof(mbstate_t));
+ fw = (api_parser_override ? api_fw : FIELDWIDTHS);
if (up_to == UNLIMITED)
nf = 0;
if (len == 0)
return nf;
- for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
- if (gawk_mb_cur_max > 1) {
- nmbc = 0;
- mbslen = 0;
- mbscan = scan;
- lenrest = end - scan;
- while (nmbc < len && mbslen < lenrest) {
- mbclen = mbrlen(mbscan, end - mbscan, &mbs);
- if ( mbclen == 1
- || mbclen == (size_t) -1
- || mbclen == (size_t) -2
- || mbclen == 0) {
- /* We treat it as a singlebyte character. */
- mbclen = 1;
- }
- if (mbclen <= end - mbscan) {
- mbscan += mbclen;
- mbslen += mbclen;
- ++nmbc;
- }
- }
- (*set)(++nf, scan, (long) mbslen, n);
- scan += mbslen;
- } else {
- if (len > end - scan)
- len = end - scan;
- (*set)(++nf, scan, (long) len, n);
- scan += len;
+ if (gawk_mb_cur_max > 1 && fw->use_chars) {
+ /*
+ * Reset the shift state. Arguably, the shift state should
+ * be part of the file state and carried forward at all times,
+ * but nobody has complained so far, so this may not matter
+ * in practice.
+ */
+ memset(&mbs, 0, sizeof(mbstate_t));
+ while (nf < up_to && scan < end) {
+ if (nf >= fw->nf) {
+ *buf = end;
+ return nf;
+ }
+ scan += calc_mbslen(scan, end, fw->fields[nf].skip, &mbs);
+ flen = calc_mbslen(scan, end, fw->fields[nf].len, &mbs);
+ (*set)(++nf, scan, (long) flen, n);
+ scan += flen;
+ }
+ } else {
+ while (nf < up_to && scan < end) {
+ if (nf >= fw->nf) {
+ *buf = end;
+ return nf;
+ }
+ skiplen = fw->fields[nf].skip;
+ if (skiplen > end - scan)
+ skiplen = end - scan;
+ scan += skiplen;
+ flen = fw->fields[nf].len;
+ if (flen > end - scan)
+ flen = end - scan;
+ (*set)(++nf, scan, (long) flen, n);
+ scan += flen;
}
}
- if (len == -1)
- *buf = end;
- else
- *buf = scan;
+ *buf = scan;
return nf;
}
@@ -857,11 +855,11 @@ get_field(long requested, Func_ptr *assign)
/*
* Keep things uniform. Also, mere intention of assigning something
* to $n should not make $0 invalid. Makes sense to invalidate $0
- * after the actual assignment is performed. Not a real issue in
+ * after the actual assignment is performed. Not a real issue in
* the interpreter otherwise, but causes problem in the
* debugger when watching or printing fields.
*/
-
+
if (assign != NULL)
*assign = invalidate_field0; /* $0 needs reconstruction */
#endif
@@ -893,7 +891,7 @@ get_field(long requested, Func_ptr *assign)
if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
NF = parse_high_water;
else if (parse_field == fpat_parse_field) {
- /* FPAT parsing is wierd, isolate the special cases */
+ /* FPAT parsing is weird, isolate the special cases */
char *rec_start = fields_arr[0]->stptr;
char *rec_end = fields_arr[0]->stptr + fields_arr[0]->stlen;
@@ -930,7 +928,7 @@ set_element(long num, char *s, long len, NODE *n)
NODE *sub;
it = make_string(s, len);
- it->flags |= MAYBE_NUM;
+ it->flags |= USER_INPUT;
sub = make_number((AWKNUM) (num));
lhs = assoc_lookup(n, sub);
unref(*lhs);
@@ -977,12 +975,12 @@ do_split(int nargs)
if (sep_arr != NULL) {
if (sep_arr == arr)
- fatal(_("split: cannot use the same array for second and fourth args"));
+ fatal(_("split: cannot use the same array for second and fourth args"));
/* This checks need to be done before clearing any of the arrays */
for (tmp = sep_arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
if (tmp == arr)
- fatal(_("split: cannot use a subarray of second arg for fourth arg"));
+ fatal(_("split: cannot use a subarray of second arg for fourth arg"));
for (tmp = arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
if (tmp == sep_arr)
fatal(_("split: cannot use a subarray of fourth arg for second arg"));
@@ -1000,6 +998,9 @@ do_split(int nargs)
return make_number((AWKNUM) 0);
}
+ if ((sep->flags & REGEX) != 0)
+ sep = sep->typed_re;
+
if ( (sep->re_flags & FS_DFLT) != 0
&& current_field_sep() == Using_FS
&& ! RS_is_null) {
@@ -1020,10 +1021,7 @@ do_split(int nargs)
}
} else if (fs->stlen == 1 && (sep->re_flags & CONSTANT) == 0) {
if (fs->stptr[0] == ' ') {
- if (do_posix)
- parseit = posix_def_parse_field;
- else
- parseit = def_parse_field;
+ parseit = def_parse_field;
} else
parseit = sc_parse_field;
} else {
@@ -1065,13 +1063,16 @@ do_patsplit(int nargs)
src = TOP_STRING();
+ if ((sep->flags & REGEX) != 0)
+ sep = sep->typed_re;
+
fpat = sep->re_exp;
if (fpat->stlen == 0)
fatal(_("patsplit: third argument must be non-null"));
if (sep_arr != NULL) {
if (sep_arr == arr)
- fatal(_("patsplit: cannot use the same array for second and fourth args"));
+ fatal(_("patsplit: cannot use the same array for second and fourth args"));
/* These checks need to be done before clearing any of the arrays */
for (tmp = sep_arr->parent_array; tmp != NULL; tmp = tmp->parent_array)
@@ -1102,6 +1103,18 @@ do_patsplit(int nargs)
return tmp;
}
+/* set_parser --- update the current (non-API) parser */
+
+static void
+set_parser(parse_field_func_t func)
+{
+ normal_parse_field = func;
+ if (! api_parser_override && parse_field != func) {
+ parse_field = func;
+ update_PROCINFO_str("FS", current_field_sep_str());
+ }
+}
+
/* set_FIELDWIDTHS --- handle an assignment to FIELDWIDTHS */
void
@@ -1123,27 +1136,27 @@ set_FIELDWIDTHS()
return;
/*
- * If changing the way fields are split, obey least-suprise
+ * If changing the way fields are split, obey least-surprise
* semantics, and force $0 to be split totally.
*/
if (fields_arr != NULL)
(void) get_field(UNLIMITED - 1, 0);
- parse_field = fw_parse_field;
+ set_parser(fw_parse_field);
tmp = force_string(FIELDWIDTHS_node->var_value);
scan = tmp->stptr;
- if (FIELDWIDTHS == NULL)
- emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
- FIELDWIDTHS[0] = 0;
- for (i = 1; ; i++) {
+ if (FIELDWIDTHS == NULL) {
+ emalloc(FIELDWIDTHS, awk_fieldwidth_info_t *, awk_fieldwidth_info_size(fw_alloc), "set_FIELDWIDTHS");
+ FIELDWIDTHS->use_chars = awk_true;
+ }
+ FIELDWIDTHS->nf = 0;
+ for (i = 0; ; i++) {
unsigned long int tmp;
- if (i + 2 >= fw_alloc) {
+ if (i >= fw_alloc) {
fw_alloc *= 2;
- erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
+ erealloc(FIELDWIDTHS, awk_fieldwidth_info_t *, awk_fieldwidth_info_size(fw_alloc), "set_FIELDWIDTHS");
}
- /* Initialize value to be end of list */
- FIELDWIDTHS[i] = -1;
/* Ensure that there is no leading `-' sign. Otherwise,
strtoul would accept it and return a bogus result. */
while (is_blank(*scan)) {
@@ -1156,19 +1169,47 @@ set_FIELDWIDTHS()
if (*scan == '\0')
break;
- /* Detect an invalid base-10 integer, a valid value that
- is followed by something other than a blank or '\0',
- or a value that is not in the range [1..INT_MAX]. */
+ // Look for skip value. We allow N:M and N:*.
+ /*
+ * Detect an invalid base-10 integer, a valid value that
+ * is followed by something other than a blank or '\0',
+ * or a value that is not in the range [1..UINT_MAX].
+ */
errno = 0;
tmp = strtoul(scan, &end, 10);
+ if (errno == 0 && *end == ':' && (0 < tmp && tmp <= UINT_MAX)) {
+ FIELDWIDTHS->fields[i].skip = tmp;
+ scan = end + 1;
+ if (*scan == '-' || is_blank(*scan)) {
+ fatal_error = true;
+ break;
+ }
+ // try scanning for field width
+ tmp = strtoul(scan, &end, 10);
+ }
+ else
+ FIELDWIDTHS->fields[i].skip = 0;
+
if (errno != 0
|| (*end != '\0' && ! is_blank(*end))
- || !(0 < tmp && tmp <= INT_MAX)
+ || !(0 < tmp && tmp <= UINT_MAX)
) {
- fatal_error = true;
+ if (*scan == '*') {
+ for (scan++; is_blank(*scan); scan++)
+ continue;
+
+ if (*scan != '\0')
+ fatal(_("`*' must be the last designator in FIELDWIDTHS"));
+
+ FIELDWIDTHS->fields[i].len = UINT_MAX;
+ FIELDWIDTHS->nf = i+1;
+ }
+ else
+ fatal_error = true;
break;
}
- FIELDWIDTHS[i] = tmp;
+ FIELDWIDTHS->fields[i].len = tmp;
+ FIELDWIDTHS->nf = i+1;
scan = end;
/* Skip past any trailing blanks. */
while (is_blank(*scan)) {
@@ -1177,12 +1218,10 @@ set_FIELDWIDTHS()
if (*scan == '\0')
break;
}
- FIELDWIDTHS[i+1] = -1;
- update_PROCINFO_str("FS", "FIELDWIDTHS");
if (fatal_error)
- fatal(_("invalid FIELDWIDTHS value, near `%s'"),
- scan);
+ fatal(_("invalid FIELDWIDTHS value, for field %d, near `%s'"),
+ i + 1, scan);
}
/* set_FS --- handle things when FS is assigned to */
@@ -1236,7 +1275,7 @@ set_FS()
* FS_regexp will be NULL with a non-null FS_re_yes_case.
* refree() handles null argument; no need for `if (FS_regexp != NULL)' below.
* Please do not remerge.
- */
+ */
refree(FS_re_yes_case);
refree(FS_re_no_case);
FS_re_yes_case = FS_re_no_case = FS_regexp = NULL;
@@ -1250,7 +1289,7 @@ choose_fs_function:
if (! do_traditional && fs->stlen == 0) {
static bool warned = false;
- parse_field = null_parse_field;
+ set_parser(null_parse_field);
if (do_lint && ! warned) {
warned = true;
@@ -1259,10 +1298,10 @@ choose_fs_function:
} else if (fs->stlen > 1) {
if (do_lint_old)
warning(_("old awk does not support regexps as value of `FS'"));
- parse_field = re_parse_field;
+ set_parser(re_parse_field);
} else if (RS_is_null) {
/* we know that fs->stlen <= 1 */
- parse_field = sc_parse_field;
+ set_parser(sc_parse_field);
if (fs->stlen == 1) {
if (fs->stptr[0] == ' ') {
default_FS = true;
@@ -1278,10 +1317,7 @@ choose_fs_function:
}
}
} else {
- if (do_posix)
- parse_field = posix_def_parse_field;
- else
- parse_field = def_parse_field;
+ set_parser(def_parse_field);
if (fs->stlen == 1) {
if (fs->stptr[0] == ' ')
@@ -1290,7 +1326,7 @@ choose_fs_function:
/* same special case */
strcpy(buf, "[\\\\]");
else
- parse_field = sc_parse_field;
+ set_parser(sc_parse_field);
}
}
if (remake_re) {
@@ -1302,7 +1338,7 @@ choose_fs_function:
FS_re_yes_case = make_regexp(buf, strlen(buf), false, true, true);
FS_re_no_case = make_regexp(buf, strlen(buf), true, true, true);
FS_regexp = (IGNORECASE ? FS_re_no_case : FS_re_yes_case);
- parse_field = re_parse_field;
+ set_parser(re_parse_field);
} else if (parse_field == re_parse_field) {
FS_re_yes_case = make_regexp(fs->stptr, fs->stlen, false, true, true);
FS_re_no_case = make_regexp(fs->stptr, fs->stlen, true, true, true);
@@ -1318,16 +1354,16 @@ choose_fs_function:
*/
if (fs->stlen == 1 && parse_field == re_parse_field)
FS_regexp = FS_re_yes_case;
-
- update_PROCINFO_str("FS", "FS");
}
-/* current_field_sep --- return what field separator is */
+/* current_field_sep --- return the field separator type */
field_sep_type
current_field_sep()
{
- if (parse_field == fw_parse_field)
+ if (api_parser_override)
+ return Using_API;
+ else if (parse_field == fw_parse_field)
return Using_FIELDWIDTHS;
else if (parse_field == fpat_parse_field)
return Using_FPAT;
@@ -1335,6 +1371,21 @@ current_field_sep()
return Using_FS;
}
+/* current_field_sep_str --- return the field separator type as a string */
+
+const char *
+current_field_sep_str()
+{
+ if (api_parser_override)
+ return "API";
+ else if (parse_field == fw_parse_field)
+ return "FIELDWIDTHS";
+ else if (parse_field == fpat_parse_field)
+ return "FPAT";
+ else
+ return "FS";
+}
+
/* update_PROCINFO_str --- update PROCINFO[sub] with string value */
void
@@ -1421,7 +1472,7 @@ set_FPAT()
set_fpat_function:
fpat = force_string(FPAT_node->var_value);
- parse_field = fpat_parse_field;
+ set_parser(fpat_parse_field);
if (remake_re) {
refree(FPAT_re_yes_case);
@@ -1432,8 +1483,6 @@ set_fpat_function:
FPAT_re_no_case = make_regexp(fpat->stptr, fpat->stlen, true, true, true);
FPAT_regexp = (IGNORECASE ? FPAT_re_no_case : FPAT_re_yes_case);
}
-
- update_PROCINFO_str("FS", "FPAT");
}
/*
@@ -1471,101 +1520,65 @@ incr_scan(char **scanp, size_t len, mbstate_t *mbs)
* via (*parse_field)(). This variation is for when FPAT is a regular
* expression -- use the value to find field contents.
*
- * This was really hard to get right. It happens to bear many resemblances
- * to issues I had with getting gsub right with null matches. When dealing
- * with that I prototyped in awk and had the foresight to save the awk code
- * over in the C file. Starting with that as a base, I finally got to this
- * awk code to do what I needed, and then translated it into C. Fortunately
- * the C code bears a closer correspondance to the awk code here than over
- * by gsub.
+ * The FPAT parsing logic is a bit difficult to specify. In particular
+ * to allow null fields at certain locations. To make the code as robust
+ * as possible, an awk reference implementation was written and tested
+ * as a first step, and later recoded in C, preserving its structure as
+ * much as possible.
*
- * BEGIN {
- * false = 0
- * true = 1
- *
- * fpat[1] = "([^,]*)|(\"[^\"]+\")"
- * fpat[2] = fpat[1]
- * fpat[3] = fpat[1]
- * fpat[4] = "aa+"
- * fpat[5] = fpat[4]
- *
- * data[1] = "Robbins,,Arnold,"
- * data[2] = "Smith,,\"1234 A Pretty Place, NE\",Sometown,NY,12345-6789,USA"
- * data[3] = "Robbins,Arnold,\"1234 A Pretty Place, NE\",Sometown,NY,12345-6789,USA"
- * data[4] = "bbbaaacccdddaaaaaqqqq"
- * data[5] = "bbbaaacccdddaaaaaqqqqa" # should get trailing qqqa
+ * # Reference implementation of the FPAT record parsing.
+ * #
+ * # Each loop iteration identifies a (separator[n-1],field[n]) pair.
+ * # Each loop iteration must consume some characters, except for the first field.
+ * # So a null field is only valid as a first field or after a non-null separator.
+ * # A null record has no fields (not a single null field).
*
- * for (i = 1; i in data; i++) {
- * printf("Splitting: <%s>\n", data[i])
- * n = mypatsplit(data[i], fields, fpat[i], seps)
- * print "n =", n
- * for (j = 1; j <= n; j++)
- * printf("fields[%d] = <%s>\n", j, fields[j])
- * for (j = 0; j in seps; j++)
- * printf("seps[%s] = <%s>\n", j, seps[j])
- * }
- * }
- *
- * function mypatsplit(string, array, pattern, seps,
- * eosflag, non_empty, nf) # locals
+ * function refpatsplit(string, fields, pattern, seps,
+ * parse_start, sep_start, field_start, field_length, field_found, nf) # locals
* {
- * delete array
- * delete seps
- * if (length(string) == 0)
- * return 0
- *
- * eosflag = non_empty = false
- * nf = 0
- * while (match(string, pattern)) {
- * if (RLENGTH > 0) { # easy case
- * non_empty = true
- * if (! (nf in seps)) {
- * if (RSTART == 1) # match at front of string
- * seps[nf] = ""
- * else
- * seps[nf] = substr(string, 1, RSTART - 1)
- * }
- * array[++nf] = substr(string, RSTART, RLENGTH)
- * string = substr(string, RSTART+RLENGTH)
- * if (length(string) == 0)
- * break
- * } else if (non_empty) {
- * # last match was non-empty, and at the
- * # current character we get a zero length match,
- * # which we don't want, so skip over it
- * non_empty = false
- * seps[nf] = substr(string, 1, 1)
- * string = substr(string, 2)
- * } else {
- * # 0 length match
- * if (! (nf in seps)) {
- * if (RSTART == 1)
- * seps[nf] = ""
- * else
- * seps[nf] = substr(string, 1, RSTART - 1)
- * }
- * array[++nf] = ""
- * if (! non_empty && ! eosflag) { # prev was empty
- * seps[nf] = substr(string, 1, 1)
- * }
- * if (RSTART == 1) {
- * string = substr(string, 2)
- * } else {
- * string = substr(string, RSTART + 1)
- * }
- * non_empty = false
- * }
- * if (length(string) == 0) {
- * if (eosflag)
- * break
- * else
- * eosflag = true
- * }
- * }
- * if (length(string) > 0)
- * seps[nf] = string
+ * # Local state variables:
+ * # - parse_start: pointer to the first not yet consumed character
+ * # - sep_start: pointer to the beginning of the parsed separator
+ * # - field start: pointer to the beginning of the parsed field
+ * # - field length: length of the parsed field
+ * # - field_found: flag for succesful field match
+ * # - nf: Number of fields found so far
+ *
+ * # Prepare for parsing
+ * parse_start = 1 # first not yet parsed char
+ * nf = 0 # fields found so far
+ * delete fields
+ * delete seps
*
- * return length(array)
+ * # Loop that consumes the whole record
+ * while (parse_start <= length(string)) { # still something to parse
+ *
+ * # first attempt to match the next field
+ * sep_start = parse_start
+ * field_found = match(substr(string, parse_start), pattern)
+ *
+ * # check for an invalid null field and retry one character away
+ * if (nf > 0 && field_found && RSTART==1 && RLENGTH==0) {
+ * parse_start++
+ * field_found = match(substr(string, parse_start), pattern)
+ * }
+ *
+ * # store the (sep[n-1],field[n]) pair
+ * if (field_found) {
+ * field_start = parse_start + RSTART - 1
+ * field_length = RLENGTH
+ * seps[nf] = substr(string, sep_start, field_start-sep_start)
+ * fields[++nf] = substr(string, field_start, field_length)
+ * parse_start = field_start + field_length
+ *
+ * # store the final extra sep after the last field
+ * } else {
+ * seps[nf] = substr(string, sep_start)
+ * parse_start = length(string) + 1
+ * }
+ * }
+ *
+ * return nf
* }
*/
static long
@@ -1584,10 +1597,9 @@ fpat_parse_field(long up_to, /* parse only up to this field number */
char *start;
char *end = scan + len;
int regex_flags = RE_NEED_START;
- bool need_to_set_sep;
- bool non_empty;
- bool eosflag;
mbstate_t mbs;
+ char* field_start;
+ bool field_found = false;
memset(&mbs, 0, sizeof(mbstate_t));
@@ -1600,90 +1612,55 @@ fpat_parse_field(long up_to, /* parse only up to this field number */
if (rp == NULL) /* use FPAT */
rp = FPAT_regexp;
- if (in_middle) {
- regex_flags |= RE_NO_BOL;
- }
- non_empty = rp->non_empty;
+ while (scan < end && nf < up_to) { /* still something to parse */
- eosflag = false;
- need_to_set_sep = true;
- start = scan;
- while (research(rp, scan, 0, (end - scan), regex_flags) != -1
- && nf < up_to) {
+ /* first attempt to match the next field */
+ start = scan;
+ field_found = research(rp, scan, 0, (end - scan), regex_flags) != -1;
- if (REEND(rp, scan) > RESTART(rp, scan)) { /* if (RLENGTH > 0) */
- non_empty = true;
- if (sep_arr != NULL && need_to_set_sep) {
- if (RESTART(rp, scan) == 0) /* match at front */
- set_element(nf, start, 0L, sep_arr);
+ /* check for an invalid null field and retry one character away */
+ if (nf > 0 && field_found && REEND(rp, scan) == 0) { /* invalid null field */
+ increment_scan(& scan, end - scan);
+ field_found = research(rp, scan, 0, (end - scan), regex_flags) != -1;
+ }
+
+ /* store the (sep[n-1],field[n]) pair */
+ if (field_found) {
+ field_start = scan + RESTART(rp, scan);
+ if (sep_arr != NULL) { /* store the separator */
+ if (field_start == start) /* match at front */
+ set_element(nf, start, 0L, sep_arr);
else
- set_element(nf,
+ set_element(nf,
start,
- (long) RESTART(rp, scan),
+ (long) (field_start - start),
sep_arr);
}
/* field is text that matched */
(*set)(++nf,
- scan + RESTART(rp, scan),
+ field_start,
(long)(REEND(rp, scan) - RESTART(rp, scan)),
n);
-
scan += REEND(rp, scan);
- if (scan >= end)
- break;
- need_to_set_sep = true;
- } else if (non_empty) { /* else if non_empty */
- /*
- * last match was non-empty, and at the
- * current character we get a zero length match,
- * which we don't want, so skip over it
- */
- non_empty = false;
- if (sep_arr != NULL) {
- need_to_set_sep = false;
- set_element(nf, start, 1L, sep_arr);
- }
- increment_scan(& scan, end - scan);
+
} else {
- /* 0 length match */
- if (sep_arr != NULL && need_to_set_sep) {
- if (RESTART(rp, scan) == 0) /* RSTART == 1 */
- set_element(nf, start, 0L, sep_arr);
- else
- set_element(nf, start,
- (long) RESTART(rp, scan),
- sep_arr);
- }
- need_to_set_sep = true;
- (*set)(++nf, scan, 0L, n);
- if (! non_empty && ! eosflag) { /* prev was empty */
- if (sep_arr != NULL) {
- set_element(nf, start, 1L, sep_arr);
- need_to_set_sep = false;
- }
- }
- if (RESTART(rp, scan) == 0)
- increment_scan(& scan, end - scan);
- else {
- scan += RESTART(rp, scan);
- }
- non_empty = false;
- }
- if (scan >= end) { /* length(string) == 0 */
- if (eosflag)
- break;
- else
- eosflag = true;
+ /*
+ * No match, store the final extra separator after
+ * the last field.
+ */
+ if (sep_arr != NULL)
+ set_element(nf, start, (long) (end - start), sep_arr);
+ scan = end;
}
-
- start = scan;
- }
- if (scan < end) {
- if (sep_arr != NULL)
- set_element(nf, scan, (long) (end - scan), sep_arr);
}
+ /*
+ * If the last field extends up to the end of the record, generate
+ * a null trailing separator
+ */
+ if (sep_arr != NULL && scan == end && field_found)
+ set_element(nf, scan, 0L, sep_arr);
+
*buf = scan;
- rp->non_empty = non_empty;
return nf;
}
diff --git a/floatcomp.c b/floatcomp.c
index 9ba169a4..7317fa75 100644
--- a/floatcomp.c
+++ b/floatcomp.c
@@ -2,23 +2,23 @@
* floatcomp.c - Isolate floating point details.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2011, 2016
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
diff --git a/floatmagic.h b/floatmagic.h
index c6aabd92..cb22b611 100644
--- a/floatmagic.h
+++ b/floatmagic.h
@@ -1,23 +1,23 @@
/*
- * floatmagic.h -- Definitions of isnan and isinf for gawk.
+ * floatmagic.h -- Definitions of isnan and isinf for gawk.
*/
-/*
+/*
* Copyright (C) 2009 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
diff --git a/gawkapi.c b/gawkapi.c
index 1ef2f79e..bb6b7d5c 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -2,22 +2,22 @@
* gawkapi.c -- Implement the functions defined for gawkapi.h
*/
-/*
+/*
* Copyright (C) 2012-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -25,7 +25,13 @@
#include "awk.h"
+/* Declare some globals used by api_get_file: */
+extern IOBUF *curfile;
+extern INSTRUCTION *main_beginfile;
+extern int currule;
+
static awk_bool_t node_to_awk_value(NODE *node, awk_value_t *result, awk_valtype_t wanted);
+static char *valtype2str(awk_valtype_t type);
/*
* api_get_argument --- get the count'th paramater, zero-based.
@@ -71,7 +77,7 @@ api_get_argument(awk_ext_id_t id, size_t count,
goto scalar;
}
}
-
+
/* at this point, we have real type */
if (arg->type == Node_var_array || arg->type == Node_array_ref) {
if (wanted != AWK_ARRAY && wanted != AWK_UNDEFINED)
@@ -159,6 +165,15 @@ awk_value_to_node(const awk_value_t *retval)
ext_ret_val = make_str_node(retval->str_value.str,
retval->str_value.len, ALREADY_MALLOCED);
break;
+ case AWK_STRNUM:
+ ext_ret_val = make_str_node(retval->str_value.str,
+ retval->str_value.len, ALREADY_MALLOCED);
+ ext_ret_val->flags |= USER_INPUT;
+ break;
+ case AWK_REGEX:
+ ext_ret_val = make_typed_regex(retval->str_value.str,
+ retval->str_value.len);
+ break;
case AWK_SCALAR:
v = (NODE *) retval->scalar_cookie;
if (v->type != Node_var)
@@ -193,6 +208,20 @@ api_fatal(awk_ext_id_t id, const char *format, ...)
va_end(args);
}
+/* api_nonfatal --- print a non fatal error message */
+
+static void
+api_nonfatal(awk_ext_id_t id, const char *format, ...)
+{
+ va_list args;
+
+ (void) id;
+
+ va_start(args, format);
+ err(false, _("error: "), format, args);
+ va_end(args);
+}
+
/* api_warning --- print a warning message */
static void
@@ -238,7 +267,7 @@ api_register_input_parser(awk_ext_id_t id, awk_input_parser_t *input_parser)
register_input_parser(input_parser);
}
-/* api_register_output_wrapper --- egister an output wrapper, for writing files / two-way pipes */
+/* api_register_output_wrapper --- register an output wrapper, for writing files / two-way pipes */
static void api_register_output_wrapper(awk_ext_id_t id,
awk_output_wrapper_t *output_wrapper)
@@ -307,7 +336,7 @@ api_unset_ERRNO(awk_ext_id_t id)
static awk_bool_t
api_add_ext_func(awk_ext_id_t id,
const char *namespace,
- const awk_ext_func_t *func)
+ awk_ext_func_t *func)
{
(void) id;
(void) namespace;
@@ -372,6 +401,68 @@ api_awk_atexit(awk_ext_id_t id,
list_head = p;
}
+static struct {
+ char **strings;
+ size_t i, size;
+} scopy;
+
+/* free_api_string_copies --- release memory used by string copies */
+
+void
+free_api_string_copies()
+{
+ size_t i;
+
+ for (i = 0; i < scopy.i; i++)
+ free(scopy.strings[i]);
+ scopy.i = 0;
+}
+
+/* assign_string --- return a string node with NUL termination */
+
+static inline void
+assign_string(NODE *node, awk_value_t *val, awk_valtype_t val_type)
+{
+ val->val_type = val_type;
+ if (node->stptr[node->stlen] != '\0') {
+ /*
+ * This is an unterminated field string, so make a copy.
+ * This should happen only for $n where n > 0 and n < NF.
+ */
+ char *s;
+
+ assert((node->flags & MALLOC) == 0);
+ if (scopy.i == scopy.size) {
+ /* expand list */
+ if (scopy.size == 0)
+ scopy.size = 8; /* initial size */
+ else
+ scopy.size *= 2;
+ erealloc(scopy.strings, char **, scopy.size * sizeof(char *), "assign_string");
+ }
+ emalloc(s, char *, node->stlen + 1, "assign_string");
+ memcpy(s, node->stptr, node->stlen);
+ s[node->stlen] = '\0';
+ val->str_value.str = scopy.strings[scopy.i++] = s;
+ }
+ else
+ val->str_value.str = node->stptr;
+ val->str_value.len = node->stlen;
+}
+
+/* assign_regex --- return a regex node */
+
+static inline void
+assign_regex(NODE *node, awk_value_t *val)
+{
+ /* a REGEX node cannot be an unterminated field string */
+ assert((node->flags & MALLOC) != 0);
+ assert(node->stptr[node->stlen] == '\0');
+ val->str_value.str = node->stptr;
+ val->str_value.len = node->stlen;
+ val->val_type = AWK_REGEX;
+}
+
/* node_to_awk_value --- convert a node into a value for an extension */
static awk_bool_t
@@ -408,52 +499,137 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted)
/* a scalar value */
switch (wanted) {
case AWK_NUMBER:
- val->val_type = AWK_NUMBER;
-
- (void) force_number(node);
- if ((node->flags & NUMCUR) != 0) {
+ if (node->flags & REGEX)
+ val->val_type = AWK_REGEX;
+ else {
+ val->val_type = AWK_NUMBER;
+ (void) force_number(node);
val->num_value = get_number_d(node);
ret = awk_true;
}
break;
- case AWK_STRING:
- val->val_type = AWK_STRING;
+ case AWK_STRNUM:
+ switch (fixtype(node)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) {
+ case STRING:
+ val->val_type = AWK_STRING;
+ break;
+ case NUMBER:
+ (void) force_string(node);
+ /* fall through */
+ case NUMBER|USER_INPUT:
+ assign_string(node, val, AWK_STRNUM);
+ ret = awk_true;
+ break;
+ case REGEX:
+ val->val_type = AWK_REGEX;
+ break;
+ case NUMBER|STRING:
+ if (node == Nnull_string) {
+ val->val_type = AWK_UNDEFINED;
+ break;
+ }
+ /* fall through */
+ default:
+ warning(_("node_to_awk_value detected invalid flags combination `%s'; please file a bug report."), flags2str(node->flags));
+ val->val_type = AWK_UNDEFINED;
+ break;
+ }
+ break;
+ case AWK_STRING:
(void) force_string(node);
- if ((node->flags & STRCUR) != 0) {
- val->str_value.str = node->stptr;
- val->str_value.len = node->stlen;
+ assign_string(node, val, AWK_STRING);
+ ret = awk_true;
+ break;
+
+ case AWK_REGEX:
+ switch (fixtype(node)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) {
+ case STRING:
+ val->val_type = AWK_STRING;
+ break;
+ case NUMBER:
+ val->val_type = AWK_NUMBER;
+ break;
+ case NUMBER|USER_INPUT:
+ val->val_type = AWK_STRNUM;
+ break;
+ case REGEX:
+ assign_regex(node, val);
ret = awk_true;
+ break;
+ case NUMBER|STRING:
+ if (node == Nnull_string) {
+ val->val_type = AWK_UNDEFINED;
+ break;
+ }
+ /* fall through */
+ default:
+ warning(_("node_to_awk_value detected invalid flags combination `%s'; please file a bug report."), flags2str(node->flags));
+ val->val_type = AWK_UNDEFINED;
+ break;
}
break;
case AWK_SCALAR:
- if ((node->flags & NUMBER) != 0) {
- val->val_type = AWK_NUMBER;
- } else if ((node->flags & STRING) != 0) {
+ switch (fixtype(node)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) {
+ case STRING:
val->val_type = AWK_STRING;
- } else
+ break;
+ case NUMBER:
+ val->val_type = AWK_NUMBER;
+ break;
+ case NUMBER|USER_INPUT:
+ val->val_type = AWK_STRNUM;
+ break;
+ case REGEX:
+ val->val_type = AWK_REGEX;
+ break;
+ case NUMBER|STRING:
+ if (node == Nnull_string) {
+ val->val_type = AWK_UNDEFINED;
+ break;
+ }
+ /* fall through */
+ default:
+ warning(_("node_to_awk_value detected invalid flags combination `%s'; please file a bug report."), flags2str(node->flags));
val->val_type = AWK_UNDEFINED;
- ret = awk_false;
+ break;
+ }
break;
case AWK_UNDEFINED:
/* return true and actual type for request of undefined */
- if (node == Nnull_string) {
- val->val_type = AWK_UNDEFINED;
+ switch (fixtype(node)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) {
+ case STRING:
+ assign_string(node, val, AWK_STRING);
ret = awk_true;
- } else if ((node->flags & NUMBER) != 0) {
+ break;
+ case NUMBER:
val->val_type = AWK_NUMBER;
val->num_value = get_number_d(node);
ret = awk_true;
- } else if ((node->flags & STRING) != 0) {
- val->val_type = AWK_STRING;
- val->str_value.str = node->stptr;
- val->str_value.len = node->stlen;
+ break;
+ case NUMBER|USER_INPUT:
+ assign_string(node, val, AWK_STRNUM);
ret = awk_true;
- } else
+ break;
+ case REGEX:
+ assign_regex(node, val);
+ ret = awk_true;
+ break;
+ case NUMBER|STRING:
+ if (node == Nnull_string) {
+ val->val_type = AWK_UNDEFINED;
+ ret = awk_true;
+ break;
+ }
+ /* fall through */
+ default:
+ warning(_("node_to_awk_value detected invalid flags combination `%s'; please file a bug report."), flags2str(node->flags));
val->val_type = AWK_UNDEFINED;
+ break;
+ }
break;
case AWK_ARRAY:
@@ -485,7 +661,7 @@ node_to_awk_value(NODE *node, awk_value_t *val, awk_valtype_t wanted)
* - No access to special variables (NF, etc.)
* - One special exception: PROCINFO.
* - Use sym_update() to change a value, including from UNDEFINED
- * to scalar or array.
+ * to scalar or array.
*/
/*
* Lookup a variable, fills in value. No messing with the value
@@ -556,7 +732,9 @@ api_sym_update(awk_ext_id_t id,
switch (value->val_type) {
case AWK_NUMBER:
+ case AWK_STRNUM:
case AWK_STRING:
+ case AWK_REGEX:
case AWK_UNDEFINED:
case AWK_ARRAY:
case AWK_SCALAR:
@@ -654,7 +832,9 @@ api_sym_update_scalar(awk_ext_id_t id,
return awk_true;
}
break;
+
case AWK_STRING:
+ case AWK_STRNUM:
if (node->var_value->valref == 1) {
NODE *r = node->var_value;
@@ -668,17 +848,22 @@ api_sym_update_scalar(awk_ext_id_t id,
/* make_str_node(s, l, ALREADY_MALLOCED): */
r->numbr = 0;
r->flags = (MALLOC|STRING|STRCUR);
- r->stfmt = -1;
+ if (value->val_type == AWK_STRNUM)
+ r->flags |= USER_INPUT;
+ r->stfmt = STFMT_UNUSED;
r->stptr = value->str_value.str;
r->stlen = value->str_value.len;
return awk_true;
}
break;
+
+ case AWK_REGEX:
case AWK_UNDEFINED:
case AWK_SCALAR:
case AWK_VALUE_COOKIE:
break;
+
default: /* AWK_ARRAY or invalid type */
return awk_false;
}
@@ -701,7 +886,9 @@ valid_subscript_type(awk_valtype_t valtype)
switch (valtype) {
case AWK_UNDEFINED:
case AWK_NUMBER:
+ case AWK_STRNUM:
case AWK_STRING:
+ case AWK_REGEX:
case AWK_SCALAR:
case AWK_VALUE_COOKIE:
return true;
@@ -782,7 +969,6 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie,
tmp = awk_value_to_node(index);
aptr = assoc_lookup(array, tmp);
- unref(tmp);
unref(*aptr);
elem = *aptr = awk_value_to_node(value);
if (elem->type == Node_var_array) {
@@ -790,12 +976,15 @@ api_set_array_element(awk_ext_id_t id, awk_array_t a_cookie,
elem->vname = estrdup(index->str_value.str,
index->str_value.len);
}
+ if (array->astore != NULL)
+ (*array->astore)(array, tmp);
+ unref(tmp);
return awk_true;
}
/*
- * remove_element --- remove an array element
+ * remove_element --- remove an array element
* common code used by multiple functions
*/
@@ -900,12 +1089,13 @@ api_clear_array(awk_ext_id_t id, awk_array_t a_cookie)
return awk_true;
}
-/* api_flatten_array --- flatten out an array so that it can be looped over easily. */
+/* api_flatten_array_typed --- flatten out an array so that it can be looped over easily. */
static awk_bool_t
-api_flatten_array(awk_ext_id_t id,
+api_flatten_array_typed(awk_ext_id_t id,
awk_array_t a_cookie,
- awk_flat_array_t **data)
+ awk_flat_array_t **data,
+ awk_valtype_t index_type, awk_valtype_t value_type)
{
NODE **list;
size_t i, j;
@@ -921,9 +1111,8 @@ api_flatten_array(awk_ext_id_t id,
alloc_size = sizeof(awk_flat_array_t) +
(array->table_size - 1) * sizeof(awk_element_t);
- emalloc(*data, awk_flat_array_t *, alloc_size,
- "api_flatten_array");
- memset(*data, 0, alloc_size);
+ ezalloc(*data, awk_flat_array_t *, alloc_size,
+ "api_flatten_array_typed");
list = assoc_list(array, "@unsorted", ASORTI);
@@ -937,21 +1126,16 @@ api_flatten_array(awk_ext_id_t id,
index = list[i];
value = list[i + 1]; /* number or string or subarray */
- /*
- * Convert index and value to ext types. Force the
- * index to be a string, since indices are always
- * conceptually strings, regardless of internal optimizations
- * to treat them as integers in some cases.
- */
+ /* Convert index and value to API types. */
if (! node_to_awk_value(index,
- & (*data)->elements[j].index, AWK_STRING)) {
- fatal(_("api_flatten_array: could not convert index %d\n"),
- (int) i);
+ & (*data)->elements[j].index, index_type)) {
+ fatal(_("api_flatten_array_typed: could not convert index %d to %s\n"),
+ (int) i, valtype2str(index_type));
}
if (! node_to_awk_value(value,
- & (*data)->elements[j].value, AWK_UNDEFINED)) {
- fatal(_("api_flatten_array: could not convert value %d\n"),
- (int) i);
+ & (*data)->elements[j].value, value_type)) {
+ fatal(_("api_flatten_array_typed: could not convert value %d to %s\n"),
+ (int) i, valtype2str(value_type));
}
}
return awk_true;
@@ -1009,7 +1193,9 @@ api_create_value(awk_ext_id_t id, awk_value_t *value,
switch (value->val_type) {
case AWK_NUMBER:
+ case AWK_STRNUM:
case AWK_STRING:
+ case AWK_REGEX:
break;
default:
/* reject anything other than a simple scalar */
@@ -1033,6 +1219,99 @@ api_release_value(awk_ext_id_t id, awk_value_cookie_t value)
return awk_true;
}
+/* api_get_file --- return a handle to an existing or newly opened file */
+
+static awk_bool_t
+api_get_file(awk_ext_id_t id, const char *name, size_t namelen, const char *filetype,
+ int fd, const awk_input_buf_t **ibufp, const awk_output_buf_t **obufp)
+{
+ const struct redirect *f;
+ int flag; /* not used, sigh */
+ enum redirval redirtype;
+
+ if (name == NULL || namelen == 0) {
+ if (curfile == NULL) {
+ INSTRUCTION *pc;
+ int save_rule;
+ char *save_source;
+
+ if (nextfile(& curfile, false) <= 0)
+ return awk_false;
+
+ pc = main_beginfile;
+ /* save execution state */
+ save_rule = currule;
+ save_source = source;
+
+ for (;;) {
+ if (pc == NULL)
+ fatal(_("cannot find end of BEGINFILE rule"));
+ if (pc->opcode == Op_after_beginfile)
+ break;
+ pc = pc->nexti;
+ }
+ pc->opcode = Op_stop;
+ (void) (*interpret)(main_beginfile);
+ pc->opcode = Op_after_beginfile;
+ after_beginfile(& curfile);
+ /* restore execution state */
+ currule = save_rule;
+ source = save_source;
+ }
+ *ibufp = &curfile->public;
+ *obufp = NULL;
+
+ return awk_true;
+ }
+
+ redirtype = redirect_none;
+ switch (filetype[0]) {
+ case '<':
+ if (filetype[1] == '\0')
+ redirtype = redirect_input;
+ break;
+ case '>':
+ switch (filetype[1]) {
+ case '\0':
+ redirtype = redirect_output;
+ break;
+ case '>':
+ if (filetype[2] == '\0')
+ redirtype = redirect_append;
+ break;
+ }
+ break;
+ case '|':
+ if (filetype[2] == '\0') {
+ switch (filetype[1]) {
+ case '>':
+ redirtype = redirect_pipe;
+ break;
+ case '<':
+ redirtype = redirect_pipein;
+ break;
+ case '&':
+ redirtype = redirect_twoway;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (redirtype == redirect_none) {
+ warning(_("cannot open unrecognized file type `%s' for `%s'"),
+ filetype, name);
+ return awk_false;
+ }
+
+ if ((f = redirect_string(name, namelen, 0, redirtype, &flag, fd, false)) == NULL)
+ return awk_false;
+
+ *ibufp = f->iop ? & f->iop->public : NULL;
+ *obufp = f->output.fp ? & f->output : NULL;
+ return awk_true;
+}
+
/*
* Register a version string for this extension with gawk.
*/
@@ -1081,6 +1360,7 @@ gawk_api_t api_impl = {
api_fatal,
api_warning,
api_lintwarn,
+ api_nonfatal,
/* updating ERRNO */
api_update_ERRNO_int,
@@ -1110,7 +1390,7 @@ gawk_api_t api_impl = {
api_del_array_element,
api_create_array,
api_clear_array,
- api_flatten_array,
+ api_flatten_array_typed,
api_release_flattened_array,
/* Memory allocation */
@@ -1118,6 +1398,9 @@ gawk_api_t api_impl = {
calloc,
realloc,
free,
+
+ /* Find/open a file */
+ api_get_file,
};
/* init_ext_api --- init the extension API */
@@ -1152,3 +1435,30 @@ print_ext_versions(void)
for (p = vi_head; p != NULL; p = p->next)
printf("%s\n", p->version);
}
+
+/* valtype2str --- return a printable representation of a value type */
+
+static char *
+valtype2str(awk_valtype_t type)
+{
+ static char buf[100];
+
+ // Important: keep in same order as in gawkapi.h!
+ static char *values[] = {
+ "AWK_UNDEFINED",
+ "AWK_NUMBER",
+ "AWK_STRING",
+ "AWK_REGEX",
+ "AWK_STRNUM",
+ "AWK_ARRAY",
+ "AWK_SCALAR",
+ "AWK_VALUE_COOKIE",
+ };
+
+ if (AWK_UNDEFINED <= type && type <= AWK_VALUE_COOKIE)
+ return values[(int) type];
+
+ sprintf(buf, "unknown type! (%d)", (int) type);
+
+ return buf;
+}
diff --git a/gawkapi.h b/gawkapi.h
index 039ec5fa..b8e8a26d 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -2,22 +2,22 @@
* gawkapi.h -- Definitions for use by extension functions calling into gawk.
*/
-/*
- * Copyright (C) 2012-2016 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 2012-2017 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -53,7 +53,7 @@
* This API purposely restricts itself to ISO C 90 features. In particular, no
* bool, no // comments, no use of the restrict keyword, or anything else,
* in order to provide maximal portability.
- *
+ *
* Exception: the "inline" keyword is used below in the "constructor"
* functions. If your compiler doesn't support it, you should either
* -Dinline='' on your command line, or use the autotools and include a
@@ -117,6 +117,32 @@ typedef enum awk_bool {
awk_true
} awk_bool_t; /* we don't use <stdbool.h> on purpose */
+/*
+ * If an input parser would like to specify the field positions in the input
+ * record, it may populate an awk_fieldwidth_info_t structure to indicate
+ * the location of each field. The use_chars boolean controls whether the
+ * field lengths are specified in terms of bytes or potentially multi-byte
+ * characters. Performance will be better if the values are supplied in
+ * terms of bytes. The fields[0].skip value indicates how many bytes (or
+ * characters) to skip before $1, and fields[0].len is the length of $1, etc.
+ */
+
+typedef struct {
+ awk_bool_t use_chars; /* false ==> use bytes */
+ size_t nf;
+ struct awk_field_info {
+ size_t skip; /* amount to skip before field starts */
+ size_t len; /* length of field */
+ } fields[1]; /* actual dimension should be nf */
+} awk_fieldwidth_info_t;
+
+/*
+ * This macro calculates the total struct size needed. This is useful when
+ * calling malloc or realloc.
+ */
+#define awk_fieldwidth_info_size(NF) (sizeof(awk_fieldwidth_info_t) + \
+ (((NF)-1) * sizeof(struct awk_field_info)))
+
/* The information about input files that input parsers need to know: */
typedef struct awk_input {
const char *name; /* filename */
@@ -136,7 +162,7 @@ typedef struct awk_input {
* parser is responsible for managing its own memory buffer.
* Similarly, gawk will make its own copy of RT, so the parser
* is also responsible for managing this memory.
- *
+ *
* It is guaranteed that errcode is a valid pointer, so there is
* no need to test for a NULL value. Gawk sets *errcode to 0,
* so there is no need to set it unless an error occurs.
@@ -146,9 +172,19 @@ typedef struct awk_input {
* than zero, gawk will automatically update the ERRNO variable based
* on the value of *errcode (e.g., setting *errcode = errno should do
* the right thing).
+ *
+ * If field_width is non-NULL, then *field_width will be initialized
+ * to NULL, and the function may set it to point to a structure
+ * supplying field width information to override the default
+ * gawk field parsing mechanism. Note that this structure will not
+ * be copied by gawk; it must persist at least until the next call
+ * to get_record or close_func. Note also that field_width will
+ * be NULL when getline is assigning the results to a variable, thus
+ * field parsing is not needed.
*/
int (*get_record)(char **out, struct awk_input *iobuf, int *errcode,
- char **rt_start, size_t *rt_len);
+ char **rt_start, size_t *rt_len,
+ const awk_fieldwidth_info_t **field_width);
/*
* No argument prototype on read_func to allow for older systems
@@ -165,14 +201,14 @@ typedef struct awk_input {
/* put last, for alignment. bleah */
struct stat sbuf; /* stat buf */
-
+
} awk_input_buf_t;
typedef struct awk_input_parser {
const char *name; /* name of parser */
/*
- * The can_take_file function should return non-zero if the parser
+ * The can_take_file function should return true if the parser
* would like to parse this file. It should not change any gawk
* state!
*/
@@ -183,7 +219,7 @@ typedef struct awk_input_parser {
* It can assume that a previous call to can_take_file was successful,
* and no gawk state has changed since that call. It should populate
* the awk_input_buf_t's get_record, close_func, and opaque values as needed.
- * It should return non-zero if successful.
+ * It should return true if successful.
*/
awk_bool_t (*take_control_of)(awk_input_buf_t *iobuf);
@@ -218,7 +254,7 @@ typedef struct awk_output_wrapper {
const char *name; /* name of the wrapper */
/*
- * The can_take_file function should return non-zero if the wrapper
+ * The can_take_file function should return true if the wrapper
* would like to process this file. It should not change any gawk
* state!
*/
@@ -229,7 +265,7 @@ typedef struct awk_output_wrapper {
* It can assume that a previous call to can_take_file was successful,
* and no gawk state has changed since that call. It should populate
* the awk_output_buf_t function pointers and opaque pointer as needed.
- * It should return non-zero if successful.
+ * It should return true if successful.
*/
awk_bool_t (*take_control_of)(awk_output_buf_t *outbuf);
@@ -241,7 +277,7 @@ typedef struct awk_two_way_processor {
const char *name; /* name of the two-way processor */
/*
- * The can_take_file function should return non-zero if the two-way
+ * The can_take_file function should return true if the two-way
* processor would like to parse this file. It should not change
* any gawk state!
*/
@@ -252,7 +288,7 @@ typedef struct awk_two_way_processor {
* It can assume that a previous call to can_take_file was successful,
* and no gawk state has changed since that call. It should populate
* the awk_input_buf_t and awk_otuput_buf_t structures as needed.
- * It should return non-zero if successful.
+ * It should return true if successful.
*/
awk_bool_t (*take_control_of)(const char *name, awk_input_buf_t *inbuf,
awk_output_buf_t *outbuf);
@@ -260,8 +296,8 @@ typedef struct awk_two_way_processor {
awk_const struct awk_two_way_processor *awk_const next; /* for use by gawk */
} awk_two_way_processor_t;
-#define gawk_api_major_version 1
-#define gawk_api_minor_version 1
+#define gawk_api_major_version 2
+#define gawk_api_minor_version 0
/* Current version of the API. */
enum {
@@ -278,6 +314,9 @@ enum {
* The API deals exclusively with regular chars; these strings may
* be multibyte encoded in the current locale's encoding and character
* set. Gawk will convert internally to wide characters if necessary.
+ *
+ * Note that a string provided by gawk will always be terminated
+ * with a '\0' character.
*/
typedef struct awk_string {
char *str; /* data */
@@ -304,6 +343,8 @@ typedef enum {
AWK_UNDEFINED,
AWK_NUMBER,
AWK_STRING,
+ AWK_REGEX,
+ AWK_STRNUM,
AWK_ARRAY,
AWK_SCALAR, /* opaque access to a variable */
AWK_VALUE_COOKIE /* for updating a previously created value */
@@ -323,6 +364,8 @@ typedef struct awk_value {
awk_value_cookie_t vc;
} u;
#define str_value u.s
+#define strnum_value str_value
+#define regex_value str_value
#define num_value u.d
#define array_cookie u.a
#define scalar_cookie u.scl
@@ -345,7 +388,7 @@ typedef struct awk_element {
AWK_ELEMENT_DELETE = 1 /* set by extension if
should be deleted */
} flags;
- awk_value_t index; /* guaranteed to be a string! */
+ awk_value_t index;
awk_value_t value;
} awk_element_t;
@@ -365,8 +408,8 @@ typedef struct awk_flat_array {
* loaded, the extension should pass in one of these to gawk for
* each C function.
*
- * Each called function must fill in the result with either a number
- * or string. Gawk takes ownership of any string memory.
+ * Each called function must fill in the result with either a scalar
+ * (number, string, or regex). Gawk takes ownership of any string memory.
*
* The called function must return the value of `result'.
* This is for the convenience of the calling code inside gawk.
@@ -374,11 +417,26 @@ typedef struct awk_flat_array {
* Each extension function may decide what to do if the number of
* arguments isn't what it expected. Following awk functions, it
* is likely OK to ignore extra arguments.
+ *
+ * 'min_required_args' indicates how many arguments MUST be passed.
+ * The API will throw a fatal error if not enough are passed.
+ *
+ * 'max_expected_args' is more benign; if more than that are passed,
+ * the API prints a lint message (IFF lint is enabled, of course).
+ *
+ * In any case, the extension function itself need not compare the
+ * actual number of arguments passed to those two values if it does
+ * not want to.
*/
typedef struct awk_ext_func {
const char *name;
- awk_value_t *(*function)(int num_actual_args, awk_value_t *result);
- size_t num_expected_args;
+ awk_value_t *(*const function)(int num_actual_args,
+ awk_value_t *result,
+ struct awk_ext_func *finfo);
+ const size_t max_expected_args;
+ const size_t min_required_args;
+ awk_bool_t suppress_lint;
+ void *data; /* opaque pointer to any extra state */
} awk_ext_func_t;
typedef void *awk_ext_id_t; /* opaque type for extension id */
@@ -411,9 +469,14 @@ typedef struct gawk_api {
/* Next, registration functions: */
- /* Add a function to the interpreter, returns true upon success */
+ /*
+ * Add a function to the interpreter, returns true upon success.
+ * Gawk does not modify what func points to, but the extension
+ * function itself receives this pointer and can modify what it
+ * points to, thus it's not const.
+ */
awk_bool_t (*api_add_ext_func)(awk_ext_id_t id, const char *namespace,
- const awk_ext_func_t *func);
+ awk_ext_func_t *func);
/* Register an input parser; for opening files read-only */
void (*api_register_input_parser)(awk_ext_id_t id,
@@ -447,6 +510,7 @@ typedef struct gawk_api {
void (*api_fatal)(awk_ext_id_t id, const char *format, ...);
void (*api_warning)(awk_ext_id_t id, const char *format, ...);
void (*api_lintwarn)(awk_ext_id_t id, const char *format, ...);
+ void (*api_nonfatal)(awk_ext_id_t id, const char *format, ...);
/* Functions to update ERRNO */
void (*api_update_ERRNO_int)(awk_ext_id_t id, int errno_val);
@@ -459,39 +523,40 @@ typedef struct gawk_api {
* behave in the same way.
*
* For a function parameter, the return is false if the argument
- * count is out of range, or if actual paramater does not match
+ * count is out of range, or if the actual paramater does not match
* what is specified in wanted. In that case, result->val_type
* will hold the actual type of what was passed.
*
* Similarly for symbol table access to variables and array elements,
* the return is false if the actual variable or array element does
- * not match what was requested, and the result->val_type will hold
+ * not match what was requested, and result->val_type will hold
* the actual type.
Table entry is type returned:
- +-------------------------------------------------+
- | Type of Actual Value: |
- +------------+------------+-----------+-----------+
- | String | Number | Array | Undefined |
- +-----------+-----------+------------+------------+-----------+-----------+
- | | String | String | String | false | false |
- | |-----------+------------+------------+-----------+-----------+
- | | Number | Number if | Number | false | false |
- | | | can be | | | |
- | | | converted, | | | |
- | | | else false | | | |
- | |-----------+------------+------------+-----------+-----------+
- | Type | Array | false | false | Array | false |
- | Requested |-----------+------------+------------+-----------+-----------+
- | | Scalar | Scalar | Scalar | false | false |
- | |-----------+------------+------------+-----------+-----------+
- | | Undefined | String | Number | Array | Undefined |
- | |-----------+------------+------------+-----------+-----------+
- | | Value | false | false | false | false |
- | | Cookie | | | | |
- +-----------+-----------+------------+------------+-----------+-----------+
+ +-------------------------------------------------------+
+ | Type of Actual Value: |
+ +--------+--------+--------+--------+-------+-----------+
+ | String | Strnum | Number | Regex | Array | Undefined |
+ +-----------+-----------+--------+--------+--------+--------+-------+-----------+
+ | | String | String | String | String | String | false | false |
+ | +-----------+--------+--------+--------+--------+-------+-----------+
+ | | Strnum | false | Strnum | Strnum | false | false | false |
+ | +-----------+--------+--------+--------+--------+-------+-----------+
+ | | Number | Number | Number | Number | false | false | false |
+ | +-----------+--------+--------+--------+--------+-------+-----------+
+ | | Regex | false | false | false | Regex | false | false |
+ | +-----------+--------+--------+--------+--------+-------+-----------+
+ | Type | Array | false | false | false | false | Array | false |
+ | Requested +-----------+--------+--------+--------+--------+-------+-----------+
+ | | Scalar | Scalar | Scalar | Scalar | Scalar | false | false |
+ | +-----------+--------+--------+--------+--------+-------+-----------+
+ | | Undefined | String | Strnum | Number | Regex | Array | Undefined |
+ | +-----------+--------+--------+--------+--------+-------+-----------+
+ | | Value | false | false | false | false | false | false |
+ | | Cookie | | | | | | |
+ +-----------+-----------+--------+--------+--------+--------+-------+-----------+
*/
/* Functions to handle parameters passed to the extension. */
@@ -507,7 +572,7 @@ typedef struct gawk_api {
awk_value_t *result);
/*
- * Convert a paramter that was undefined into an array
+ * Convert a parameter that was undefined into an array
* (provide call-by-reference for arrays). Returns false
* if count is too big, or if the argument's type is
* not undefined.
@@ -521,12 +586,12 @@ typedef struct gawk_api {
* - Read-only access to special variables (NF, etc.)
* - One special exception: PROCINFO.
* - Use sym_update() to change a value, including from UNDEFINED
- * to scalar or array.
+ * to scalar or array.
*/
/*
* Lookup a variable, fill in value. No messing with the value
* returned.
- * Returns false if the variable doesn't exist* or if the wrong type
+ * Returns false if the variable doesn't exist or if the wrong type
* was requested. In the latter case, vaule->val_type will have
* the real type, as described above.
*
@@ -588,7 +653,7 @@ typedef struct gawk_api {
* use the scalar cookie
*
* Return will be false if the new value is not one of
- * AWK_STRING or AWK_NUMBER.
+ * AWK_STRING, AWK_NUMBER, AWK_REGEX.
*
* Here too, the built-in variables may not be updated.
*/
@@ -598,12 +663,12 @@ typedef struct gawk_api {
/* Cached values */
/*
- * Create a cached string or numeric value for efficient later
+ * Create a cached string,regex, or numeric value for efficient later
* assignment. This improves performance when you want to assign
* the same value to one or more variables repeatedly. Only
- * AWK_NUMBER and AWK_STRING values are allowed. Any other type
- * is rejected. We disallow AWK_UNDEFINED since that case would
- * result in inferior performance.
+ * AWK_NUMBER, AWK_STRING, AWK_REGEX and AWK_STRNUM values are allowed.
+ * Any other type is rejected. We disallow AWK_UNDEFINED since that
+ * case would result in inferior performance.
*/
awk_bool_t (*api_create_value)(awk_ext_id_t id, awk_value_t *value,
awk_value_cookie_t *result);
@@ -647,21 +712,27 @@ typedef struct gawk_api {
/*
* Remove the element with the given index.
- * Returns success if removed or false if element did not exist.
+ * Returns true if removed or false if element did not exist.
*/
awk_bool_t (*api_del_array_element)(awk_ext_id_t id,
awk_array_t a_cookie, const awk_value_t* const index);
- /* Create a new array cookie to which elements may be added */
+ /* Create a new array cookie to which elements may be added. */
awk_array_t (*api_create_array)(awk_ext_id_t id);
- /* Clear out an array */
+ /* Clear out an array. */
awk_bool_t (*api_clear_array)(awk_ext_id_t id, awk_array_t a_cookie);
- /* Flatten out an array so that it can be looped over easily. */
- awk_bool_t (*api_flatten_array)(awk_ext_id_t id,
+ /*
+ * Flatten out an array with type conversions as requested.
+ * This supersedes the earlier api_flatten_array function that
+ * did not allow the caller to specify the requested types.
+ * (That API is still available as a macro, defined below.)
+ */
+ awk_bool_t (*api_flatten_array_typed)(awk_ext_id_t id,
awk_array_t a_cookie,
- awk_flat_array_t **data);
+ awk_flat_array_t **data,
+ awk_valtype_t index_type, awk_valtype_t value_type);
/* When done, delete any marked elements, release the memory. */
awk_bool_t (*api_release_flattened_array)(awk_ext_id_t id,
@@ -677,6 +748,53 @@ typedef struct gawk_api {
void *(*api_calloc)(size_t nmemb, size_t size);
void *(*api_realloc)(void *ptr, size_t size);
void (*api_free)(void *ptr);
+
+ /*
+ * Look up a file. If the name is NULL or name_len is 0, it returns
+ * data for the currently open input file corresponding to FILENAME
+ * (and it will not access the filetype argument, so that may be
+ * undefined).
+ *
+ * If the file is not already open, try to open it.
+ *
+ * The "filetype" argument should be one of:
+ *
+ * ">", ">>", "<", "|>", "|<", and "|&"
+ *
+ * If the file is not already open, and the fd argument is non-negative,
+ * gawk will use that file descriptor instead of opening the file
+ * in the usual way.
+ *
+ * If the fd is non-negative, but the file exists already, gawk
+ * ignores the fd and returns the existing file. It is the caller's
+ * responsibility to notice that the fd in the returned
+ * awk_input_buf_t does not match the requested value.
+ *
+ * Note that supplying a file descriptor is currently NOT supported
+ * for pipes. It should work for input, output, append, and two-way
+ * (coprocess) sockets. If the filetype is two-way, we assume that
+ * it is a socket!
+ *
+ * Note that in the two-way case, the input and output file descriptors
+ * may differ. To check for success, one must check that either of
+ * them matches.
+ *
+ * ibufp and obufp point at gawk's internal copies of the
+ * awk_input_buf_t and awk_output_t associated with the open
+ * file. Treat these data structures as read-only!
+ */
+ awk_bool_t (*api_get_file)(awk_ext_id_t id,
+ const char *name,
+ size_t name_len,
+ const char *filetype,
+ int fd,
+ /*
+ * Return values (on success, one or both should
+ * be non-NULL):
+ */
+ const awk_input_buf_t **ibufp,
+ const awk_output_buf_t **obufp);
+
} gawk_api_t;
#ifndef GAWK /* these are not for the gawk code itself! */
@@ -698,6 +816,7 @@ typedef struct gawk_api {
(api->api_set_argument(ext_id, count, new_array))
#define fatal api->api_fatal
+#define nonfatal api->api_nonfatal
#define warning api->api_warning
#define lintwarn api->api_lintwarn
@@ -742,8 +861,11 @@ typedef struct gawk_api {
#define clear_array(array) (api->api_clear_array(ext_id, array))
+#define flatten_array_typed(array, data, index_type, value_type) \
+ (api->api_flatten_array_typed(ext_id, array, data, index_type, value_type))
+
#define flatten_array(array, data) \
- (api->api_flatten_array(ext_id, array, data))
+ flatten_array_typed(array, data, AWK_STRING, AWK_UNDEFINED)
#define release_flattened_array(array, data) \
(api->api_release_flattened_array(ext_id, array, data))
@@ -759,6 +881,9 @@ typedef struct gawk_api {
#define release_value(value) \
(api->api_release_value(ext_id, value))
+#define get_file(name, namelen, filetype, fd, ibuf, obuf) \
+ (api->api_get_file(ext_id, name, namelen, filetype, fd, ibuf, obuf))
+
#define register_ext_version(version) \
(api->api_register_ext_version(ext_id, version))
@@ -768,6 +893,12 @@ typedef struct gawk_api {
fatal(ext_id, "%s: malloc of %d bytes failed\n", message, size); \
} while(0)
+#define ezalloc(pointer, type, size, message) \
+ do { \
+ if ((pointer = (type) gawk_calloc(1, size)) == 0) \
+ fatal(ext_id, "%s: calloc of %d bytes failed\n", message, size); \
+ } while(0)
+
#define erealloc(pointer, type, size, message) \
do { \
if ((pointer = (type) gawk_realloc(pointer, size)) == 0) \
@@ -776,25 +907,26 @@ typedef struct gawk_api {
/* Constructor functions */
-/* r_make_string --- make a string value in result from the passed-in string */
+/* r_make_string_type --- make a string or strnum or regexp value in result from the passed-in string */
static inline awk_value_t *
-r_make_string(const gawk_api_t *api, /* needed for emalloc */
- awk_ext_id_t *ext_id, /* ditto */
- const char *string,
- size_t length,
- awk_bool_t duplicate,
- awk_value_t *result)
+r_make_string_type(const gawk_api_t *api, /* needed for emalloc */
+ awk_ext_id_t *ext_id, /* ditto */
+ const char *string,
+ size_t length,
+ awk_bool_t duplicate,
+ awk_value_t *result,
+ awk_valtype_t val_type)
{
char *cp = NULL;
memset(result, 0, sizeof(*result));
- result->val_type = AWK_STRING;
+ result->val_type = val_type;
result->str_value.len = length;
if (duplicate) {
- emalloc(cp, char *, length + 2, "r_make_string");
+ emalloc(cp, char *, length + 1, "r_make_string");
memcpy(cp, string, length);
cp[length] = '\0';
result->str_value.str = cp;
@@ -805,9 +937,33 @@ r_make_string(const gawk_api_t *api, /* needed for emalloc */
return result;
}
+/* r_make_string --- make a string value in result from the passed-in string */
+
+static inline awk_value_t *
+r_make_string(const gawk_api_t *api, /* needed for emalloc */
+ awk_ext_id_t *ext_id, /* ditto */
+ const char *string,
+ size_t length,
+ awk_bool_t duplicate,
+ awk_value_t *result)
+{
+ return r_make_string_type(api, ext_id, string, length, duplicate, result, AWK_STRING);
+}
+
#define make_const_string(str, len, result) r_make_string(api, ext_id, str, len, 1, result)
#define make_malloced_string(str, len, result) r_make_string(api, ext_id, str, len, 0, result)
+#define make_const_regex(str, len, result) r_make_string_type(api, ext_id, str, len, 1, result, AWK_REGEX)
+#define make_malloced_regex(str, len, result) r_make_string_type(api, ext_id, str, len, 0, result, AWK_REGEX)
+
+/*
+ * Note: The caller may not create a STRNUM, but it can create a string that is
+ * flagged as user input that MAY be a STRNUM. Gawk will decide whether it's a
+ * STRNUM or a string by checking whether the string is numeric.
+ */
+#define make_const_user_input(str, len, result) r_make_string_type(api, ext_id, str, len, 1, result, AWK_STRNUM)
+#define make_malloced_user_input(str, len, result) r_make_string_type(api, ext_id, str, len, 0, result, AWK_STRNUM)
+
/* make_null_string --- make a null string value */
static inline awk_value_t *
@@ -832,6 +988,7 @@ make_number(double num, awk_value_t *result)
return result;
}
+
/*
* Each extension must define a function with this prototype:
*
diff --git a/gawkmisc.c b/gawkmisc.c
index 0172a810..bef4f365 100644
--- a/gawkmisc.c
+++ b/gawkmisc.c
@@ -2,23 +2,23 @@
* gawkmisc.c --- miscellanious gawk routines that are OS specific.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2004, 2010, 2011
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -41,19 +41,3 @@
#include "posix/gawkmisc.c"
#endif /* not VMS */
#endif /* not __DJGPP__, not __MINGW32__ */
-
-/* xmalloc --- provide this so that other GNU library routines work */
-
-typedef void *pointer;
-
-extern pointer xmalloc(size_t bytes); /* get rid of gcc warning */
-
-pointer
-xmalloc(size_t bytes)
-{
- pointer p;
- if (bytes == 0)
- bytes = 1; /* avoid dfa.c mishegos */
- emalloc(p, pointer, bytes, "xmalloc");
- return p;
-}
diff --git a/gettext.h b/gettext.h
index 474419ac..b3e8d876 100644
--- a/gettext.h
+++ b/gettext.h
@@ -193,7 +193,8 @@ npgettext_aux (const char *domain,
#include <string.h>
#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
- /* || __STDC_VERSION__ >= 199901L */ )
+ /* || __STDC_VERSION__ == 199901L
+ || (__STDC_VERSION__ >= 201112L && !defined __STDC_NO_VLA__) */ )
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
#else
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
@@ -234,15 +235,17 @@ dcpgettext_expr (const char *domain,
if (msg_ctxt_id != NULL)
#endif
{
+ int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcgettext (domain, msg_ctxt_id, category);
+ found_translation = (translation != msg_ctxt_id);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
- if (translation != msg_ctxt_id)
+ if (found_translation)
return translation;
}
return msgid;
@@ -280,15 +283,17 @@ dcnpgettext_expr (const char *domain,
if (msg_ctxt_id != NULL)
#endif
{
+ int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+ found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
- if (!(translation == msg_ctxt_id || translation == msgid_plural))
+ if (found_translation)
return translation;
}
return (n == 1 ? msgid : msgid_plural);
diff --git a/helpers/ChangeLog b/helpers/ChangeLog
index d27fc555..c1a74d5b 100644
--- a/helpers/ChangeLog
+++ b/helpers/ChangeLog
@@ -1,3 +1,39 @@
+2017-06-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * testdfa.c: Bring up to date, fix compile warnings.
+ Remove more xmalloc stuff.
+
+2017-06-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * testdfa.c (xcalloc): Replace xmalloc+memset with calloc.
+ (xzalloc): Replace xmalloc+memset with xcalloc.
+
+2017-04-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ * test-build.sh: Allow override of compiler lists. Print
+ out path to current compiler. Thanks to Michal Jaegermann
+ <michal.jnn@gmail.com> for the suggestions.
+
+2017-04-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * test-build.sh: New file.
+
+2017-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * update-branches.sh: Robustness improvements.
+
+2017-02-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * update-branches.sh: New file.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+
+2016-09-08 Paul Eggert <eggert@cs.ucla.edu>
+
+ * testdfa.c: Adjust to DFA API changes.
+
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.4: Release tar ball made.
@@ -37,6 +73,14 @@
* 4.1.2: Release tar ball made.
+2015-04-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * testdfa.c (setup_pattern): Rationalize buffer size computations.
+
+2014-12-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * testdfa.c (setup_pattern): Do not waste a byte at the end of a string.
+
2014-09-04 Arnold D. Robbins <arnold@skeeve.com>
* chlistref.awk: New file. Finds @ref{} to non-chapters.
diff --git a/helpers/test-build.sh b/helpers/test-build.sh
new file mode 100755
index 00000000..3ed20ec1
--- /dev/null
+++ b/helpers/test-build.sh
@@ -0,0 +1,52 @@
+#! /bin/bash
+
+MIXED_COMPILERS=${MIXED_COMPILERS:-gcc /usr/gcc/bin/gcc clang}
+OTHER_COMPILERS=${OTHER_COMPILERS:-tcc pcc}
+
+rm -f compile-results.txt
+
+compile () {
+ make -k
+ if make check
+ then
+ echo success: $1 $2 >> compile-results.txt
+ else
+ echo failure: $1 $2 >> compile-results.txt
+ fi
+}
+
+configure_and_compile () {
+ if type -p $1 >> compile-results.txt 2>&1
+ then
+ for j in "" --disable-mpfr
+ do
+ ./configure $j CC="$1"
+ compile "$1" "$j"
+ make distclean
+ done
+ fi
+}
+
+(make distclean)
+
+for i in $OTHER_COMPILERS $MIXED_COMPILERS
+do
+ configure_and_compile $i
+done
+
+for i in $MIXED_COMPILERS
+do
+ configure_and_compile "$i -m32"
+done
+
+echo
+echo ==========================================
+echo
+case $(grep failure compile-results.txt | wc -l) in
+0) echo No failures!
+ # rm compile-results.txt
+ ;;
+*) echo The following combinations failed:
+ grep failure compile-results.txt
+ ;;
+esac
diff --git a/helpers/testdfa.c b/helpers/testdfa.c
index 1e144bd7..0f7911a1 100644
--- a/helpers/testdfa.c
+++ b/helpers/testdfa.c
@@ -1,23 +1,25 @@
/*
* testdfa.c --- abstracted from gawk.
+ *
+ * gcc -I.. -I../support testdfa.c ../support/libsupport.a -o testdfa
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991-2013 the Free Software Foundation, Inc.
- *
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-2017 the Free Software Foundation, Inc.
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -44,6 +46,7 @@
#define _Noreturn
#define _GL_ATTRIBUTE_PURE
#include "dfa.h"
+#include "localeinfo.h"
const char *regexflags2str(int flags);
char *databuf(int fd);
@@ -71,7 +74,8 @@ void usage(const char *myname)
int main(int argc, char **argv)
{
- int c, ret, try_backref;
+ int c, ret;
+ bool try_backref;
struct re_pattern_buffer pat;
struct re_registers regs;
struct dfa *dfareg;
@@ -84,6 +88,7 @@ int main(int argc, char **argv)
char save;
size_t count = 0;
char *place;
+ struct localeinfo localeinfo;
if (argc < 2)
usage(argv[0]);
@@ -128,10 +133,10 @@ int main(int argc, char **argv)
printf("Ignorecase: %s\nSyntax: %s\n",
(ignorecase ? "true" : "false"),
reflags2str(syn));
- printf("Pattern: /%s/, len = %d\n", pattern, len);
+ printf("Pattern: /%s/, len = %lu\n", pattern, len);
pattern = setup_pattern(pattern, & len);
- printf("After setup_pattern(), len = %d\n", len);
+ printf("After setup_pattern(), len = %lu\n", len);
pat.fastmap = (char *) malloc(256);
if (pat.fastmap == NULL) {
@@ -158,7 +163,6 @@ int main(int argc, char **argv)
dfa_syn = syn;
if (ignorecase)
dfa_syn |= RE_ICASE;
- dfasyntax(dfa_syn, ignorecase, '\n');
re_set_syntax(syn);
if ((rerr = re_compile_pattern(pattern, len, & pat)) != NULL) {
@@ -171,6 +175,9 @@ int main(int argc, char **argv)
pat.newline_anchor = false; /* don't get \n in middle of string */
dfareg = dfaalloc();
+ init_localeinfo(&localeinfo);
+ dfasyntax(dfareg, &localeinfo, dfa_syn, 0);
+
printf("Calling dfacomp(%s, %d, %p, true)\n",
pattern, (int) len, dfareg);
@@ -196,7 +203,7 @@ int main(int argc, char **argv)
if (place == NULL)
printf("dfaexec returned NULL\n");
else
- printf("dfaexec returned %d (%.3s)\n", place - data, place);
+ printf("dfaexec returned %ld (%.3s)\n", place - data, place);
/* release storage */
regfree(& pat);
@@ -336,21 +343,6 @@ databuf(int fd)
return buf;
}
-/* xmalloc --- for dfa.c */
-
-void *
-xmalloc(size_t bytes)
-{
- void *p = malloc(bytes);
-
- if (p == NULL) {
- fprintf(stderr, "xmalloc: malloc failed: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- return p;
-}
-
/* r_fatal --- print a fatal error message. also for dfa.c */
void
@@ -372,10 +364,10 @@ setup_pattern(const char *pattern, size_t *len)
{
size_t is_multibyte = 0;
int c, c2;
- size_t buflen = 0;
+ size_t buflen;
mbstate_t mbs;
bool has_anchor = false;
- char *buf = NULL;
+ char *buf;
char *dest;
const char *src, *end;
@@ -389,23 +381,14 @@ setup_pattern(const char *pattern, size_t *len)
/*
* Build a copy of the string (in buf) with the
* escaped characters translated, and generate the regex
- * from that.
+ * from that.
*/
+ buf = (char *) malloc(*len + 1);
if (buf == NULL) {
- buf = (char *) malloc(*len + 2);
- if (buf == NULL) {
- fprintf(stderr, "%s: malloc failed\n", __func__);
- exit(EXIT_FAILURE);
- }
- buflen = *len;
- } else if (*len > buflen) {
- buf = (char *) realloc(buf, *len + 2);
- if (buf == NULL) {
- fprintf(stderr, "%s: realloc failed\n", __func__);
- exit(EXIT_FAILURE);
- }
- buflen = *len;
+ fprintf(stderr, "%s: malloc failed\n", __func__);
+ exit(EXIT_FAILURE);
}
+ buflen = *len;
dest = buf;
while (src < end) {
@@ -502,16 +485,16 @@ setup_pattern(const char *pattern, size_t *len)
*
* Parse a C escape sequence. STRING_PTR points to a variable containing a
* pointer to the string to parse. That pointer is updated past the
- * characters we use. The value of the escape sequence is returned.
+ * characters we use. The value of the escape sequence is returned.
*
* A negative value means the sequence \ newline was seen, which is supposed to
- * be equivalent to nothing at all.
+ * be equivalent to nothing at all.
*
* If \ is followed by a null character, we return a negative value and leave
- * the string pointer pointing at the null character.
+ * the string pointer pointing at the null character.
*
* If \ is followed by 000, we return 0 and leave the string pointer after the
- * zeros. A value of 0 does not mean end of string.
+ * zeros. A value of 0 does not mean end of string.
*
* POSIX doesn't allow \x.
*/
@@ -600,7 +583,7 @@ parse_escape(const char **string_ptr)
#ifdef C
#undef C
#endif
-#define C(c) ((char)c)
+#define C(c) ((char)c)
/*
* This table is used by the regexp routines to do case independent
* matching. Basically, every ascii character maps to itself, except
@@ -740,343 +723,3 @@ char casetable[] = {
#endif
#undef C
-
-#ifdef GREP_DFA /* not needed for gawk */
-/* xalloc.h -- malloc with out-of-memory checking
-
- Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2003, 2004, 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
- Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef XALLOC_H_
-# define XALLOC_H_
-
-# include <stddef.h>
-
-
-# ifdef __cplusplus
-extern "C" {
-# endif
-
-
-# ifndef __attribute__
-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
-# define __attribute__(x)
-# endif
-# endif
-
-# ifndef ATTRIBUTE_NORETURN
-# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
-# endif
-
-# ifndef ATTRIBUTE_MALLOC
-# if __GNUC__ >= 3
-# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
-# else
-# define ATTRIBUTE_MALLOC
-# endif
-# endif
-
-/* This function is always triggered when memory is exhausted.
- It must be defined by the application, either explicitly
- or by using gnulib's xalloc-die module. This is the
- function to call when one wants the program to die because of a
- memory allocation failure. */
-extern void xalloc_die (void);
-
-void *xmalloc (size_t s) ATTRIBUTE_MALLOC;
-void *xzalloc (size_t s) ATTRIBUTE_MALLOC;
-void *xcalloc (size_t n, size_t s) ATTRIBUTE_MALLOC;
-void *xrealloc (void *p, size_t s);
-void *x2realloc (void *p, size_t *pn);
-void *xmemdup (void const *p, size_t s) ATTRIBUTE_MALLOC;
-char *xstrdup (char const *str) ATTRIBUTE_MALLOC;
-
-/* Return 1 if an array of N objects, each of size S, cannot exist due
- to size arithmetic overflow. S must be positive and N must be
- nonnegative. This is a macro, not an inline function, so that it
- works correctly even when SIZE_MAX < N.
-
- By gnulib convention, SIZE_MAX represents overflow in size
- calculations, so the conservative dividend to use here is
- SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
- However, malloc (SIZE_MAX) fails on all known hosts where
- sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
- exactly-SIZE_MAX allocations on such hosts; this avoids a test and
- branch when S is known to be 1. */
-# define xalloc_oversized(n, s) \
- ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
-
-
-/* In the following macros, T must be an elementary or structure/union or
- typedef'ed type, or a pointer to such a type. To apply one of the
- following macros to a function pointer or array type, you need to typedef
- it first and use the typedef name. */
-
-/* Allocate an object of type T dynamically, with error checking. */
-/* extern t *XMALLOC (typename t); */
-# define XMALLOC(t) ((t *) xmalloc (sizeof (t)))
-
-/* Allocate memory for N elements of type T, with error checking. */
-/* extern t *XNMALLOC (size_t n, typename t); */
-# define XNMALLOC(n, t) \
- ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t))))
-
-/* Allocate an object of type T dynamically, with error checking,
- and zero it. */
-/* extern t *XZALLOC (typename t); */
-# define XZALLOC(t) ((t *) xzalloc (sizeof (t)))
-
-/* Allocate memory for N elements of type T, with error checking,
- and zero it. */
-/* extern t *XCALLOC (size_t n, typename t); */
-# define XCALLOC(n, t) \
- ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t))))
-
-/*
- * Gawk uses this file only to keep dfa.c happy.
- * We're therefore safe in manually defining HAVE_INLINE to
- * make the !@#$%^&*() thing just work.
- */
-#ifdef GAWK
-#define HAVE_INLINE 1 /* so there. nyah, nyah, nyah. */
-#endif
-
-# if HAVE_INLINE
-# define static_inline static inline
-# else
-void *xnmalloc (size_t n, size_t s) ATTRIBUTE_MALLOC;
-void *xnrealloc (void *p, size_t n, size_t s);
-void *x2nrealloc (void *p, size_t *pn, size_t s);
-char *xcharalloc (size_t n) ATTRIBUTE_MALLOC;
-# endif
-
-
-/* Allocate an array of N objects, each with S bytes of memory,
- dynamically, with error checking. S must be nonzero. */
-
-void *
-xnmalloc (size_t n, size_t s)
-{
- if (xalloc_oversized (n, s))
- xalloc_die ();
- return xmalloc (n * s);
-}
-
-/* Allocate an array of N objects, each with S bytes of memory,
- dynamically, with error checking. S must be nonzero.
- Clear the contents afterwards. */
-
-void *
-xcalloc(size_t nmemb, size_t size)
-{
- void *p = xmalloc (nmemb * size);
- memset(p, '\0', nmemb * size);
- return p;
-}
-
-/* Reallocate a pointer to a new size, with error checking. */
-
-void *
-xrealloc(void *p, size_t size)
-{
- void *new_p = realloc(p, size);
- if (new_p == 0)
- xalloc_die ();
-
- return new_p;
-}
-
-/* xalloc_die --- fatal error message when malloc fails, needed by dfa.c */
-
-void
-xalloc_die (void)
-{
- r_fatal("xalloc: malloc failed: %s"), strerror(errno);
-}
-
-/* Clone an object P of size S, with error checking. There's no need
- for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
- need for an arithmetic overflow check. */
-
-void *
-xmemdup (void const *p, size_t s)
-{
- return memcpy (xmalloc (s), p, s);
-}
-
-/* Change the size of an allocated block of memory P to an array of N
- objects each of S bytes, with error checking. S must be nonzero. */
-
-void *
-xnrealloc (void *p, size_t n, size_t s)
-{
- if (xalloc_oversized (n, s))
- xalloc_die ();
- return xrealloc (p, n * s);
-}
-
-/* If P is null, allocate a block of at least *PN such objects;
- otherwise, reallocate P so that it contains more than *PN objects
- each of S bytes. *PN must be nonzero unless P is null, and S must
- be nonzero. Set *PN to the new number of objects, and return the
- pointer to the new block. *PN is never set to zero, and the
- returned pointer is never null.
-
- Repeated reallocations are guaranteed to make progress, either by
- allocating an initial block with a nonzero size, or by allocating a
- larger block.
-
- In the following implementation, nonzero sizes are increased by a
- factor of approximately 1.5 so that repeated reallocations have
- O(N) overall cost rather than O(N**2) cost, but the
- specification for this function does not guarantee that rate.
-
- Here is an example of use:
-
- int *p = NULL;
- size_t used = 0;
- size_t allocated = 0;
-
- void
- append_int (int value)
- {
- if (used == allocated)
- p = x2nrealloc (p, &allocated, sizeof *p);
- p[used++] = value;
- }
-
- This causes x2nrealloc to allocate a block of some nonzero size the
- first time it is called.
-
- To have finer-grained control over the initial size, set *PN to a
- nonzero value before calling this function with P == NULL. For
- example:
-
- int *p = NULL;
- size_t used = 0;
- size_t allocated = 0;
- size_t allocated1 = 1000;
-
- void
- append_int (int value)
- {
- if (used == allocated)
- {
- p = x2nrealloc (p, &allocated1, sizeof *p);
- allocated = allocated1;
- }
- p[used++] = value;
- }
-
- */
-
-void *
-x2nrealloc (void *p, size_t *pn, size_t s)
-{
- size_t n = *pn;
-
- if (! p)
- {
- if (! n)
- {
- /* The approximate size to use for initial small allocation
- requests, when the invoking code specifies an old size of
- zero. 64 bytes is the largest "small" request for the
- GNU C library malloc. */
- enum { DEFAULT_MXFAST = 64 };
-
- n = DEFAULT_MXFAST / s;
- n += !n;
- }
- }
- else
- {
- /* Set N = ceil (1.5 * N) so that progress is made if N == 1.
- Check for overflow, so that N * S stays in size_t range.
- The check is slightly conservative, but an exact check isn't
- worth the trouble. */
- if ((size_t) -1 / 3 * 2 / s <= n)
- xalloc_die ();
- n += (n + 1) / 2;
- }
-
- *pn = n;
- return xrealloc (p, n * s);
-}
-
-/* Return a pointer to a new buffer of N bytes. This is like xmalloc,
- except it returns char *. */
-
-char *
-xcharalloc (size_t n)
-{
- return XNMALLOC (n, char);
-}
-
-/* Allocate S bytes of zeroed memory dynamically, with error checking.
- There's no need for xnzalloc (N, S), since it would be equivalent
- to xcalloc (N, S). */
-
-void *
-xzalloc (size_t s)
-{
- return memset (xmalloc (s), 0, s);
-}
-
-# endif
-
-# ifdef __cplusplus
-}
-
-/* C++ does not allow conversions from void * to other pointer types
- without a cast. Use templates to work around the problem when
- possible. */
-
-template <typename T> inline T *
-xrealloc (T *p, size_t s)
-{
- return (T *) xrealloc ((void *) p, s);
-}
-
-template <typename T> inline T *
-xnrealloc (T *p, size_t n, size_t s)
-{
- return (T *) xnrealloc ((void *) p, n, s);
-}
-
-template <typename T> inline T *
-x2realloc (T *p, size_t *pn)
-{
- return (T *) x2realloc ((void *) p, pn);
-}
-
-template <typename T> inline T *
-x2nrealloc (T *p, size_t *pn, size_t s)
-{
- return (T *) x2nrealloc ((void *) p, pn, s);
-}
-
-template <typename T> inline T *
-xmemdup (T const *p, size_t s)
-{
- return (T *) xmemdup ((void const *) p, s);
-}
-
-
-
-#endif /* !XALLOC_H_ */
-#endif /* GREP_DFA */
diff --git a/helpers/testnet.c b/helpers/testnet.c
index feda38b4..cbe2d97e 100644
--- a/helpers/testnet.c
+++ b/helpers/testnet.c
@@ -220,9 +220,9 @@ devopen(const char *name, const char *mode)
localpname = cp;
while (*cp != '/' && *cp != '\0')
cp++;
- /*
+ /*
* Require a port, let them explicitly put 0 if
- * they don't care.
+ * they don't care.
*/
if (*cp != '/' || cp == localpname) {
fprintf(stderr, _("special file name `%s' is incomplete"), name);
@@ -241,7 +241,7 @@ devopen(const char *name, const char *mode)
cp++;
hostname = cp;
while (*cp != '/' && *cp != '\0')
- cp++;
+ cp++;
if (*cp != '/' || cp == hostname) {
*localpnamelastcharp = '/';
fprintf(stderr, _("must supply a remote hostname to `/inet'"));
@@ -278,7 +278,7 @@ devopen(const char *name, const char *mode)
char *cp, *end;
unsigned long count = 0;
char *ms2;
-
+
first_time = false;
if ((cp = getenv("GAWK_SOCK_RETRIES")) != NULL) {
count = strtoul(cp, & end, 10);
diff --git a/helpers/update-branches.sh b/helpers/update-branches.sh
new file mode 100755
index 00000000..b08e1f16
--- /dev/null
+++ b/helpers/update-branches.sh
@@ -0,0 +1,37 @@
+#! /bin/sh
+
+if [ ! -d .git ]
+then
+ echo you must run this script from the top level directory
+ exit 1
+fi
+
+doit () {
+ echo "
+ Running: $@"
+ "$@" || {
+ echo "Oops: command [$@] failed with status $?"
+ return 1
+ }
+}
+
+doit git checkout master || exit
+
+features=$(git branch -a | grep /origin/feature/ | sed 's;.*/origin/;;')
+others="porting"
+
+for i in $others $features
+do
+ echo "
+ Updating branch $i"
+ (doit git checkout $i && doit git pull && doit git merge master && doit git push) || {
+ echo "
+Error encountered updating branch $i.
+Please resolve the conflict and push it manually in a separate window.
+Please hit enter when you are done so we may continue to merge into
+the other branches."
+ read x
+ }
+done
+
+doit git checkout master
diff --git a/install-sh b/install-sh
index 0b0fdcbb..0360b79e 100755
--- a/install-sh
+++ b/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2013-12-25.23; # UTC
+scriptversion=2016-01-11.22; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -496,6 +496,6 @@ done
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/int_array.c b/int_array.c
index 6cffec86..1c309cfd 100644
--- a/int_array.c
+++ b/int_array.c
@@ -2,23 +2,23 @@
* int_array.c - routines for arrays of integer indices.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2013, 2016,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -167,49 +167,53 @@ is_integer(NODE *symbol, NODE *subs)
* a[-3]=1; print "-3" in a -- true
*/
- if ((subs->flags & (STRING|STRCUR)) != 0) {
- char *cp = subs->stptr, *cpend, *ptr;
- char save;
- size_t len = subs->stlen;
+ /* must be a STRING */
+ char *cp = subs->stptr, *cpend, *ptr;
+ char save;
+ size_t len = subs->stlen;
- if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-'))
- return NULL;
- if (len > 1 &&
- ((*cp == '0') /* "00", "011" .. */
- || (*cp == '-' && *(cp + 1) == '0') /* "-0", "-011" .. */
- )
+ if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-'))
+ return NULL;
+
+ if (len > 1 &&
+ ((*cp == '0') /* "00", "011" .. */
+ || (*cp == '-' && *(cp + 1) == '0') /* "-0", "-011" .. */
)
- return NULL;
- if (len == 1 && *cp != '-') { /* single digit */
- subs->numbr = (long) (*cp - '0');
- if ((subs->flags & MAYBE_NUM) != 0) {
- subs->flags &= ~MAYBE_NUM;
- subs->flags |= NUMBER;
- }
- subs->flags |= (NUMCUR|NUMINT);
- return & success_node;
+ )
+ return NULL;
+ if (len == 1 && *cp != '-') { /* single digit */
+ subs->numbr = (long) (*cp - '0');
+ if ((subs->flags & USER_INPUT) != 0) {
+ /* leave USER_INPUT set */
+ subs->flags &= ~STRING;
+ subs->flags |= NUMBER;
}
+ subs->flags |= (NUMCUR|NUMINT);
+ return & success_node;
+ }
- cpend = cp + len;
- save = *cpend;
- *cpend = '\0';
+ cpend = cp + len;
+ save = *cpend;
+ *cpend = '\0';
- errno = 0;
- l = strtol(cp, & ptr, 10);
- *cpend = save;
- if (errno != 0 || ptr != cpend)
- return NULL;
- subs->numbr = l;
- if ((subs->flags & MAYBE_NUM) != 0) {
- subs->flags &= ~MAYBE_NUM;
- subs->flags |= NUMBER;
- }
- subs->flags |= NUMCUR;
- if (l <= INT32_MAX && l >= INT32_MIN) {
- subs->flags |= NUMINT;
- return & success_node;
- }
+ errno = 0;
+ l = strtol(cp, & ptr, 10);
+ *cpend = save;
+ if (errno != 0 || ptr != cpend)
+ return NULL;
+
+ subs->numbr = l;
+ if ((subs->flags & USER_INPUT) != 0) {
+ /* leave USER_INPUT set */
+ subs->flags &= ~STRING;
+ subs->flags |= NUMBER;
}
+ subs->flags |= NUMCUR;
+ if (l <= INT32_MAX && l >= INT32_MIN) {
+ subs->flags |= NUMINT;
+ return & success_node;
+ }
+
return NULL;
#endif /* CHECK_INTEGER_USING_FORCE_NUMBER */
}
@@ -238,7 +242,7 @@ int_lookup(NODE *symbol, NODE *subs)
if (! is_integer(symbol, subs)) {
- xn = symbol->xarray;
+ xn = symbol->xarray;
if (xn == NULL) {
xn = symbol->xarray = make_array();
xn->vname = symbol->vname; /* shallow copy */
@@ -256,9 +260,9 @@ int_lookup(NODE *symbol, NODE *subs)
hash1 = int_hash(k, symbol->array_size);
if ((lhs = int_find(symbol, k, hash1)) != NULL)
return lhs;
-
+
/* It's not there, install it */
-
+
symbol->table_size++;
/* first see if we would need to grow the array, before installing */
@@ -272,7 +276,7 @@ int_lookup(NODE *symbol, NODE *subs)
/* have to recompute hash value for new size */
hash1 = int_hash(k, symbol->array_size);
}
-
+
return int_insert(symbol, k, hash1);
}
@@ -326,7 +330,7 @@ int_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
r = b->aivalue[j];
if (r->type == Node_var_array) {
assoc_clear(r); /* recursively clear all sub-arrays */
- efree(r->vname);
+ efree(r->vname);
freenode(r);
} else
unref(r);
@@ -452,10 +456,9 @@ int_copy(NODE *symbol, NODE *newsymb)
/* find the current hash size */
cursize = symbol->array_size;
-
+
/* allocate new table */
- emalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "int_copy");
- memset(new, '\0', cursize * sizeof(BUCKET *));
+ ezalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "int_copy");
old = symbol->buckets;
@@ -491,7 +494,7 @@ int_copy(NODE *symbol, NODE *newsymb)
newchain->ainext = NULL;
pnew = & newchain->ainext;
}
- }
+ }
if (symbol->xarray != NULL) {
NODE *xn, *n;
@@ -537,7 +540,7 @@ int_list(NODE *symbol, NODE *t)
if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
elem_size = 2;
list_size = elem_size * num_elems;
-
+
if (symbol->xarray != NULL) {
xn = symbol->xarray;
list = xn->alist(xn, t);
@@ -557,7 +560,7 @@ int_list(NODE *symbol, NODE *t)
/* index */
num = b->ainum[j];
if ((assoc_kind & AISTR) != 0) {
- sprintf(buf, "%ld", num);
+ sprintf(buf, "%ld", num);
subs = make_string(buf, strlen(buf));
subs->numbr = num;
subs->flags |= (NUMCUR|NUMINT);
@@ -602,7 +605,7 @@ int_kilobytes(NODE *symbol)
for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
bucket_cnt++;
}
- kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
+ kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
if (symbol->xarray != NULL)
@@ -736,7 +739,7 @@ int_hash(uint32_t k, uint32_t hsize)
*/
/* This is the final mixing function used by Paul Hsieh in SuperFastHash. */
-
+
k ^= k << 3;
k += k >> 5;
k ^= k << 4;
@@ -778,7 +781,7 @@ int_insert(NODE *symbol, long k, uint32_t hash1)
b = symbol->buckets[hash1];
- /* Only the first bucket in the chain can be partially full, but is never empty. */
+ /* Only the first bucket in the chain can be partially full, but is never empty. */
if (b == NULL || (i = b->aicount) == 2) {
getbucket(b);
@@ -818,7 +821,7 @@ grow_int_table(NODE *symbol)
static const unsigned long sizes[] = {
13, 127, 1021, 8191, 16381, 32749, 65497,
131101, 262147, 524309, 1048583, 2097169,
- 4194319, 8388617, 16777259, 33554467,
+ 4194319, 8388617, 16777259, 33554467,
67108879, 134217757, 268435459, 536870923,
1073741827
};
@@ -838,8 +841,7 @@ grow_int_table(NODE *symbol)
}
/* allocate new table */
- emalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_int_table");
- memset(new, '\0', newsize * sizeof(BUCKET *));
+ ezalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_int_table");
old = symbol->buckets;
symbol->buckets = new;
diff --git a/interpret.h b/interpret.h
index bb7cba96..ec6a3dda 100644
--- a/interpret.h
+++ b/interpret.h
@@ -7,26 +7,35 @@
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+/*
+ * If "r" is a field, valref should normally be > 1, because the field is
+ * created initially with valref 1, and valref should be bumped when it is
+ * pushed onto the stack by Op_field_spec. On the other hand, if we are
+ * assigning to $n, then Op_store_field calls unref(*lhs) before assigning
+ * the new value, so that decrements valref. So if the RHS is a field with
+ * valref 1, that effectively means that this is an assignment like "$n = $n",
+ * so a no-op, other than triggering $0 reconstitution.
+ */
#define UNFIELD(l, r) \
{ \
/* if was a field, turn it into a var */ \
- if ((r->flags & FIELD) == 0 || r->valref == 1) { \
+ if ((r->flags & MALLOC) != 0 || r->valref == 1) { \
l = r; \
} else { \
l = dupnode(r); \
@@ -96,7 +105,7 @@ top:
/* avoid false source indications */
source = NULL;
sourceline = 0;
- (void) nextfile(& curfile, true); /* close input data file */
+ (void) nextfile(& curfile, true); /* close input data file */
/*
* This used to be:
*
@@ -141,6 +150,7 @@ top:
case Op_push:
case Op_push_arg:
+ case Op_push_arg_untyped:
{
NODE *save_symbol;
bool isparam = false;
@@ -157,7 +167,7 @@ top:
m = m->orig_array;
}
}
-
+
switch (m->type) {
case Node_var:
if (do_lint && var_uninitialized(m))
@@ -172,19 +182,23 @@ top:
case Node_var_new:
uninitialized_scalar:
- m->type = Node_var;
- m->var_value = dupnode(Nnull_string);
+ if (op != Op_push_arg_untyped) {
+ /* convert untyped to scalar */
+ m->type = Node_var;
+ m->var_value = dupnode(Nnull_string);
+ }
if (do_lint)
lintwarn(isparam ?
_("reference to uninitialized argument `%s'") :
_("reference to uninitialized variable `%s'"),
save_symbol->vname);
- m = dupnode(Nnull_string);
+ if (op != Op_push_arg_untyped)
+ m = dupnode(Nnull_string);
PUSH(m);
break;
case Node_var_array:
- if (op == Op_push_arg)
+ if (op == Op_push_arg || op == Op_push_arg_untyped)
PUSH(m);
else
fatal(_("attempt to use array `%s' in a scalar context"),
@@ -195,7 +209,7 @@ uninitialized_scalar:
cant_happen();
}
}
- break;
+ break;
case Op_push_param: /* function argument */
m = pc->memory;
@@ -233,7 +247,7 @@ uninitialized_scalar:
/* for FUNCTAB, get the name as the element value */
if (t1 == func_table) {
static bool warned = false;
-
+
if (do_lint && ! warned) {
warned = true;
lintwarn(_("FUNCTAB is a gawk extension"));
@@ -251,7 +265,7 @@ uninitialized_scalar:
/* for SYMTAB, step through to the actual variable */
if (t1 == symbol_table) {
static bool warned = false;
-
+
if (do_lint && ! warned) {
warned = true;
lintwarn(_("SYMTAB is a gawk extension"));
@@ -296,7 +310,7 @@ uninitialized_scalar:
t1 = POP_ARRAY();
if (do_lint && in_array(t1, t2) == NULL) {
t2 = force_string(t2);
- if (pc->do_reference)
+ if (pc->do_reference)
lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
array_vname(t1), (int) t2->stlen, t2->stptr);
if (t2->stlen == 0)
@@ -349,12 +363,8 @@ uninitialized_scalar:
lhs = r_get_field(t1, (Func_ptr *) 0, true);
decr_sp();
DEREF(t1);
- /* only for $0, up ref count */
- if (*lhs == fields_arr[0]) {
- r = *lhs;
- UPREF(r);
- } else
- r = dupnode(*lhs);
+ r = *lhs;
+ UPREF(r);
PUSH(r);
break;
@@ -400,7 +410,7 @@ uninitialized_scalar:
case Op_jmp_true:
r = POP_SCALAR();
di = eval_condition(r);
- DEREF(r);
+ DEREF(r);
if (di)
JUMPTO(pc->target_jmp);
break;
@@ -436,37 +446,37 @@ uninitialized_scalar:
break;
case Op_equal:
- r = node_Boolean[cmp_scalars() == 0];
+ r = node_Boolean[cmp_scalars(SCALAR_EQ_NEQ) == 0];
UPREF(r);
REPLACE(r);
break;
case Op_notequal:
- r = node_Boolean[cmp_scalars() != 0];
+ r = node_Boolean[cmp_scalars(SCALAR_EQ_NEQ) != 0];
UPREF(r);
REPLACE(r);
break;
case Op_less:
- r = node_Boolean[cmp_scalars() < 0];
+ r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) < 0];
UPREF(r);
REPLACE(r);
break;
case Op_greater:
- r = node_Boolean[cmp_scalars() > 0];
+ r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) > 0];
UPREF(r);
REPLACE(r);
break;
case Op_leq:
- r = node_Boolean[cmp_scalars() <= 0];
+ r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) <= 0];
UPREF(r);
REPLACE(r);
break;
case Op_geq:
- r = node_Boolean[cmp_scalars() >= 0];
+ r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) >= 0];
UPREF(r);
REPLACE(r);
break;
@@ -491,7 +501,7 @@ plus:
case Op_minus:
t2 = POP_NUMBER();
x2 = t2->numbr;
- DEREF(t2);
+ DEREF(t2);
minus:
t1 = TOP_NUMBER();
r = make_number(t1->numbr - x2);
@@ -541,7 +551,7 @@ quotient:
r = make_number(t1->numbr / x2);
DEREF(t1);
REPLACE(r);
- break;
+ break;
case Op_mod_i:
x2 = force_number(pc->memory)->numbr;
@@ -608,6 +618,11 @@ mod:
REPLACE(r);
break;
+ case Op_unary_plus:
+ // Force argument to be numeric
+ t1 = TOP_NUMBER();
+ break;
+
case Op_store_sub:
/*
* array[sub] assignment optimization,
@@ -660,7 +675,7 @@ mod:
* simple variable assignment optimization,
* see awkgram.y (optimize_assignment)
*/
-
+
lhs = get_lhs(pc->memory, false);
unref(*lhs);
r = pc->initval; /* constant initializer */
@@ -703,37 +718,39 @@ mod:
*lhs = dupnode(t1);
}
- if (t1 != t2 && t1->valref == 1 && (t1->flags & (MPFN|MPZN)) == 0) {
+ if (t1 != t2 && t1->valref == 1 && (t1->flags & (MALLOC|MPFN|MPZN)) == MALLOC) {
size_t nlen = t1->stlen + t2->stlen;
- erealloc(t1->stptr, char *, nlen + 2, "r_interpret");
+ erealloc(t1->stptr, char *, nlen + 1, "r_interpret");
memcpy(t1->stptr + t1->stlen, t2->stptr, t2->stlen);
t1->stlen = nlen;
t1->stptr[nlen] = '\0';
- t1->flags &= ~(NUMCUR|NUMBER|MAYBE_NUM|NUMINT|INTIND);
- t1->flags |= (STRING|STRCUR);
- t1->stfmt = -1;
+ /* clear flags except WSTRCUR (used below) */
+ t1->flags &= WSTRCUR;
+ /* configure as a string as in make_str_node */
+ t1->flags |= (MALLOC|STRING|STRCUR);
+ t1->stfmt = STFMT_UNUSED;
if ((t1->flags & WSTRCUR) != 0 && (t2->flags & WSTRCUR) != 0) {
size_t wlen = t1->wstlen + t2->wstlen;
erealloc(t1->wstptr, wchar_t *,
- sizeof(wchar_t) * (wlen + 2), "r_interpret");
- memcpy(t1->wstptr + t1->wstlen, t2->wstptr, t2->wstlen);
+ sizeof(wchar_t) * (wlen + 1), "r_interpret");
+ memcpy(t1->wstptr + t1->wstlen, t2->wstptr, t2->wstlen * sizeof(wchar_t));
t1->wstlen = wlen;
t1->wstptr[wlen] = L'\0';
- t1->flags |= WSTRCUR;
} else
free_wstr(*lhs);
} else {
- size_t nlen = t1->stlen + t2->stlen;
+ size_t nlen = t1->stlen + t2->stlen;
char *p;
- emalloc(p, char *, nlen + 2, "r_interpret");
+ emalloc(p, char *, nlen + 1, "r_interpret");
memcpy(p, t1->stptr, t1->stlen);
memcpy(p + t1->stlen, t2->stptr, t2->stlen);
+ /* N.B. No NUL-termination required, since make_str_node will do it. */
unref(*lhs);
- t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED);
+ t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED);
}
DEREF(t2);
break;
@@ -748,7 +765,7 @@ mod:
break;
case Op_subscript_assign:
- /* conditionally execute post-assignment routine for an array element */
+ /* conditionally execute post-assignment routine for an array element */
if (set_idx != NULL) {
di = true;
@@ -825,12 +842,11 @@ mod:
t2 = TOP_SCALAR(); /* switch expression */
t2 = force_string(t2);
rp = re_update(m);
- di = (research(rp, t2->stptr, 0, t2->stlen,
- avoid_dfa(m, t2->stptr, t2->stlen)) >= 0);
+ di = (research(rp, t2->stptr, 0, t2->stlen, RE_NO_FLAGS) >= 0);
} else {
t1 = POP_SCALAR(); /* case value */
t2 = TOP_SCALAR(); /* switch expression */
- di = (cmp_nodes(t2, t1) == 0);
+ di = (cmp_nodes(t2, t1, true) == 0);
DEREF(t1);
}
@@ -870,6 +886,8 @@ mod:
size_t num_elems = 0;
static NODE *sorted_in = NULL;
const char *how_to_sort = "@unsorted";
+ char save;
+ bool saved_end = false;
/* get the array */
array = POP_ARRAY();
@@ -892,11 +910,16 @@ mod:
if (sort_str != NULL) {
sort_str = force_string(sort_str);
- if (sort_str->stlen > 0)
+ if (sort_str->stlen > 0) {
how_to_sort = sort_str->stptr;
+ str_terminate(sort_str, save);
+ saved_end = true;
+ }
}
list = assoc_list(array, how_to_sort, SORTED_IN);
+ if (saved_end)
+ str_restore(sort_str, save);
arrayfor:
getnode(r);
@@ -941,22 +964,30 @@ arrayfor:
break;
case Op_ext_builtin:
- case Op_old_ext_builtin:
{
- int arg_count = pc->expr_count;
+ size_t arg_count = pc->expr_count;
+ awk_ext_func_t *f = pc[1].c_func;
+ size_t min_req = f->min_required_args;
+ size_t max_expect = f->max_expected_args;
awk_value_t result;
+ if (arg_count < min_req)
+ fatal(_("%s: called with %lu arguments, expecting at least %lu"),
+ pc[1].func_name, arg_count, min_req);
+
+ if (do_lint && ! f->suppress_lint && arg_count > max_expect)
+ lintwarn(_("%s: called with %lu arguments, expecting no more than %lu"),
+ pc[1].func_name, arg_count, max_expect);
+
PUSH_CODE(pc);
- if (op == Op_ext_builtin)
- r = awk_value_to_node(pc->extfunc(arg_count, & result));
- else
- r = pc->builtin(arg_count);
+ r = awk_value_to_node(pc->extfunc(arg_count, & result, f));
(void) POP_CODE();
while (arg_count-- > 0) {
t1 = POP();
if (t1->type == Node_val)
DEREF(t1);
}
+ free_api_string_copies();
PUSH(r);
}
break;
@@ -984,29 +1015,19 @@ arrayfor:
r = POP_STRING();
unref(m->re_exp);
m->re_exp = r;
+ } else if (m->type == Node_val) {
+ assert((m->flags & REGEX) != 0);
+ UPREF(m);
}
PUSH(m);
break;
-
+
case Op_match_rec:
m = pc->memory;
t1 = *get_field(0, (Func_ptr *) 0);
match_re:
rp = re_update(m);
- /*
- * Any place where research() is called with a last parameter of
- * zero, we need to use the avoid_dfa test. This appears here and
- * in the code for Op_K_case.
- *
- * A new or improved dfa that distinguishes beginning/end of
- * string from beginning/end of line will allow us to get rid of
- * this hack.
- *
- * The avoid_dfa() function is in re.c; it is not very smart.
- */
-
- di = research(rp, t1->stptr, 0, t1->stlen,
- avoid_dfa(m, t1->stptr, t1->stlen));
+ di = research(rp, t1->stptr, 0, t1->stlen, RE_NO_FLAGS);
di = (di == -1) ^ (op != Op_nomatch);
if (op != Op_match_rec) {
decr_sp();
@@ -1035,6 +1056,7 @@ match_re:
{
NODE *f = NULL;
int arg_count;
+ char save;
arg_count = (pc + 1)->expr_count;
t1 = PEEK(arg_count); /* indirect var */
@@ -1043,12 +1065,14 @@ match_re:
fatal(_("indirect function call requires a simple scalar value"));
t1 = force_string(t1);
+ str_terminate(t1, save);
if (t1->stlen > 0) {
/* retrieve function definition node */
f = pc->func_body;
if (f != NULL && strcmp(f->vname, t1->stptr) == 0) {
/* indirect var hasn't been reassigned */
+ str_restore(t1, save);
ni = setup_frame(pc);
JUMPTO(ni); /* Op_func */
}
@@ -1061,7 +1085,7 @@ match_re:
} 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 */
@@ -1073,12 +1097,13 @@ match_re:
r = call_split_func(t1->stptr, arg_count);
else
r = the_func(arg_count);
+ str_restore(t1, save);
PUSH(r);
break;
} else if (f->type != Node_func) {
- if ( f->type == Node_ext_func
- || f->type == Node_old_ext_func) {
+ str_restore(t1, save);
+ if (f->type == Node_ext_func) {
/* code copied from below, keep in sync */
INSTRUCTION *bc;
char *fname = pc->func_name;
@@ -1089,22 +1114,20 @@ match_re:
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].opcode = Op_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;
+ npc[1].c_func = bc->c_func;
+ ni = npc;
JUMPTO(ni);
} else
fatal(_("function called indirectly through `%s' does not exist"),
- pc->func_name);
+ pc->func_name);
}
pc->func_body = f; /* save for next call */
+ str_restore(t1, save);
ni = setup_frame(pc);
JUMPTO(ni); /* Op_func */
@@ -1118,12 +1141,12 @@ match_re:
f = pc->func_body;
if (f == NULL) {
f = lookup(pc->func_name);
- if (f == NULL || (f->type != Node_func && f->type != Node_ext_func && f->type != Node_old_ext_func))
+ if (f == NULL || (f->type != Node_func && f->type != Node_ext_func))
fatal(_("function `%s' not defined"), pc->func_name);
pc->func_body = f; /* save for next call */
}
- if (f->type == Node_ext_func || f->type == Node_old_ext_func) {
+ if (f->type == Node_ext_func) {
/* keep in sync with indirect call code */
INSTRUCTION *bc;
char *fname = pc->func_name;
@@ -1131,15 +1154,12 @@ match_re:
bc = f->code_ptr;
assert(bc->opcode == Op_symbol);
- if (f->type == Node_ext_func)
- pc->opcode = Op_ext_builtin; /* self modifying code */
- else
- pc->opcode = Op_old_ext_builtin; /* self modifying code */
+ pc->opcode = Op_ext_builtin; /* self modifying code */
pc->extfunc = bc->extfunc;
- pc->expr_count = arg_count; /* actual argument count */
+ pc->expr_count = arg_count; /* actual argument count */
(pc + 1)->func_name = fname; /* name of the builtin */
- (pc + 1)->expr_count = bc->expr_count; /* defined max # of arguments */
- ni = pc;
+ (pc + 1)->c_func = bc->c_func; /* min and max args */
+ ni = pc;
JUMPTO(ni);
}
@@ -1151,7 +1171,7 @@ match_re:
m = POP_SCALAR(); /* return value */
ni = pop_fcall();
-
+
/* put the return value back on stack */
PUSH(m);
@@ -1176,7 +1196,7 @@ match_re:
/* Save execution state so that we can return to it
* from Op_after_beginfile or Op_after_endfile.
- */
+ */
push_exec_state(pc, currule, source, stack_ptr);
@@ -1234,8 +1254,8 @@ match_re:
execute beginfile block */
}
break;
-
- case Op_get_record:
+
+ case Op_get_record:
{
int errcode = 0;
@@ -1293,13 +1313,13 @@ match_re:
JUMPTO(ni);
} else {
/* do run ENDFILE block(s) first. */
-
+
/* Execution state to return to in Op_after_endfile. */
push_exec_state(ni, currule, source, stack_ptr);
JUMPTO(pc->target_endfile);
- }
- } /* else
+ }
+ } /* else
Start over with the first rule. */
/* empty the run-time stack to avoid memory leak */
@@ -1390,7 +1410,7 @@ match_re:
/* not already triggered and left expression is true */
decr_sp();
ip->triggered = true;
- JUMPTO(ip->target_jmp); /* evaluate right expression */
+ JUMPTO(ip->target_jmp); /* evaluate right expression */
}
result = ip->triggered || di;
@@ -1416,6 +1436,8 @@ match_re:
case Op_K_if:
case Op_K_else:
case Op_cond_exp:
+ case Op_comment:
+ case Op_parens:
break;
default:
diff --git a/io.c b/io.c
index 2dbc07a6..02278551 100644
--- a/io.c
+++ b/io.c
@@ -2,23 +2,23 @@
* io.c --- routines for dealing with input and output and records
*/
-/*
- * Copyright (C) 1986, 1988, 1989, 1991-2016,
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-2017,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -191,7 +191,7 @@
#define setsid() /* nothing */
#endif /* HAVE_SETSID */
-#if defined(GAWK_AIX)
+#if defined(_AIX)
#undef TANDEM /* AIX defines this in one of its header files */
#endif
@@ -264,7 +264,6 @@ struct recmatch {
static int iop_close(IOBUF *iop);
-struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg);
static void close_one(void);
static int close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how);
#ifndef PIPES_SIMULATED
@@ -275,8 +274,8 @@ static IOBUF *iop_alloc(int fd, const char *name, int errno_val);
static IOBUF *iop_finish(IOBUF *iop);
static int gawk_pclose(struct redirect *rp);
static int str2mode(const char *mode);
-static int two_way_open(const char *str, struct redirect *rp);
-static int pty_vs_pipe(const char *command);
+static int two_way_open(const char *str, struct redirect *rp, int extfd);
+static bool pty_vs_pipe(const char *command);
static void find_input_parser(IOBUF *iop);
static bool find_output_wrapper(awk_output_buf_t *outbuf);
static void init_output_wrapper(awk_output_buf_t *outbuf);
@@ -288,7 +287,7 @@ static RECVALUE rsrescan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state);
static RECVALUE (*matchrec)(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) = rs1scan;
-static int get_a_record(char **out, IOBUF *iop, int *errcode);
+static int get_a_record(char **out, IOBUF *iop, int *errcode, const awk_fieldwidth_info_t **field_width);
static void free_rp(struct redirect *rp);
@@ -307,7 +306,7 @@ struct inet_socket_info {
} localport, remotehost, remoteport;
};
-static bool inetfile(const char *str, struct inet_socket_info *isn);
+static bool inetfile(const char *str, size_t len, struct inet_socket_info *isn);
static NODE *in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx);
static long get_read_timeout(IOBUF *iop);
@@ -319,10 +318,11 @@ static long read_default_timeout;
static struct redirect *red_head = NULL;
static NODE *RS = NULL;
-static Regexp *RS_re_yes_case; /* regexp for RS when ignoring case */
-static Regexp *RS_re_no_case; /* regexp for RS when not ignoring case */
+static Regexp *RS_re[2]; /* index 0 - don't ignore case, index 1, do */
static Regexp *RS_regexp;
+static const char nonfatal[] = "NONFATAL";
+
bool RS_is_null;
extern NODE *ARGC_node;
@@ -356,7 +356,7 @@ init_io()
* PROCINFO entries for timeout are dynamic;
* We can't be any more specific than this.
*/
- if (PROCINFO_node != NULL)
+ if (PROCINFO_node != NULL)
read_can_timeout = true;
}
@@ -416,7 +416,7 @@ after_beginfile(IOBUF **curfile)
bool valid;
fname = iop->public.name;
- errcode = iop->errcode;
+ errcode = iop->errcode;
valid = iop->valid;
errno = 0;
update_ERRNO_int(errcode);
@@ -465,12 +465,12 @@ nextfile(IOBUF **curfile, bool skipping)
(void) iop_close(iop);
*curfile = NULL;
return 1; /* run endfile block */
- } else
+ } else
return 0;
}
argc = get_number_si(ARGC_node->var_value);
-
+
for (; i < argc; i++) {
tmp = make_number((AWKNUM) i);
(void) force_string(tmp);
@@ -479,7 +479,6 @@ nextfile(IOBUF **curfile, bool skipping)
if (arg == NULL || arg->stlen == 0)
continue;
arg = force_string(arg);
- arg->stptr[arg->stlen] = '\0';
if (! do_traditional) {
unref(ARGIND_node->var_value);
ARGIND_node->var_value = make_number((AWKNUM) i);
@@ -533,7 +532,7 @@ nextfile(IOBUF **curfile, bool skipping)
unref(FILENAME_node->var_value);
FILENAME_node->var_value = make_string("-", 1);
- FILENAME_node->var_value->flags |= MAYBE_NUM; /* be pedantic */
+ FILENAME_node->var_value->flags |= USER_INPUT; /* be pedantic */
fname = "-";
iop = iop_alloc(fileno(stdin), fname, 0);
*curfile = iop_finish(iop);
@@ -591,20 +590,22 @@ inrec(IOBUF *iop, int *errcode)
char *begin;
int cnt;
bool retval = true;
+ const awk_fieldwidth_info_t *field_width = NULL;
if (at_eof(iop) && no_data_left(iop))
cnt = EOF;
else if ((iop->flag & IOP_CLOSED) != 0)
cnt = EOF;
- else
- cnt = get_a_record(& begin, iop, errcode);
+ else
+ cnt = get_a_record(& begin, iop, errcode, & field_width);
- if (cnt == EOF) {
+ /* Note that get_a_record may return -2 when I/O would block */
+ if (cnt < 0) {
retval = false;
} else {
INCREMENT_REC(NR);
INCREMENT_REC(FNR);
- set_record(begin, cnt);
+ set_record(begin, cnt, field_width);
if (*errcode > 0)
retval = false;
}
@@ -727,13 +728,13 @@ redflags2str(int flags)
return genflags2str(flags, redtab);
}
-/* redirect --- Redirection for printf and print commands */
+/* redirect_string --- Redirection for printf and print commands, use string info */
struct redirect *
-redirect(NODE *redir_exp, int redirtype, int *errflg)
+redirect_string(const char *str, size_t explen, bool not_string,
+ int redirtype, int *errflg, int extfd, bool failure_fatal)
{
struct redirect *rp;
- char *str;
int tflag = 0;
int outflag = 0;
const char *direction = "to";
@@ -782,27 +783,25 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
default:
cant_happen();
}
- if (do_lint && (redir_exp->flags & STRCUR) == 0)
- lintwarn(_("expression in `%s' redirection only has numeric value"),
+ if (do_lint && not_string)
+ lintwarn(_("expression in `%s' redirection is a number"),
what);
- redir_exp = force_string(redir_exp);
- str = redir_exp->stptr;
- if (str == NULL || *str == '\0')
+ if (explen < 1 || str == NULL || *str == '\0')
fatal(_("expression for `%s' redirection has null string value"),
what);
- if (do_lint && (strncmp(str, "0", redir_exp->stlen) == 0
- || strncmp(str, "1", redir_exp->stlen) == 0))
- lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"),
- str, what);
+ if (do_lint && (strncmp(str, "0", explen) == 0
+ || strncmp(str, "1", explen) == 0))
+ lintwarn(_("filename `%.*s' for `%s' redirection may be result of logical expression"),
+ (int) explen, str, what);
#ifdef HAVE_SOCKETS
/*
* Use /inet4 to force IPv4, /inet6 to force IPv6, and plain
* /inet will be whatever we get back from the system.
*/
- if (inetfile(str, & isi)) {
+ if (inetfile(str, explen, & isi)) {
tflag |= RED_SOCKET;
if (isi.protocol == SOCK_STREAM)
tflag |= RED_TCP; /* use shutdown when closing */
@@ -831,8 +830,8 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
#endif /* PIPES_SIMULATED */
/* now check for a match */
- if (strlen(rp->value) == redir_exp->stlen
- && memcmp(rp->value, str, redir_exp->stlen) == 0
+ if (strlen(rp->value) == explen
+ && memcmp(rp->value, str, explen) == 0
&& ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag
|| (outflag != 0
&& (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
@@ -843,23 +842,25 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
if (do_lint && rpflag != newflag)
lintwarn(
_("unnecessary mixing of `>' and `>>' for file `%.*s'"),
- (int) redir_exp->stlen, rp->value);
+ (int) explen, rp->value);
break;
}
}
if (rp == NULL) {
+ char *newstr;
new_rp = true;
if (save_rp != NULL) {
rp = save_rp;
efree(rp->value);
} else
emalloc(rp, struct redirect *, sizeof(struct redirect), "redirect");
- emalloc(str, char *, redir_exp->stlen + 1, "redirect");
- memcpy(str, redir_exp->stptr, redir_exp->stlen);
- str[redir_exp->stlen] = '\0';
- rp->value = str;
+ emalloc(newstr, char *, explen + 1, "redirect");
+ memcpy(newstr, str, explen);
+ newstr[explen] = '\0';
+ str = newstr;
+ rp->value = newstr;
rp->flag = tflag;
init_output_wrapper(& rp->output);
rp->output.name = str;
@@ -891,25 +892,35 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
mode = binmode("a");
break;
case redirect_pipe:
+ if (extfd >= 0) {
+ warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd);
+ return NULL;
+ }
/* synchronize output before new pipe */
(void) flush_io();
os_restore_mode(fileno(stdin));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_DFL);
-#endif
+ set_sigpipe_to_default();
+ /*
+ * Don't check failure_fatal; see input pipe below.
+ * Note that the failure happens upon failure to fork,
+ * using a non-existant program will still succeed the
+ * popen().
+ */
if ((rp->output.fp = popen(str, binmode("w"))) == NULL)
fatal(_("can't open pipe `%s' for output (%s)"),
str, strerror(errno));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
/* set close-on-exec */
os_close_on_exec(fileno(rp->output.fp), str, "pipe", "to");
rp->flag |= RED_NOBUF;
break;
case redirect_pipein:
+ if (extfd >= 0) {
+ warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd);
+ return NULL;
+ }
direction = "from";
if (gawk_popen(str, rp) == NULL)
fatal(_("can't open pipe `%s' for input (%s)"),
@@ -917,7 +928,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
break;
case redirect_input:
direction = "from";
- fd = devopen(str, binmode("r"));
+ fd = (extfd >= 0) ? extfd : devopen(str, binmode("r"));
if (fd == INVALID_HANDLE && errno == EISDIR) {
*errflg = EISDIR;
/* do not free rp, saving it for reuse (save_rp = rp) */
@@ -934,15 +945,19 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
}
break;
case redirect_twoway:
+#ifndef HAVE_SOCKETS
+ if (extfd >= 0) {
+ warning(_("get_file socket creation not supported on this platform for `%s' with fd %d"), str, extfd);
+ return NULL;
+ }
+#endif
direction = "to/from";
- if (! two_way_open(str, rp)) {
-#ifdef HAVE_SOCKETS
- if (inetfile(str, NULL)) {
+ if (! two_way_open(str, rp, extfd)) {
+ if (! failure_fatal || is_non_fatal_redirect(str, explen)) {
*errflg = errno;
/* do not free rp, saving it for reuse (save_rp = rp) */
return NULL;
} else
-#endif
fatal(_("can't open two way pipe `%s' for input/output (%s)"),
str, strerror(errno));
}
@@ -954,7 +969,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
if (mode != NULL) {
errno = 0;
rp->output.mode = mode;
- fd = devopen(str, mode);
+ fd = (extfd >= 0) ? extfd : devopen(str, mode);
if (fd > INVALID_HANDLE) {
if (fd == fileno(stdin))
@@ -1002,7 +1017,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
#ifdef VMS
/* Alpha/VMS V7.1+ C RTL is returning these instead
of EMFILE (haven't tried other post-V6.2 systems) */
- else if ((errno == EIO || errno == EVMSERR) &&
+ else if ((errno == EIO || errno == EVMSERR) &&
(vaxc$errno == SS$_EXQUOTA ||
vaxc$errno == SS$_EXBYTLM ||
vaxc$errno == RMS$_ACC ||
@@ -1020,11 +1035,14 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
* can return -1. For output to file,
* complain. The shell will complain on
* a bad command to a pipe.
+ *
+ * 12/2014: Take nonfatal settings in PROCINFO into account.
*/
if (errflg != NULL)
*errflg = errno;
- if ( redirtype == redirect_output
- || redirtype == redirect_append) {
+ if (failure_fatal && ! is_non_fatal_redirect(str, explen) &&
+ (redirtype == redirect_output
+ || redirtype == redirect_append)) {
/* multiple messages make life easier for translators */
if (*direction == 'f')
fatal(_("can't redirect from `%s' (%s)"),
@@ -1055,6 +1073,18 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
return rp;
}
+/* redirect --- Redirection for printf and print commands */
+
+struct redirect *
+redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal)
+{
+ bool not_string = ((fixtype(redir_exp)->flags & STRING) == 0);
+
+ redir_exp = force_string(redir_exp);
+ return redirect_string(redir_exp->stptr, redir_exp->stlen, not_string,
+ redirtype, errflg, -1, failure_fatal);
+}
+
/* getredirect --- find the struct redirect for this file or pipe */
struct redirect *
@@ -1069,6 +1099,45 @@ getredirect(const char *str, int len)
return NULL;
}
+/* is_non_fatal_std --- return true if fp is stdout/stderr and nonfatal */
+
+bool
+is_non_fatal_std(FILE *fp)
+{
+ if (in_PROCINFO(nonfatal, NULL, NULL))
+ return true;
+
+ /* yucky logic. sigh. */
+ if (fp == stdout) {
+ return ( in_PROCINFO("-", nonfatal, NULL) != NULL
+ || in_PROCINFO("/dev/stdout", nonfatal, NULL) != NULL);
+ } else if (fp == stderr) {
+ return (in_PROCINFO("/dev/stderr", nonfatal, NULL) != NULL);
+ }
+
+ return false;
+}
+
+/* is_non_fatal_redirect --- return true if redirected I/O should be nonfatal */
+
+bool
+is_non_fatal_redirect(const char *str, size_t len)
+{
+ bool ret;
+ char save;
+ char *s = (char *) str;
+
+ save = s[len];
+ s[len] = '\0';
+
+ ret = in_PROCINFO(nonfatal, NULL, NULL) != NULL
+ || in_PROCINFO(s, nonfatal, NULL) != NULL;
+
+ s[len] = save;
+
+ return ret;
+}
+
/* close_one --- temporarily close an open file to re-use the fd */
static void
@@ -1105,7 +1174,7 @@ close_one()
}
if (rp == NULL)
/* surely this is the only reason ??? */
- fatal(_("too many pipes or input files open"));
+ fatal(_("too many pipes or input files open"));
}
/* do_close --- completely close an open file or pipe */
@@ -1120,7 +1189,11 @@ do_close(int nargs)
if (nargs == 2) {
/* 2nd arg if present: "to" or "from" for two-way pipe */
/* DO NOT use _() on the strings here! */
+ char save;
+
tmp2 = POP_STRING();
+ save = tmp2->stptr[tmp2->stlen];
+ tmp2->stptr[tmp2->stlen] = '\0';
if (strcasecmp(tmp2->stptr, "to") == 0)
how = CLOSE_TO;
else if (strcasecmp(tmp2->stptr, "from") == 0)
@@ -1129,6 +1202,7 @@ do_close(int nargs)
DEREF(tmp2);
fatal(_("close: second argument must be `to' or `from'"));
}
+ tmp2->stptr[tmp2->stlen] = save;
DEREF(tmp2);
}
@@ -1164,7 +1238,8 @@ do_close(int nargs)
* POSIX says close() returns 0 on success, non-zero otherwise.
* For POSIX, at this point we just return 0. Otherwise we
* return the exit status of the process or of pclose(), depending.
- * This whole business is a mess.
+ * Down in the call tree of close_redir(), we rationalize the
+ * value like we do for system().
*/
if (do_posix) {
unref(tmp);
@@ -1206,13 +1281,14 @@ close_rp(struct redirect *rp, two_way_close_type how)
#endif /* HAVE_SOCKETS */
(void) iop_close(rp->iop);
} else
+ /* status already sanitized */
status = gawk_pclose(rp);
rp->iop = NULL;
}
} else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) {
/* write to pipe */
- status = pclose(rp->output.fp);
+ status = sanitize_exit_status(pclose(rp->output.fp));
if ((BINMODE & BINMODE_INPUT) != 0)
os_setbinmode(fileno(stdin), O_BINARY);
@@ -1313,6 +1389,41 @@ checkwarn:
return status;
}
+/* non_fatal_flush_std_file --- flush a standard output file allowing for nonfatal setting */
+
+bool
+non_fatal_flush_std_file(FILE *fp)
+{
+ int status = fflush(fp);
+
+ if (status != 0) {
+ bool is_fatal = ! is_non_fatal_std(fp);
+
+ if (is_fatal) {
+#ifdef __MINGW32__
+ if (errno == 0 || errno == EINVAL)
+ w32_maybe_set_errno();
+#endif
+ if (errno == EPIPE)
+ die_via_sigpipe();
+ else
+ fatal(fp == stdout
+ ? _("fflush: cannot flush standard output: %s")
+ : _("fflush: cannot flush standard error: %s"),
+ strerror(errno));
+ } else {
+ update_ERRNO_int(errno);
+ warning(fp == stdout
+ ? _("error writing standard output (%s)")
+ : _("error writing standard error (%s)"),
+ strerror(errno));
+ }
+ return false;
+ }
+
+ return true;
+}
+
/* flush_io --- flush all open output files */
int
@@ -1322,29 +1433,34 @@ flush_io()
int status = 0;
errno = 0;
- /* we don't warn about stdout/stderr if EPIPE, but we do error exit */
- if (fflush(stdout)) {
- if (errno != EPIPE)
- warning(_("error writing standard output (%s)"), strerror(errno));
+ if (! non_fatal_flush_std_file(stdout)) // ERRNO updated
status++;
- }
- if (fflush(stderr)) {
- if (errno != EPIPE)
- warning(_("error writing standard error (%s)"), strerror(errno));
+
+ errno = 0;
+ if (! non_fatal_flush_std_file(stderr)) // ERRNO updated
status++;
- }
+
+
+ // now for all open redirections
for (rp = red_head; rp != NULL; rp = rp->next) {
+ void (*messagefunc)(const char *mesg, ...) = r_fatal;
+
/* flush both files and pipes, what the heck */
if ((rp->flag & RED_WRITE) != 0 && rp->output.fp != NULL) {
- if (rp->output.gawk_fflush(rp->output.fp, rp->output.opaque)) {
+ if (rp->output.gawk_fflush(rp->output.fp, rp->output.opaque) != 0) {
+ update_ERRNO_int(errno);
+
+ if (is_non_fatal_redirect(rp->value, strlen(rp->value)))
+ messagefunc = r_warning;
+
if ((rp->flag & RED_PIPE) != 0)
- warning(_("pipe flush of `%s' failed (%s)."),
+ messagefunc(_("pipe flush of `%s' failed (%s)."),
rp->value, strerror(errno));
else if ((rp->flag & RED_TWOWAY) != 0)
- warning(_("co-process flush of pipe to `%s' failed (%s)."),
+ messagefunc(_("co-process flush of pipe to `%s' failed (%s)."),
rp->value, strerror(errno));
else
- warning(_("file flush of `%s' failed (%s)."),
+ messagefunc(_("file flush of `%s' failed (%s)."),
rp->value, strerror(errno));
status++;
}
@@ -1383,12 +1499,20 @@ close_io(bool *stdio_problem)
*stdio_problem = false;
/* we don't warn about stdout/stderr if EPIPE, but we do error exit */
if (fflush(stdout) != 0) {
+#ifdef __MINGW32__
+ if (errno == 0 || errno == EINVAL)
+ w32_maybe_set_errno();
+#endif
if (errno != EPIPE)
warning(_("error writing standard output (%s)"), strerror(errno));
status++;
*stdio_problem = true;
}
if (fflush(stderr) != 0) {
+#ifdef __MINGW32__
+ if (errno == 0 || errno == EINVAL)
+ w32_maybe_set_errno();
+#endif
if (errno != EPIPE)
warning(_("error writing standard error (%s)"), strerror(errno));
status++;
@@ -1442,7 +1566,7 @@ str2mode(const char *mode)
static int
socketopen(int family, int type, const char *localpname,
- const char *remotepname, const char *remotehostname)
+ const char *remotepname, const char *remotehostname, bool *hard_error)
{
struct addrinfo *lres, *lres0;
struct addrinfo lhints;
@@ -1461,8 +1585,11 @@ socketopen(int family, int type, const char *localpname,
lerror = getaddrinfo(NULL, localpname, & lhints, & lres);
if (lerror) {
- if (strcmp(localpname, "0") != 0)
- fatal(_("local port %s invalid in `/inet'"), localpname);
+ if (strcmp(localpname, "0") != 0) {
+ warning(_("local port %s invalid in `/inet'"), localpname);
+ *hard_error = true;
+ return INVALID_HANDLE;
+ }
lres0 = NULL;
lres = & lhints;
} else
@@ -1480,7 +1607,9 @@ socketopen(int family, int type, const char *localpname,
if (rerror) {
if (lres0 != NULL)
freeaddrinfo(lres0);
- fatal(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname);
+ warning(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname);
+ *hard_error = true;
+ return INVALID_HANDLE;
}
rres0 = rres;
socket_fd = INVALID_HANDLE;
@@ -1646,6 +1775,7 @@ devopen(const char *name, const char *mode)
char *cp;
int flag;
struct inet_socket_info isi;
+ int save_errno = 0;
openfd = devopen_simple(name, mode, false);
if (openfd != INVALID_HANDLE)
@@ -1655,27 +1785,30 @@ devopen(const char *name, const char *mode)
if (do_traditional) {
goto strictopen;
- } else if (inetfile(name, & isi)) {
+ } else if (inetfile(name, strlen(name), & isi)) {
#ifdef HAVE_SOCKETS
- cp = (char *) name;
-
- /* socketopen requires NUL-terminated strings */
- cp[isi.localport.offset+isi.localport.len] = '\0';
- cp[isi.remotehost.offset+isi.remotehost.len] = '\0';
- /* remoteport comes last, so already NUL-terminated */
-
- {
#define DEFAULT_RETRIES 20
static unsigned long def_retries = DEFAULT_RETRIES;
static bool first_time = true;
unsigned long retries = 0;
static long msleep = 1000;
+ bool hard_error = false;
+ bool non_fatal = is_non_fatal_redirect(name, strlen(name));
+ char save;
+
+ cp = (char *) name;
+
+ /* socketopen requires NUL-terminated strings */
+ cp[isi.localport.offset+isi.localport.len] = '\0';
+ cp[isi.remotehost.offset+isi.remotehost.len] = '\0';
+ save = cp[isi.remoteport.offset+isi.remoteport.len];
+ cp[isi.remoteport.offset+isi.remoteport.len] = '\0';
if (first_time) {
char *cp, *end;
unsigned long count = 0;
char *ms2;
-
+
first_time = false;
if ((cp = getenv("GAWK_SOCK_RETRIES")) != NULL) {
count = strtoul(cp, & end, 10);
@@ -1696,32 +1829,49 @@ devopen(const char *name, const char *mode)
msleep *= 1000;
}
}
- retries = def_retries;
+ /*
+ * PROCINFO["NONFATAL"] or PROCINFO[name, "NONFATAL"] overrrides
+ * GAWK_SOCK_RETRIES. The explicit code in the program carries
+ * a bigger stick than the environment variable does.
+ */
+ retries = non_fatal ? 1 : def_retries;
+ errno = 0;
do {
- openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset);
+ openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset,
+ name+isi.remoteport.offset, name+isi.remotehost.offset,
+ & hard_error);
retries--;
- } while (openfd == INVALID_HANDLE && retries > 0 && usleep(msleep) == 0);
- }
+ } while (openfd == INVALID_HANDLE && ! hard_error && retries > 0 && usleep(msleep) == 0);
+ save_errno = errno;
- /* restore original name string */
- cp[isi.localport.offset+isi.localport.len] = '/';
- cp[isi.remotehost.offset+isi.remotehost.len] = '/';
+ /* restore original name string */
+ cp[isi.localport.offset+isi.localport.len] = '/';
+ cp[isi.remotehost.offset+isi.remotehost.len] = '/';
+ cp[isi.remoteport.offset+isi.remoteport.len] = save;
#else /* ! HAVE_SOCKETS */
- fatal(_("TCP/IP communications are not supported"));
+ fatal(_("TCP/IP communications are not supported"));
#endif /* HAVE_SOCKETS */
}
strictopen:
- if (openfd == INVALID_HANDLE)
+ if (openfd == INVALID_HANDLE) {
openfd = open(name, flag, 0666);
+ /*
+ * ENOENT means there is no such name in the filesystem.
+ * Therefore it's ok to propagate up the error from
+ * getaddrinfo() that's in save_errno.
+ */
+ if (openfd == INVALID_HANDLE && errno == ENOENT && save_errno)
+ errno = save_errno;
+ }
#if defined(__EMX__) || defined(__MINGW32__)
if (openfd == INVALID_HANDLE && errno == EACCES) {
/* On OS/2 and Windows directory access via open() is
not permitted. */
struct stat buf;
- if (! inetfile(name, NULL)
+ if (! inetfile(name, strlen(name), NULL)
&& stat(name, & buf) == 0 && S_ISDIR(buf.st_mode))
errno = EISDIR;
}
@@ -1737,16 +1887,16 @@ strictopen:
/* two_way_open --- open a two way communications channel */
static int
-two_way_open(const char *str, struct redirect *rp)
+two_way_open(const char *str, struct redirect *rp, int extfd)
{
static bool no_ptys = false;
#ifdef HAVE_SOCKETS
/* case 1: socket */
- if (inetfile(str, NULL)) {
+ if (extfd >= 0 || inetfile(str, strlen(str), NULL)) {
int fd, newfd;
- fd = devopen(str, "rw");
+ fd = (extfd >= 0) ? extfd : devopen(str, "rw");
if (fd == INVALID_HANDLE)
return false;
if ((BINMODE & BINMODE_OUTPUT) != 0)
@@ -1798,7 +1948,7 @@ two_way_open(const char *str, struct redirect *rp)
char c;
int master, dup_master;
int slave;
- int save_errno;
+ int save_errno;
pid_t pid;
struct stat statb;
struct termios st;
@@ -1974,7 +2124,7 @@ two_way_open(const char *str, struct redirect *rp)
/* stderr does NOT get dup'ed onto child's stdout */
- signal(SIGPIPE, SIG_DFL);
+ set_sigpipe_to_default();
execl("/bin/sh", "sh", "-c", str, NULL);
_exit(errno == ENOENT ? 127 : 126);
@@ -2053,7 +2203,7 @@ use_pipes:
#if defined(__EMX__) || defined(__MINGW32__)
save_stdin = dup(0); /* duplicate stdin */
save_stdout = dup(1); /* duplicate stdout */
-
+
if (save_stdout == -1 || save_stdin == -1) {
/* if an error occurs close all open file handles */
save_errno = errno;
@@ -2066,7 +2216,7 @@ use_pipes:
errno = save_errno;
return false;
}
-
+
/* connect pipes to stdin and stdout */
close(1); /* close stdout */
if (dup(ctop[1]) != 1) { /* connect pipe input to stdout */
@@ -2086,7 +2236,7 @@ use_pipes:
/* none of these handles must be inherited by the child process */
(void) close(ptoc[0]); /* close pipe output, child will use stdin instead */
(void) close(ctop[1]); /* close pipe input, child will use stdout instead */
-
+
os_close_on_exec(ptoc[1], str, "pipe", "from"); /* pipe input: output of the parent process */
os_close_on_exec(ctop[0], str, "pipe", "from"); /* pipe output: input of the parent process */
os_close_on_exec(save_stdin, str, "pipe", "from"); /* saved stdin of the parent process */
@@ -2100,7 +2250,7 @@ use_pipes:
qcmd = quote_cmd(str), NULL);
efree(qcmd);
#endif
-
+
/* restore stdin and stdout */
close(1);
if (dup(save_stdout) != 1) {
@@ -2109,7 +2259,7 @@ use_pipes:
fatal(_("restoring stdout in parent process failed\n"));
}
close(save_stdout);
-
+
close(0);
if (dup(save_stdin) != 0) {
close(save_stdin);
@@ -2135,7 +2285,7 @@ use_pipes:
errno = save_errno;
return false;
}
-
+
if (pid == 0) { /* child */
if (close(1) == -1)
fatal(_("close of stdout in child failed (%s)"),
@@ -2151,7 +2301,7 @@ use_pipes:
|| close(ctop[0]) == -1 || close(ctop[1]) == -1)
fatal(_("close of pipe failed (%s)"), strerror(errno));
/* stderr does NOT get dup'ed onto child's stdout */
- signal(SIGPIPE, SIG_DFL);
+ set_sigpipe_to_default();
execl("/bin/sh", "sh", "-c", str, NULL);
_exit(errno == ENOENT ? 127 : 126);
}
@@ -2217,17 +2367,43 @@ use_pipes:
#ifndef PIPES_SIMULATED /* real pipes */
-/* wait_any --- wait for a child process, close associated pipe */
+/*
+ * wait_any --- if the argument pid is 0, wait for all child processes that
+ * have exited. We loop to make sure to reap all children that have exited to
+ * minimize the risk of running out of process slots. Since we don't process
+ * SIGCHLD, we do not immediately reap exited children. So when we get here,
+ * we want to reap any that have piled up.
+ *
+ * Note: on platforms that do not support waitpid with WNOHANG, when called with
+ * a zero argument, this function will hang until all children have exited.
+ *
+ * AJS, 2013-07-07: I do not see why we need to ignore signals during this
+ * function. This function just waits and updates the pid and status fields.
+ * I don't see why that should interfere with any signal handlers. But I am
+ * reluctant to remove this protection. So I changed to use sigprocmask to
+ * block signals instead to avoid interfering with installed signal handlers.
+ */
static int
wait_any(int interesting) /* pid of interest, if any */
{
- RETSIGTYPE (*hstat)(int), (*istat)(int), (*qstat)(int);
int pid;
int status = 0;
struct redirect *redp;
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set, oldset;
+
+ /* I have no idea why we are blocking signals during this function... */
+ sigemptyset(& set);
+ sigaddset(& set, SIGINT);
+ sigaddset(& set, SIGHUP);
+ sigaddset(& set, SIGQUIT);
+ sigprocmask(SIG_BLOCK, & set, & oldset);
+#else
+ void (*hstat)(int), (*istat)(int), (*qstat)(int);
istat = signal(SIGINT, SIG_IGN);
+#endif
#ifdef __MINGW32__
if (interesting < 0) {
status = -1;
@@ -2243,11 +2419,22 @@ wait_any(int interesting) /* pid of interest, if any */
break;
}
}
-#else
+#else /* ! __MINGW32__ */
+#ifndef HAVE_SIGPROCMASK
hstat = signal(SIGHUP, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
+#endif
for (;;) {
-# ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */
+# if defined(HAVE_WAITPID) && defined(WNOHANG)
+ /*
+ * N.B. If the caller wants status for a specific child process
+ * (i.e. interesting is non-zero), then we must hang until we
+ * get exit status for that child.
+ */
+ if ((pid = waitpid(-1, & status, (interesting ? 0 : WNOHANG))) == 0)
+ /* No children have exited */
+ break;
+# elif defined(HAVE_SYS_WAIT_H) /* POSIX compatible sys/wait.h */
pid = wait(& status);
# else
pid = wait((union wait *) & status);
@@ -2265,10 +2452,16 @@ wait_any(int interesting) /* pid of interest, if any */
if (pid == -1 && errno == ECHILD)
break;
}
+#ifndef HAVE_SIGPROCMASK
signal(SIGHUP, hstat);
signal(SIGQUIT, qstat);
#endif
+#endif /* ! __MINGW32__ */
+#ifndef HAVE_SIGPROCMASK
signal(SIGINT, istat);
+#else
+ sigprocmask(SIG_SETMASK, & oldset, NULL);
+#endif
return status;
}
@@ -2313,10 +2506,10 @@ gawk_popen(const char *cmd, struct redirect *rp)
fatal(_("moving pipe to stdout in child failed (dup: %s)"),
strerror(errno));
}
-
+
/* none of these handles must be inherited by the child process */
close(p[1]); /* close pipe input */
-
+
os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */
os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */
@@ -2327,7 +2520,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
qcmd = quote_cmd(cmd), NULL);
efree(qcmd);
#endif
-
+
/* restore stdout */
close(1);
if (dup(save_stdout) != 1) {
@@ -2345,7 +2538,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
if (close(p[0]) == -1 || close(p[1]) == -1)
fatal(_("close of pipe failed (%s)"), strerror(errno));
- signal(SIGPIPE, SIG_DFL);
+ set_sigpipe_to_default();
execl("/bin/sh", "sh", "-c", cmd, NULL);
_exit(errno == ENOENT ? 127 : 126);
}
@@ -2390,7 +2583,7 @@ gawk_pclose(struct redirect *rp)
/* process previously found, return stored status */
if (rp->pid == -1)
return rp->status;
- rp->status = wait_any(rp->pid);
+ rp->status = sanitize_exit_status(wait_any(rp->pid));
rp->pid = -1;
return rp->status;
}
@@ -2410,17 +2603,13 @@ gawk_popen(const char *cmd, struct redirect *rp)
FILE *current;
os_restore_mode(fileno(stdin));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_DFL);
-#endif
+ set_sigpipe_to_default();
current = popen(cmd, binmode("r"));
if ((BINMODE & BINMODE_INPUT) != 0)
os_setbinmode(fileno(stdin), O_BINARY);
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
if (current == NULL)
return NULL;
@@ -2473,13 +2662,14 @@ do_getline_redir(int into_variable, enum redirval redirtype)
NODE *redir_exp = NULL;
NODE **lhs = NULL;
int redir_error = 0;
+ const awk_fieldwidth_info_t *field_width = NULL;
if (into_variable)
lhs = POP_ADDRESS();
assert(redirtype != redirect_none);
redir_exp = TOP();
- rp = redirect(redir_exp, redirtype, & redir_error);
+ rp = redirect(redir_exp, redirtype, & redir_error, false);
DEREF(redir_exp);
decr_sp();
if (rp == NULL) {
@@ -2489,6 +2679,10 @@ do_getline_redir(int into_variable, enum redirval redirtype)
}
return make_number((AWKNUM) -1.0);
} else if ((rp->flag & RED_TWOWAY) != 0 && rp->iop == NULL) {
+ if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
+ update_ERRNO_int(EBADF);
+ return make_number((AWKNUM) -1.0);
+ }
(void) close_rp(rp, CLOSE_ALL);
fatal(_("getline: attempt to read from closed read end of two-way pipe"));
}
@@ -2497,11 +2691,11 @@ do_getline_redir(int into_variable, enum redirval redirtype)
return make_number((AWKNUM) 0.0);
errcode = 0;
- cnt = get_a_record(& s, iop, & errcode);
+ cnt = get_a_record(& s, iop, & errcode, (lhs ? NULL : & field_width));
if (errcode != 0) {
if (! do_traditional && (errcode != -1))
update_ERRNO_int(errcode);
- return make_number((AWKNUM) -1.0);
+ return make_number((AWKNUM) cnt);
}
if (cnt == EOF) {
@@ -2519,11 +2713,11 @@ do_getline_redir(int into_variable, enum redirval redirtype)
}
if (lhs == NULL) /* no optional var. */
- set_record(s, cnt);
+ set_record(s, cnt, field_width);
else { /* assignment to variable */
unref(*lhs);
*lhs = make_string(s, cnt);
- (*lhs)->flags |= MAYBE_NUM;
+ (*lhs)->flags |= USER_INPUT;
}
return make_number((AWKNUM) 1.0);
@@ -2537,6 +2731,7 @@ do_getline(int into_variable, IOBUF *iop)
int cnt = EOF;
char *s = NULL;
int errcode;
+ const awk_fieldwidth_info_t *field_width = NULL;
if (iop == NULL) { /* end of input */
if (into_variable)
@@ -2545,13 +2740,13 @@ do_getline(int into_variable, IOBUF *iop)
}
errcode = 0;
- cnt = get_a_record(& s, iop, & errcode);
+ cnt = get_a_record(& s, iop, & errcode, (into_variable ? NULL : & field_width));
if (errcode != 0) {
if (! do_traditional && (errcode != -1))
update_ERRNO_int(errcode);
if (into_variable)
(void) POP_ADDRESS();
- return make_number((AWKNUM) -1.0);
+ return make_number((AWKNUM) cnt);
}
if (cnt == EOF)
@@ -2560,13 +2755,13 @@ do_getline(int into_variable, IOBUF *iop)
INCREMENT_REC(FNR);
if (! into_variable) /* no optional var. */
- set_record(s, cnt);
+ set_record(s, cnt, field_width);
else { /* assignment to variable */
NODE **lhs;
lhs = POP_ADDRESS();
unref(*lhs);
*lhs = make_string(s, cnt);
- (*lhs)->flags |= MAYBE_NUM;
+ (*lhs)->flags |= USER_INPUT;
}
return make_number((AWKNUM) 1.0);
}
@@ -2574,8 +2769,8 @@ do_getline(int into_variable, IOBUF *iop)
typedef struct {
const char *envname;
char **dfltp; /* pointer to address of default path */
- char **awkpath; /* array containing library search paths */
- int max_pathlen; /* length of the longest item in awkpath */
+ char **awkpath; /* array containing library search paths */
+ int max_pathlen; /* length of the longest item in awkpath */
} path_info;
static path_info pi_awkpath = {
@@ -2608,8 +2803,7 @@ init_awkpath(path_info *pi)
max_path++;
// +3 --> 2 for null entries at front and end of path, 1 for NULL end of list
- emalloc(pi->awkpath, char **, (max_path + 3) * sizeof(char *), "init_awkpath");
- memset(pi->awkpath, 0, (max_path + 3) * sizeof(char *));
+ ezalloc(pi->awkpath, char **, (max_path + 3) * sizeof(char *), "init_awkpath");
start = path;
i = 0;
@@ -2659,7 +2853,7 @@ init_awkpath(path_info *pi)
pi->awkpath[i] = NULL;
}
-/* do_find_source --- search $AWKPATH for file, return NULL if not found */
+/* do_find_source --- search $AWKPATH for file, return NULL if not found */
static char *
do_find_source(const char *src, struct stat *stb, int *errcode, path_info *pi)
@@ -2683,7 +2877,7 @@ do_find_source(const char *src, struct stat *stb, int *errcode, path_info *pi)
if (pi->awkpath == NULL)
init_awkpath(pi);
- emalloc(path, char *, pi->max_pathlen + strlen(src) + 1, "do_find_source");
+ emalloc(path, char *, pi->max_pathlen + strlen(src) + 1, "do_find_source");
for (i = 0; pi->awkpath[i] != NULL; i++) {
if (strcmp(pi->awkpath[i], "./") == 0 || strcmp(pi->awkpath[i], ".") == 0)
*path = '\0';
@@ -2700,7 +2894,7 @@ do_find_source(const char *src, struct stat *stb, int *errcode, path_info *pi)
return NULL;
}
-/* find_source --- find source file with default file extension handling */
+/* find_source --- find source file with default file extension handling */
char *
find_source(const char *src, struct stat *stb, int *errcode, int is_extlib)
@@ -3016,9 +3210,8 @@ iop_alloc(int fd, const char *name, int errno_val)
{
IOBUF *iop;
- emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
+ ezalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
- memset(iop, '\0', sizeof(IOBUF));
iop->public.fd = fd;
iop->public.name = name;
iop->public.read_func = ( ssize_t(*)() ) read;
@@ -3085,7 +3278,7 @@ iop_finish(IOBUF *iop)
lintwarn(_("data file `%s' is empty"), iop->public.name);
iop->errcode = errno = 0;
iop->count = iop->scanoff = 0;
- emalloc(iop->buf, char *, iop->size += 2, "iop_finish");
+ emalloc(iop->buf, char *, iop->size += 1, "iop_finish");
iop->off = iop->buf;
iop->dataend = NULL;
iop->end = iop->buf + iop->size;
@@ -3117,10 +3310,10 @@ grow_iop_buffer(IOBUF *iop)
size_t newsize;
/*
- * Lop off original extra two bytes, double the size,
- * add them back.
+ * Lop off original extra byte, double the size,
+ * add it back.
*/
- newsize = ((iop->size - 2) * 2) + 2;
+ newsize = ((iop->size - 1) * 2) + 1;
/* Check for overflow */
if (newsize <= iop->size)
@@ -3128,7 +3321,7 @@ grow_iop_buffer(IOBUF *iop)
/* Make sure there's room for a disk block */
if (newsize - valid < iop->readsize)
- newsize += iop->readsize + 2;
+ newsize += iop->readsize + 1;
/* Check for overflow, again */
if (newsize <= iop->size)
@@ -3141,8 +3334,6 @@ grow_iop_buffer(IOBUF *iop)
iop->end = iop->buf + iop->size;
}
-/* Here are the routines. */
-
/* rs1scan --- scan for a single character record terminator */
static RECVALUE
@@ -3168,51 +3359,51 @@ rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
* Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
* Date: Mon, 23 Jun 2003 12:20:16 +0200
* Cc: isamu@yamato.ibm.com
- *
+ *
* Hi,
- *
+ *
* > Is there any way to make the following query to the current locale?
* >
* > Given an 8-bit value, can this value ever appear as part of
* > a multibyte character?
- *
+ *
* There is no simple answer here. The easiest solution I see is to
* get the current locale's codeset (via locale_charset() which is a
* wrapper around nl_langinfo(CODESET)), and then perform a case-by-case
* treatment of the known multibyte encodings, from GB2312 to EUC-JISX0213;
* for the unibyte encodings, a single btowc() call will tell you.
- *
+ *
* > This is particularly critical for me for ASCII newline ('\n'). If I
* > can be guaranteed that it never shows up as part of a multibyte character,
* > I can speed up gawk considerably in mulitbyte locales.
- *
+ *
* This is much simpler to answer!
* In all ASCII based multibyte encodings used for locales today (this
* excludes EBCDIC based doublebyte encodings from IBM, and also excludes
* ISO-2022-JP which is used for email exchange but not as a locale encoding)
* ALL bytes in the range 0x00..0x2F occur only as a single character, not
* as part of a multibyte character.
- *
+ *
* So it's safe to assume, but deserves a comment in the source.
- *
+ *
* Bruno
***************************************************************
* From: Bruno Haible <bruno@clisp.org>
* To: Aharon Robbins <arnold@skeeve.com>
* Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
* Date: Mon, 23 Jun 2003 14:27:49 +0200
- *
+ *
* On Monday 23 June 2003 14:11, you wrote:
- *
+ *
* > if (rs != '\n' && MB_CUR_MAX > 1) {
- *
+ *
* If you assume ASCII, you can even write
- *
+ *
* if (rs >= 0x30 && MB_CUR_MAX > 1) {
- *
+ *
* (this catches also the space character) but if portability to EBCDIC
* systems is desired, your code is fine as is.
- *
+ *
* Bruno
*/
/* Thus, the check for \n here; big speedup ! */
@@ -3460,16 +3651,53 @@ find_longest_terminator:
return REC_OK;
}
+/* retryable --- return true if PROCINFO[<filename>, "RETRY"] exists */
+
+static inline int
+retryable(IOBUF *iop)
+{
+ return PROCINFO_node && in_PROCINFO(iop->public.name, "RETRY", NULL);
+}
+
+/* errno_io_retry --- Does the I/O error indicate that the operation should be retried later? */
+
+static inline int
+errno_io_retry(void)
+{
+ switch (errno) {
+#ifdef EAGAIN
+ case EAGAIN:
+#endif
+#ifdef EWOULDBLOCK
+#if !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)
+ case EWOULDBLOCK:
+#endif
+#endif
+#ifdef EINTR
+ case EINTR:
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+#endif
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/*
* get_a_record --- read a record from IOP into out,
* return length of EOF, set RT.
* Note that errcode is never NULL, and the caller initializes *errcode to 0.
+ * If I/O would block, return -2.
*/
static int
get_a_record(char **out, /* pointer to pointer to data */
IOBUF *iop, /* input IOP */
- int *errcode) /* pointer to error variable */
+ int *errcode, /* pointer to error variable */
+ const awk_fieldwidth_info_t **field_width)
+ /* pointer to pointer to field_width info */
{
struct recmatch recm;
SCANSTATE state;
@@ -3488,7 +3716,8 @@ get_a_record(char **out, /* pointer to pointer to data */
char *rt_start;
size_t rt_len;
int rc = iop->public.get_record(out, &iop->public, errcode,
- &rt_start, &rt_len);
+ &rt_start, &rt_len,
+ field_width);
if (rc == EOF)
iop->flag |= IOP_AT_EOF;
else {
@@ -3507,8 +3736,10 @@ get_a_record(char **out, /* pointer to pointer to data */
iop->flag |= IOP_AT_EOF;
return EOF;
} else if (iop->count == -1) {
- iop->flag |= IOP_AT_EOF;
*errcode = errno;
+ if (errno_io_retry() && retryable(iop))
+ return -2;
+ iop->flag |= IOP_AT_EOF;
return EOF;
} else {
iop->dataend = iop->buf + iop->count;
@@ -3582,6 +3813,8 @@ get_a_record(char **out, /* pointer to pointer to data */
iop->count = iop->public.read_func(iop->public.fd, iop->dataend, amt_to_read);
if (iop->count == -1) {
*errcode = errno;
+ if (errno_io_retry() && retryable(iop))
+ return -2;
iop->flag |= IOP_AT_EOF;
break;
} else if (iop->count == 0) {
@@ -3681,7 +3914,7 @@ set_RS()
* set_IGNORECASE() relies on this routine to call
* set_FS().
*/
- RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case);
+ RS_regexp = RS_re[IGNORECASE];
goto set_FS;
}
unref(save_rs);
@@ -3693,9 +3926,9 @@ set_RS()
* Please do not remerge the if condition; hinders memory deallocation
* in case of fatal error in make_regexp.
*/
- refree(RS_re_yes_case); /* NULL argument is ok */
- refree(RS_re_no_case);
- RS_re_yes_case = RS_re_no_case = RS_regexp = NULL;
+ refree(RS_re[0]); /* NULL argument is ok */
+ refree(RS_re[1]);
+ RS_re[0] = RS_re[1] = RS_regexp = NULL;
if (RS->stlen == 0) {
RS_is_null = true;
@@ -3703,9 +3936,9 @@ set_RS()
} else if (RS->stlen > 1 && ! do_traditional) {
static bool warned = false;
- RS_re_yes_case = make_regexp(RS->stptr, RS->stlen, false, true, true);
- RS_re_no_case = make_regexp(RS->stptr, RS->stlen, true, true, true);
- RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case);
+ RS_re[0] = make_regexp(RS->stptr, RS->stlen, false, true, true);
+ RS_re[1] = make_regexp(RS->stptr, RS->stlen, true, true, true);
+ RS_regexp = RS_re[IGNORECASE];
matchrec = rsrescan;
@@ -3727,23 +3960,19 @@ set_FS:
* This works by checking if PROCINFO["command", "pty"] exists and is true.
*/
-static int
+static bool
pty_vs_pipe(const char *command)
{
#ifdef HAVE_TERMIOS_H
NODE *val;
- if (PROCINFO_node == NULL)
- return false;
+ /*
+ * N.B. No need to check for NULL PROCINFO_node, since the
+ * in_PROCINFO function now checks that for us.
+ */
val = in_PROCINFO(command, "pty", NULL);
- if (val) {
- if ((val->flags & MAYBE_NUM) != 0)
- (void) force_number(val);
- if ((val->flags & NUMBER) != 0)
- return ! iszero(val);
- else
- return (val->stlen != 0);
- }
+ if (val)
+ return boolval(val);
#endif /* HAVE_TERMIOS_H */
return false;
}
@@ -3776,21 +4005,24 @@ free_rp(struct redirect *rp)
/* inetfile --- return true for a /inet special file, set other values */
static bool
-inetfile(const char *str, struct inet_socket_info *isi)
+inetfile(const char *str, size_t len, struct inet_socket_info *isi)
{
#ifndef HAVE_SOCKETS
return false;
#else
const char *cp = str;
+ const char *cpend = str + len;
struct inet_socket_info buf;
/* syntax: /inet/protocol/localport/hostname/remoteport */
- if (strncmp(cp, "/inet", 5) != 0)
+ if (len < 5 || memcmp(cp, "/inet", 5) != 0)
/* quick exit */
return false;
if (! isi)
isi = & buf;
cp += 5;
+ if (cpend - cp < 2)
+ return false;
switch (*cp) {
case '/':
isi->family = AF_UNSPEC;
@@ -3811,9 +4043,11 @@ inetfile(const char *str, struct inet_socket_info *isi)
cp++; /* skip past '/' */
/* which protocol? */
- if (strncmp(cp, "tcp/", 4) == 0)
+ if (cpend - cp < 5)
+ return false;
+ if (memcmp(cp, "tcp/", 4) == 0)
isi->protocol = SOCK_STREAM;
- else if (strncmp(cp, "udp/", 4) == 0)
+ else if (memcmp(cp, "udp/", 4) == 0)
isi->protocol = SOCK_DGRAM;
else
return false;
@@ -3821,37 +4055,43 @@ inetfile(const char *str, struct inet_socket_info *isi)
/* which localport? */
isi->localport.offset = cp-str;
- while (*cp != '/' && *cp != '\0')
- cp++;
- /*
+ while (*cp != '/') {
+ if (++cp >= cpend)
+ return false;
+ }
+ /*
* Require a port, let them explicitly put 0 if
- * they don't care.
+ * they don't care.
*/
- if (*cp != '/' || ((isi->localport.len = (cp-str)-isi->localport.offset) == 0))
+ if ((isi->localport.len = (cp-str)-isi->localport.offset) == 0)
return false;
/* which hostname? */
+ if (cpend - cp < 2)
+ return false;
cp++;
isi->remotehost.offset = cp-str;
- while (*cp != '/' && *cp != '\0')
- cp++;
- if (*cp != '/' || ((isi->remotehost.len = (cp-str)-isi->remotehost.offset) == 0))
+ while (*cp != '/') {
+ if (++cp >= cpend)
+ return false;
+ }
+ if ((isi->remotehost.len = (cp-str)-isi->remotehost.offset) == 0)
return false;
/* which remoteport? */
+ if (cpend - cp < 2)
+ return false;
cp++;
/*
* The remote port ends the special file name.
- * This means there already is a '\0' at the end of the string.
- * Therefore no need to patch any string ending.
*
* Here too, require a port, let them explicitly put 0 if
* they don't care.
*/
isi->remoteport.offset = cp-str;
- while (*cp != '/' && *cp != '\0')
- cp++;
- if (*cp != '\0' || ((isi->remoteport.len = (cp-str)-isi->remoteport.offset) == 0))
+ while (*cp != '/' && cp < cpend)
+ cp++;
+ if (cp != cpend || ((isi->remoteport.len = (cp-str)-isi->remoteport.offset) == 0))
return false;
#ifndef HAVE_GETADDRINFO
@@ -3866,22 +4106,31 @@ inetfile(const char *str, struct inet_socket_info *isi)
/*
* in_PROCINFO --- return value for a PROCINFO element with
* SUBSEP seperated indices.
- */
+ */
static NODE *
in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx)
{
char *str;
size_t str_len;
- NODE *r, *sub = NULL;
+ NODE *r, *sub = NULL;
NODE *subsep = SUBSEP_node->var_value;
+ if (PROCINFO_node == NULL || (pidx1 == NULL && pidx2 == NULL))
+ return NULL;
+
/* full_idx is in+out parameter */
if (full_idx)
sub = *full_idx;
- str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2);
+ if (pidx1 != NULL && pidx2 == NULL)
+ str_len = strlen(pidx1);
+ else if (pidx1 == NULL && pidx2 != NULL)
+ str_len = strlen(pidx2);
+ else
+ str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2);
+
if (sub == NULL) {
emalloc(str, char *, str_len + 1, "in_PROCINFO");
sub = make_str_node(str, str_len, ALREADY_MALLOCED);
@@ -3895,8 +4144,14 @@ in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx)
sub->stlen = str_len;
}
- sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen,
- subsep->stptr, pidx2);
+ if (pidx1 != NULL && pidx2 == NULL)
+ strcpy(sub->stptr, pidx1);
+ else if (pidx1 == NULL && pidx2 != NULL)
+ strcpy(sub->stptr, pidx2);
+ else
+ sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen,
+ subsep->stptr, pidx2);
+
r = in_array(PROCINFO_node, sub);
if (! full_idx)
unref(sub);
@@ -4013,6 +4268,8 @@ gawk_fwrite(const void *buf, size_t size, size_t count, FILE *fp, void *opaque)
return fwrite(buf, size, count, fp);
}
+/* gawk_fflush --- like fflush */
+
static int
gawk_fflush(FILE *fp, void *opaque)
{
@@ -4021,6 +4278,8 @@ gawk_fflush(FILE *fp, void *opaque)
return fflush(fp);
}
+/* gawk_ferror --- like ferror */
+
static int
gawk_ferror(FILE *fp, void *opaque)
{
@@ -4029,6 +4288,8 @@ gawk_ferror(FILE *fp, void *opaque)
return ferror(fp);
}
+/* gawk_fclose --- like fclose */
+
static int
gawk_fclose(FILE *fp, void *opaque)
{
@@ -4046,7 +4307,6 @@ gawk_fclose(FILE *fp, void *opaque)
return result;
}
-
/* init_output_wrapper --- initialize the output wrapper */
static void
diff --git a/m4/ChangeLog b/m4/ChangeLog
index e801ddc9..d3a23cc3 100644
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -12,6 +12,14 @@
* po.m4: Upgrade to gettext-0.19.7.
* progtest.m4: Upgrade to gettext-0.19.7.
+2016-01-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * arch.m4 (GAWK_AC_AIX_TWEAK): Remove definition.
+
+2016-01-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * arch.m4 (GAWK_AC_LINUX_ALPHA): Remove definition.
+
2015-09-11 Daniel Richard G. <skunk@iSKUNK.ORG>
* arch.m4: Rework again. In particular, provide a wrapper
@@ -51,6 +59,10 @@
* 4.1.2: Release tar ball made.
+2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * isc-posix.m4: Removed. No longer needed.
+
2015-01-24 gettextize <bug-gnu-gettext@gnu.org>
* iconv.m4: Upgrade to gettext-0.19.4.
diff --git a/m4/arch.m4 b/m4/arch.m4
index 441602cd..70cee013 100644
--- a/m4/arch.m4
+++ b/m4/arch.m4
@@ -22,43 +22,6 @@ dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
dnl
-dnl Check for AIX and add _XOPEN_SOURCE_EXTENDED
-AC_DEFUN([GAWK_AC_AIX_TWEAK], [
-AC_MSG_CHECKING([for AIX compilation hacks])
-AC_CACHE_VAL(gawk_cv_aix_hack, [
-if test -d /lpp
-then
- CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED=1 -DGAWK_AIX=1"
- gawk_cv_aix_hack=yes
-else
- gawk_cv_aix_hack=no
-fi
-])dnl
-AC_MSG_RESULT([${gawk_cv_aix_hack}])
-])dnl
-
-dnl Check for Alpha Linux systems
-AC_DEFUN([GAWK_AC_LINUX_ALPHA], [
-AC_MSG_CHECKING([for Linux/Alpha compilation hacks])
-AC_CACHE_VAL(gawk_cv_linux_alpha_hack, [
-if test "Linux" = "`uname`" && test "alpha" = "`uname -m`"
-then
- # this isn't necessarily always true,
- # the vendor's compiler is also often found
- if test "$GCC" = yes
- then
- CFLAGS="$CFLAGS -mieee"
- gawk_cv_linux_alpha_hack=yes
- else
- gawk_cv_linux_alpha_hack=no
- fi
-else
- gawk_cv_linux_alpha_hack=no
-fi
-])dnl
-AC_MSG_RESULT([${gawk_cv_linux_alpha_hack}])
-])dnl
-
dnl Check for z/OS Unix Systems Services
AC_DEFUN([AC_ZOS_USS], [
AC_MSG_CHECKING([for z/OS USS compilation])
diff --git a/m4/isc-posix.m4 b/m4/isc-posix.m4
deleted file mode 100644
index 74dc8f26..00000000
--- a/m4/isc-posix.m4
+++ /dev/null
@@ -1,24 +0,0 @@
-# isc-posix.m4 serial 2 (gettext-0.11.2)
-dnl Copyright (C) 1995-2002 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-# This file is not needed with autoconf-2.53 and newer. Remove it in 2005.
-
-# This test replaces the one in autoconf.
-# Currently this macro should have the same name as the autoconf macro
-# because gettext's gettext.m4 (distributed in the automake package)
-# still uses it. Otherwise, the use in gettext.m4 makes autoheader
-# give these diagnostics:
-# configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX
-# configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX
-
-undefine([AC_ISC_POSIX])
-
-AC_DEFUN([AC_ISC_POSIX],
- [
- dnl This test replaces the obsolescent AC_ISC_POSIX kludge.
- AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"])
- ]
-)
diff --git a/main.c b/main.c
index be210036..195684c4 100644
--- a/main.c
+++ b/main.c
@@ -1,23 +1,23 @@
/*
- * main.c -- Code generator and main program for gawk.
+ * main.c -- Code generator and main program for gawk.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -58,7 +58,7 @@ static void init_args(int argc0, int argc, const char *argv0, char **argv);
static void init_vars(void);
static NODE *load_environ(void);
static NODE *load_procinfo(void);
-static RETSIGTYPE catchsig(int sig);
+static void catchsig(int sig);
#ifdef HAVE_LIBSIGSEGV
static int catchsegv(void *fault_address, int serious);
static void catchstackoverflow(int emergency, stackoverflow_context_t scp);
@@ -85,7 +85,7 @@ long NF;
long NR;
long FNR;
int BINMODE;
-int IGNORECASE;
+bool IGNORECASE;
char *OFS;
char *ORS;
char *OFMT;
@@ -147,7 +147,7 @@ static void set_locale_stuff(void);
static bool stopped_early = false;
int do_flags = false;
-bool do_optimize = false; /* apply default optimizations */
+bool do_optimize = true; /* apply default optimizations */
static int do_nostalgia = false; /* provide a blast from the past */
static int do_binary = false; /* hands off my data! */
static int do_version = false; /* print version info */
@@ -194,6 +194,7 @@ static const struct option optab[] = {
{ "locale", required_argument, NULL, 'Z' },
#endif
{ "non-decimal-data", no_argument, NULL, 'n' },
+ { "no-optimize", no_argument, NULL, 's' },
{ "nostalgia", no_argument, & do_nostalgia, 1 },
{ "optimize", no_argument, NULL, 'O' },
#if defined(YYDEBUG) || defined(GAWKDEBUG)
@@ -254,7 +255,7 @@ main(int argc, char **argv)
#ifdef SIGBUS
(void) signal(SIGBUS, catchsig);
#endif
-#ifdef SIGPIPE
+
/*
* Ignore SIGPIPE so that writes to pipes that fail don't
* kill the process but instead return -1 and set errno.
@@ -268,8 +269,7 @@ main(int argc, char **argv)
* should not give us "broken pipe" messages --- mainly because
* it did not do so in the past and people would complain.
*/
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
(void) sigsegv_install_handler(catchsegv);
#define STACK_SIZE (16*1024)
@@ -307,22 +307,10 @@ main(int argc, char **argv)
* this value once makes a speed difference.
*/
gawk_mb_cur_max = MB_CUR_MAX;
-#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();
-
if (do_nostalgia)
nostalgia();
@@ -368,7 +356,7 @@ main(int argc, char **argv)
init_debug();
#ifdef HAVE_MPFR
- /* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */
+ /* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */
if (do_mpfr)
init_mpfr(DEFAULT_PREC, DEFAULT_ROUNDMODE);
#endif
@@ -469,7 +457,7 @@ main(int argc, char **argv)
/* Read in the program */
if (parse_program(& code_block) != 0)
exit(EXIT_FAILURE);
-
+
if (do_intl)
exit(EXIT_SUCCESS);
@@ -511,9 +499,8 @@ main(int argc, char **argv)
if (do_debug)
debug_prog(code_block);
- else if (do_pretty_print && ! do_debug && getenv("GAWK_NO_PP_RUN") != NULL)
- /* hack to run pretty printer only. need a better solution */
- ;
+ else if (do_pretty_print && ! do_profile)
+ ; /* run pretty printer only. */
else
interpret(code_block);
@@ -532,7 +519,7 @@ main(int argc, char **argv)
if (do_tidy_mem)
release_all_vars();
-
+
/* keep valgrind happier */
if (extra_stack)
efree(extra_stack);
@@ -609,6 +596,7 @@ usage(int exitval, FILE *fp)
fputs(_("\t-p[file]\t\t--profile[=file]\n"), fp);
fputs(_("\t-P\t\t\t--posix\n"), fp);
fputs(_("\t-r\t\t\t--re-interval\n"), fp);
+ fputs(_("\t-s\t\t\t--no-optimize\n"), fp);
fputs(_("\t-S\t\t\t--sandbox\n"), fp);
fputs(_("\t-t\t\t\t--lint-old\n"), fp);
fputs(_("\t-V\t\t\t--version\n"), fp);
@@ -639,13 +627,20 @@ By default it reads standard input and writes standard output.\n\n"), fp);
fflush(fp);
if (ferror(fp)) {
+#ifdef __MINGW32__
+ if (errno == 0 || errno == EINVAL)
+ w32_maybe_set_errno();
+#endif
/* don't warn about stdout/stderr if EPIPE, but do error exit */
- if (errno != EPIPE) {
- if (fp == stdout)
- warning(_("error writing standard output (%s)"), strerror(errno));
- else if (fp == stderr)
- warning(_("error writing standard error (%s)"), strerror(errno));
- }
+ if (errno == EPIPE)
+ die_via_sigpipe();
+
+ if (fp == stdout)
+ warning(_("error writing standard output (%s)"), strerror(errno));
+ else if (fp == stderr)
+ warning(_("error writing standard error (%s)"), strerror(errno));
+
+ // some other problem than SIGPIPE
exit(EXIT_FAILURE);
}
@@ -674,7 +669,7 @@ GNU General Public License for more details.\n\
static const char blurb_part3[] =
N_("You should have received a copy of the GNU General Public License\n\
along with this program. If not, see http://www.gnu.org/licenses/.\n");
-
+
/* multiple blurbs are needed for some brain dead compilers. */
printf(_(blurb_part1), UPDATE_YEAR); /* Last update year */
fputs(_(blurb_part2), stdout);
@@ -682,6 +677,10 @@ along with this program. If not, see http://www.gnu.org/licenses/.\n");
fflush(stdout);
if (ferror(stdout)) {
+#ifdef __MINGW32__
+ if (errno == 0 || errno == EINVAL)
+ w32_maybe_set_errno();
+#endif
/* don't warn about stdout if EPIPE, but do error exit */
if (errno != EPIPE)
warning(_("error writing standard output (%s)"), strerror(errno));
@@ -733,14 +732,14 @@ init_args(int argc0, int argc, const char *argv0, char **argv)
unref(tmp);
unref(*aptr);
*aptr = make_string(argv0, strlen(argv0));
- (*aptr)->flags |= MAYBE_NUM;
+ (*aptr)->flags |= USER_INPUT;
for (i = argc0, j = 1; i < argc; i++, j++) {
tmp = make_number((AWKNUM) j);
aptr = assoc_lookup(ARGV_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(argv[i], strlen(argv[i]));
- (*aptr)->flags |= MAYBE_NUM;
+ (*aptr)->flags |= USER_INPUT;
}
ARGC_node = install_symbol(estrdup("ARGC", 4), Node_var);
@@ -785,7 +784,7 @@ static const struct varinit varinit[] = {
{&FPAT_node, "FPAT", "[^[:space:]]+", 0, NULL, set_FPAT, false, NON_STANDARD },
{&IGNORECASE_node, "IGNORECASE", NULL, 0, NULL, set_IGNORECASE, false, NON_STANDARD },
{&LINT_node, "LINT", NULL, 0, NULL, set_LINT, false, NON_STANDARD },
-{&PREC_node, "PREC", NULL, DEFAULT_PREC, NULL, set_PREC, false, NON_STANDARD},
+{&PREC_node, "PREC", NULL, DEFAULT_PREC, NULL, set_PREC, false, NON_STANDARD},
{&NF_node, "NF", NULL, -1, update_NF, set_NF, false, 0 },
{&NR_node, "NR", NULL, 0, update_NR, set_NR, true, 0 },
{&OFMT_node, "OFMT", "%.6g", 0, NULL, set_OFMT, true, 0 },
@@ -894,7 +893,7 @@ load_environ()
unref(tmp);
unref(*aptr);
*aptr = make_string(val, strlen(val));
- (*aptr)->flags |= MAYBE_NUM;
+ (*aptr)->flags |= USER_INPUT;
/* restore '=' so that system() gets a valid environment */
if (val != nullstr)
@@ -911,9 +910,40 @@ load_environ()
*/
path_environ("AWKPATH", defpath);
path_environ("AWKLIBPATH", deflibpath);
+
+ /* set up array functions */
+ init_env_array(ENVIRON_node);
+
return ENVIRON_node;
}
+static void
+load_procinfo_argv()
+{
+ NODE *tmp;
+ NODE **aptr;
+ NODE *argv_array;
+ int i;
+
+ tmp = make_string("argv", 4);
+ aptr = assoc_lookup(PROCINFO_node, tmp);
+ unref(tmp);
+ unref(*aptr);
+ getnode(argv_array);
+ memset(argv_array, '\0', sizeof(NODE)); /* valgrind wants this */
+ null_array(argv_array);
+ *aptr = argv_array;
+ argv_array->parent_array = PROCINFO_node;
+ argv_array->vname = estrdup("argv", 4);
+ for (i = 0; d_argv[i] != NULL; i++) {
+ tmp = make_number(i);
+ aptr = assoc_lookup(argv_array, tmp);
+ unref(tmp);
+ unref(*aptr);
+ *aptr = make_string(d_argv[i], strlen(d_argv[i]));
+ }
+}
+
/* load_procinfo --- populate the PROCINFO array */
static NODE *
@@ -985,22 +1015,7 @@ load_procinfo()
value = getegid();
update_PROCINFO_num("egid", value);
- switch (current_field_sep()) {
- case Using_FIELDWIDTHS:
- update_PROCINFO_str("FS", "FIELDWIDTHS");
- break;
- case Using_FPAT:
- update_PROCINFO_str("FS", "FPAT");
- break;
- case Using_FS:
- update_PROCINFO_str("FS", "FS");
- break;
- default:
- fatal(_("unknown value for field spec: %d\n"),
- current_field_sep());
- break;
- }
-
+ update_PROCINFO_str("FS", current_field_sep_str());
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
for (i = 0; i < ngroups; i++) {
@@ -1013,6 +1028,7 @@ load_procinfo()
groupset = NULL;
}
#endif
+ load_procinfo_argv();
return PROCINFO_node;
}
@@ -1132,7 +1148,7 @@ arg_assign(char *arg, bool initing)
if (! initing) {
var = lookup(arg);
if (var != NULL && var->type == Node_func)
- fatal(_("cannot use function `%s' as variable name"), arg);
+ fatal(_("cannot use function `%s' as variable name"), arg);
}
/*
@@ -1140,7 +1156,7 @@ arg_assign(char *arg, bool initing)
* This makes sense, so we do it too.
*/
it = make_str_node(cp, strlen(cp), SCAN);
- it->flags |= MAYBE_NUM;
+ it->flags |= USER_INPUT;
#ifdef LC_NUMERIC
/*
* See comment above about locale decimal point.
@@ -1183,7 +1199,7 @@ arg_assign(char *arg, bool initing)
/* catchsig --- catch signals */
-static RETSIGTYPE
+static void
catchsig(int sig)
{
if (sig == SIGFPE) {
@@ -1254,7 +1270,7 @@ version()
#ifdef HAVE_MPFR
printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
#endif
- printf("\n");
+ printf("\n");
print_ext_versions();
/*
@@ -1337,7 +1353,7 @@ estrdup(const char *str, size_t len)
s[len] = '\0';
return s;
}
-
+
#if defined(HAVE_LOCALE_H)
/* init_locale --- initialize locale info. */
@@ -1407,7 +1423,7 @@ long
getenv_long(const char *name)
{
const char *val;
- long newval;
+ long newval;
if ((val = getenv(name)) != NULL && isdigit((unsigned char) *val)) {
for (newval = 0; *val && isdigit((unsigned char) *val); val++)
newval = (newval * 10) + *val - '0';
@@ -1424,7 +1440,7 @@ parse_args(int argc, char **argv)
/*
* The + on the front tells GNU getopt not to rearrange argv.
*/
- const char *optlist = "+F:f:v:W;bcCd::D::e:E:ghi:l:L:nNo::Op::MPrStVYZ:";
+ const char *optlist = "+F:f:v:W;bcCd::D::e:E:ghi:l:L:nNo::Op::MPrSstVYZ:";
int old_optind;
int c;
char *scan;
@@ -1433,7 +1449,7 @@ parse_args(int argc, char **argv)
/* we do error messages ourselves on invalid options */
opterr = false;
- /* copy argv before getopt gets to it; used to restart the debugger */
+ /* copy argv before getopt gets to it; used to restart the debugger */
save_argv(argc, argv);
/* option processing. ready, set, go! */
@@ -1583,7 +1599,11 @@ parse_args(int argc, char **argv)
case 'r':
do_flags |= DO_INTERVALS;
break;
-
+
+ case 's':
+ do_optimize = false;
+ break;
+
case 'S':
do_flags |= DO_SANDBOX;
break;
@@ -1658,6 +1678,8 @@ parse_args(int argc, char **argv)
break;
}
out:
+ do_optimize = (do_optimize && ! do_pretty_print);
+
return;
}
diff --git a/mbsupport.h b/mbsupport.h
index 37dd219d..e7b40423 100644
--- a/mbsupport.h
+++ b/mbsupport.h
@@ -2,23 +2,23 @@
* mbsupport.h --- Localize determination of whether we have multibyte stuff.
*/
-/*
+/*
* Copyright (C) 2004, 2005, 2011, 2012, 2015, 2016
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
diff --git a/missing_d/ChangeLog b/missing_d/ChangeLog
index 19d57042..7d9bddc4 100644
--- a/missing_d/ChangeLog
+++ b/missing_d/ChangeLog
@@ -1,3 +1,11 @@
+2017-06-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * getaddrinfo.c (getaddrinfo): Replace malloc+memset with calloc.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+
2016-09-07 Arnold D. Robbins <arnold@skeeve.com>
* setenv.c: Update license text in setenv.c. Thanks
@@ -16,6 +24,12 @@
* 4.1.2: Release tar ball made.
+2015-02-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * getaddrinfo.h (gai_strerror): Add declaration.
+ * getaddrinfo.c (gai_strerror): New function.
+ (getaddrinfo): Return errno values instead of just -1.
+
2014-04-08 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.1: Release tar ball made.
diff --git a/missing_d/getaddrinfo.c b/missing_d/getaddrinfo.c
index 677f27d0..5233cf56 100644
--- a/missing_d/getaddrinfo.c
+++ b/missing_d/getaddrinfo.c
@@ -12,6 +12,8 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#include <errno.h>
+#include <string.h> /* strerror */
#include "getaddrinfo.h"
@@ -29,20 +31,19 @@ getaddrinfo(const char *hostname, const char *portname,
{
struct addrinfo *out;
if (res == NULL)
- return -1;
+ return EINVAL;
- out = (struct addrinfo *) malloc(sizeof(*out));
+ out = (struct addrinfo *) calloc(1, sizeof(*out));
if (out == NULL) {
*res = NULL;
- return -1;
+ return ENOMEM;
}
- memset(out, '\0', sizeof(*out));
out->ai_addr = (struct sockaddr *) malloc(sizeof(struct sockaddr_in));
if (out->ai_addr == NULL) {
free(out);
*res = NULL;
- return -1;
+ return ENOMEM;
}
out->ai_socktype = SOCK_STREAM;
@@ -78,7 +79,7 @@ getaddrinfo(const char *hostname, const char *portname,
= ((struct in_addr *)he->h_addr_list[0])->s_addr;
} else {
freeaddrinfo(out);
- return -1;
+ return EADDRNOTAVAIL;
}
} else {
if (!(out->ai_flags & AI_PASSIVE))
@@ -109,4 +110,10 @@ getaddrinfo(const char *hostname, const char *portname,
return 0;
}
+
+const char *
+gai_strerror(int errcode)
+{
+ return strerror(errcode);
+}
#endif
diff --git a/missing_d/getaddrinfo.h b/missing_d/getaddrinfo.h
index 3d816c93..873d67df 100644
--- a/missing_d/getaddrinfo.h
+++ b/missing_d/getaddrinfo.h
@@ -29,3 +29,5 @@ void freeaddrinfo(struct xaddrinfo * res);
int getaddrinfo(const char * hostname, const char * portname,
struct xaddrinfo * hints, struct xaddrinfo ** res);
+
+const char *gai_strerror(int errcode);
diff --git a/missing_d/snprintf.c b/missing_d/snprintf.c
index 6cee2bed..9d692d5a 100644
--- a/missing_d/snprintf.c
+++ b/missing_d/snprintf.c
@@ -2,22 +2,22 @@
* snprintf.c - Implement snprintf and vsnprintf on platforms that need them.
*/
-/*
+/*
* Copyright (C) 2006, 2007 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
diff --git a/mpfr.c b/mpfr.c
index db2eb697..c83a57b3 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -2,22 +2,22 @@
* mpfr.c - routines for arbitrary-precision number support in gawk.
*/
-/*
+/*
* Copyright (C) 2012, 2013, 2015 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -118,7 +118,7 @@ mpg_node(unsigned int tp)
mpz_init(r->mpg_i);
r->flags = MPZN;
}
-
+
r->valref = 1;
r->flags |= MALLOC|NUMBER|NUMCUR;
r->stptr = NULL;
@@ -151,7 +151,7 @@ mpg_make_number(double x)
return r;
}
-/* mpg_strtoui --- assign arbitrary-precision integral value from a string */
+/* mpg_strtoui --- assign arbitrary-precision integral value from a string */
int
mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
@@ -264,7 +264,7 @@ mpg_zero(NODE *n)
n->flags &= ~MPFN;
}
if (! is_mpg_integer(n)) {
- mpz_init(n->mpg_i); /* this also sets its value to 0 */
+ mpz_init(n->mpg_i); /* this also sets its value to 0 */
n->flags |= MPZN;
} else
mpz_set_si(n->mpg_i, 0);
@@ -303,7 +303,7 @@ force_mpnum(NODE *n, int do_nondec, int use_locale)
cp1 = cp;
if (do_nondec)
- base = get_numbase(cp1, use_locale);
+ base = get_numbase(cp1, cpend - cp1, use_locale);
if (! mpg_maybe_float(cp1, use_locale)) {
mpg_zero(n);
@@ -329,13 +329,13 @@ force_mpnum(NODE *n, int do_nondec, int use_locale)
IEEE_FMT(n->mpg_numbr, tval);
done:
/* trailing space is OK for NUMBER */
- while (isspace((unsigned char) *ptr))
+ while (ptr < cpend && isspace((unsigned char) *ptr))
ptr++;
*cpend = save;
if (errno == 0 && ptr == cpend)
return true;
errno = 0;
- return false;
+ return false;
}
/* mpg_force_number --- force a value to be a multiple-precision number */
@@ -343,20 +343,18 @@ done:
static NODE *
mpg_force_number(NODE *n)
{
- unsigned int newflags = 0;
-
- if (is_mpg_number(n) && (n->flags & NUMCUR) != 0)
+ if ((n->flags & NUMCUR) != 0)
return n;
-
- if ((n->flags & MAYBE_NUM) != 0) {
- n->flags &= ~MAYBE_NUM;
- newflags = NUMBER;
- }
+ n->flags |= NUMCUR;
if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), true)) {
- n->flags |= newflags;
- n->flags |= NUMCUR;
- }
+ if ((n->flags & USER_INPUT) != 0) {
+ /* leave USER_INPUT set to indicate a strnum */
+ n->flags &= ~STRING;
+ n->flags |= NUMBER;
+ }
+ } else
+ n->flags &= ~USER_INPUT;
return n;
}
@@ -375,7 +373,7 @@ mpg_format_val(const char *format, int index, NODE *s)
if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) {
/* integral value, use %d */
r = format_tree("%d", 2, dummy, 2);
- s->stfmt = -1;
+ s->stfmt = STFMT_UNUSED;
} else {
r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
assert(r != NULL);
@@ -383,12 +381,11 @@ mpg_format_val(const char *format, int index, NODE *s)
}
s->flags = oflags;
s->stlen = r->stlen;
- if ((s->flags & STRCUR) != 0)
+ if ((s->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
efree(s->stptr);
s->stptr = r->stptr;
- freenode(r); /* Do not unref(r)! We want to keep s->stptr == r->stpr. */
-
s->flags |= STRCUR;
+ freenode(r); /* Do not unref(r)! We want to keep s->stptr == r->stpr. */
free_wstr(s);
return s;
}
@@ -430,8 +427,8 @@ mpg_cmp(const NODE *t1, const NODE *t2)
/*
- * mpg_update_var --- update NR or FNR.
- * NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long)
+ * mpg_update_var --- update NR or FNR.
+ * NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long)
*/
NODE *
@@ -485,7 +482,7 @@ mpg_set_var(NODE *n)
if (is_mpg_integer(val))
r = val->mpg_i;
else {
- /* convert float to integer */
+ /* convert float to integer */
mpfr_get_z(mpzval, val->mpg_numbr, MPFR_RNDZ);
r = mpzval;
}
@@ -506,11 +503,11 @@ set_PREC()
mpfr_exp_t emax;
mpfr_exp_t emin;
} ieee_fmts[] = {
-{ "half", 11, 16, -23 }, /* binary16 */
-{ "single", 24, 128, -148 }, /* binary32 */
-{ "double", 53, 1024, -1073 }, /* binary64 */
-{ "quad", 113, 16384, -16493 }, /* binary128 */
-{ "oct", 237, 262144, -262377 }, /* binary256, not in the IEEE 754-2008 standard */
+ { "half", 11, 16, -23 }, /* binary16 */
+ { "single", 24, 128, -148 }, /* binary32 */
+ { "double", 53, 1024, -1073 }, /* binary64 */
+ { "quad", 113, 16384, -16493 }, /* binary128 */
+ { "oct", 237, 262144, -262377 }, /* binary256, not in the IEEE 754-2008 standard */
/*
* For any bitwidth = 32 * k ( k >= 4),
@@ -523,11 +520,9 @@ set_PREC()
if (! do_mpfr)
return;
- val = PREC_node->var_value;
- if ((val->flags & MAYBE_NUM) != 0)
- force_number(val);
+ val = fixtype(PREC_node->var_value);
- if ((val->flags & STRCUR) != 0) {
+ if ((val->flags & STRING) != 0) {
int i, j;
/* emulate IEEE-754 binary format */
@@ -553,7 +548,7 @@ set_PREC()
if (prec <= 0) {
force_number(val);
- prec = get_number_si(val);
+ prec = get_number_si(val);
if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
force_string(val);
warning(_("PREC value `%.*s' is invalid"), (int) val->stlen, val->stptr);
@@ -677,9 +672,9 @@ do_mpfr_atan2(int nargs)
t1 = POP_SCALAR();
if (do_lint) {
- if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(t1)->flags & NUMBER) == 0)
lintwarn(_("atan2: received non-numeric first argument"));
- if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+ if ((fixtype(t2)->flags & NUMBER) == 0)
lintwarn(_("atan2: received non-numeric second argument"));
}
force_number(t1);
@@ -688,7 +683,7 @@ do_mpfr_atan2(int nargs)
p1 = MP_FLOAT(t1);
p2 = MP_FLOAT(t2);
res = mpg_float();
- /* See MPFR documentation for handling of special values like +inf as an argument */
+ /* See MPFR documentation for handling of special values like +inf as an argument */
tval = mpfr_atan2(res->mpg_numbr, p1, p2, ROUND_MODE);
IEEE_FMT(res->mpg_numbr, tval);
@@ -710,7 +705,7 @@ do_mpfr_func(const char *name,
mpfr_prec_t argprec;
t1 = POP_SCALAR();
- if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(t1)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), name);
force_number(t1);
@@ -777,7 +772,7 @@ do_mpfr_int(int nargs)
NODE *tmp, *r;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("int: received non-numeric argument"));
force_number(tmp);
@@ -807,7 +802,7 @@ do_mpfr_compl(int nargs)
mpz_ptr zptr;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("compl: received non-numeric argument"));
force_number(tmp);
@@ -818,28 +813,26 @@ do_mpfr_compl(int nargs)
/* [+-]inf or NaN */
return tmp;
}
- if (do_lint) {
- if (mpfr_sgn(p) < 0)
- lintwarn("%s",
- mpg_fmt(_("compl(%Rg): negative value will give strange results"), p)
+ if (mpfr_sgn(p) < 0)
+ fatal("%s",
+ mpg_fmt(_("compl(%Rg): negative value is not allowed"), p)
);
+ if (do_lint) {
if (! mpfr_integer_p(p))
lintwarn("%s",
mpg_fmt(_("comp(%Rg): fractional value will be truncated"), p)
);
}
-
+
mpfr_get_z(mpzval, p, MPFR_RNDZ); /* float to integer conversion */
zptr = mpzval;
} else {
- /* (tmp->flags & MPZN) != 0 */
+ /* (tmp->flags & MPZN) != 0 */
zptr = tmp->mpg_i;
- if (do_lint) {
- if (mpz_sgn(zptr) < 0)
- lintwarn("%s",
- mpg_fmt(_("cmpl(%Zd): negative values will give strange results"), zptr)
+ if (mpz_sgn(zptr) < 0)
+ fatal("%s",
+ mpg_fmt(_("compl(%Zd): negative values is not allowed"), zptr)
);
- }
}
r = mpg_integer();
@@ -855,7 +848,7 @@ get_intval(NODE *t1, int argnum, const char *op)
{
mpz_ptr pz;
- if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(t1)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument #%d"), op, argnum);
(void) force_number(t1);
@@ -875,13 +868,13 @@ get_intval(NODE *t1, int argnum, const char *op)
return pz; /* should be freed */
}
- if (do_lint) {
- if (mpfr_sgn(left) < 0)
- lintwarn("%s",
- mpg_fmt(_("%s: argument #%d negative value %Rg will give strange results"),
+ if (mpfr_sgn(left) < 0)
+ fatal("%s",
+ mpg_fmt(_("%s: argument #%d negative value %Rg is not allowed"),
op, argnum, left)
);
+ if (do_lint) {
if (! mpfr_integer_p(left))
lintwarn("%s",
mpg_fmt(_("%s: argument #%d fractional value %Rg will be truncated"),
@@ -893,16 +886,15 @@ get_intval(NODE *t1, int argnum, const char *op)
mpz_init(pz);
mpfr_get_z(pz, left, MPFR_RNDZ); /* float to integer conversion */
return pz; /* should be freed */
- }
- /* (t1->flags & MPZN) != 0 */
+ }
+ /* (t1->flags & MPZN) != 0 */
pz = t1->mpg_i;
- if (do_lint) {
- if (mpz_sgn(pz) < 0)
- lintwarn("%s",
- mpg_fmt(_("%s: argument #%d negative value %Zd will give strange results"),
+ if (mpz_sgn(pz) < 0)
+ fatal("%s",
+ mpg_fmt(_("%s: argument #%d negative value %Zd is not allowed"),
op, argnum, pz)
);
- }
+
return pz; /* must not be freed */
}
@@ -927,7 +919,7 @@ do_mpfr_lshift(int nargs)
NODE *t1, *t2, *res;
unsigned long shift;
mpz_ptr pz1, pz2;
-
+
t2 = POP_SCALAR();
t1 = POP_SCALAR();
@@ -959,7 +951,7 @@ do_mpfr_rshift(int nargs)
NODE *t1, *t2, *res;
unsigned long shift;
mpz_ptr pz1, pz2;
-
+
t2 = POP_SCALAR();
t1 = POP_SCALAR();
@@ -969,7 +961,7 @@ do_mpfr_rshift(int nargs)
/* N.B: See do_mpfp_lshift. */
shift = mpz_get_ui(pz2); /* GMP integer => unsigned long conversion */
res = mpg_integer();
- mpz_fdiv_q_2exp(res->mpg_i, pz1, shift); /* res = pz1 / 2^shift, round towards −inf */
+ mpz_fdiv_q_2exp(res->mpg_i, pz1, shift); /* res = pz1 / 2^shift, round towards -inf */
free_intval(t1, pz1);
free_intval(t2, pz2);
@@ -1080,25 +1072,24 @@ do_mpfr_strtonum(int nargs)
{
NODE *tmp, *r;
- tmp = POP_SCALAR();
- if ((tmp->flags & (NUMBER|NUMCUR)) == 0) {
+ tmp = fixtype(POP_SCALAR());
+ if ((tmp->flags & NUMBER) == 0) {
r = mpg_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */
r->stptr = tmp->stptr;
r->stlen = tmp->stlen;
force_mpnum(r, true, use_lc_numeric);
r->stptr = NULL;
r->stlen = 0;
+ r->wstptr = NULL;
+ r->wstlen = 0;
+ } else if (is_mpg_float(tmp)) {
+ int tval;
+ r = mpg_float();
+ tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
} else {
- (void) force_number(tmp);
- if (is_mpg_float(tmp)) {
- int tval;
- r = mpg_float();
- tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- } else {
- r = mpg_integer();
- mpz_set(r->mpg_i, tmp->mpg_i);
- }
+ r = mpg_integer();
+ mpz_set(r->mpg_i, tmp->mpg_i);
}
DEREF(tmp);
@@ -1176,7 +1167,7 @@ do_mpfr_srand(int nargs)
else {
NODE *tmp;
tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("srand: received non-numeric argument"));
force_number(tmp);
if (is_mpg_float(tmp))
@@ -1190,6 +1181,100 @@ do_mpfr_srand(int nargs)
return res;
}
+/* do_mpfr_intdiv --- do integer division, return quotient and remainder in dest array */
+
+/*
+ * We define the semantics as:
+ * numerator = int(numerator)
+ * denominator = int(denonmator)
+ * quotient = int(numerator / denomator)
+ * remainder = int(numerator % denomator)
+ */
+
+NODE *
+do_mpfr_intdiv(int nargs)
+{
+ NODE *numerator, *denominator, *result;
+ NODE *num, *denom;
+ NODE *quotient, *remainder;
+ NODE *sub, **lhs;
+
+ result = POP_PARAM();
+ if (result->type != Node_var_array)
+ fatal(_("intdiv: third argument is not an array"));
+ assoc_clear(result);
+
+ denominator = POP_SCALAR();
+ numerator = POP_SCALAR();
+
+ if (do_lint) {
+ if ((fixtype(numerator)->flags & NUMBER) == 0)
+ lintwarn(_("intdiv: received non-numeric first argument"));
+ if ((fixtype(denominator)->flags & NUMBER) == 0)
+ lintwarn(_("intdiv: received non-numeric second argument"));
+ }
+
+ (void) force_number(numerator);
+ (void) force_number(denominator);
+
+ /* convert numerator and denominator to integer */
+ if (is_mpg_integer(numerator)) {
+ num = mpg_integer();
+ mpz_set(num->mpg_i, numerator->mpg_i);
+ } else {
+ if (! mpfr_number_p(numerator->mpg_numbr)) {
+ /* [+-]inf or NaN */
+ unref(numerator);
+ unref(denominator);
+ return make_number((AWKNUM) -1);
+ }
+
+ num = mpg_integer();
+ mpfr_get_z(num->mpg_i, numerator->mpg_numbr, MPFR_RNDZ);
+ }
+
+ if (is_mpg_integer(denominator)) {
+ denom = mpg_integer();
+ mpz_set(denom->mpg_i, denominator->mpg_i);
+ } else {
+ if (! mpfr_number_p(denominator->mpg_numbr)) {
+ /* [+-]inf or NaN */
+ unref(numerator);
+ unref(denominator);
+ unref(num);
+ return make_number((AWKNUM) -1);
+ }
+
+ denom = mpg_integer();
+ mpfr_get_z(denom->mpg_i, denominator->mpg_numbr, MPFR_RNDZ);
+ }
+
+ if (mpz_sgn(denom->mpg_i) == 0)
+ fatal(_("intdiv: division by zero attempted"));
+
+ quotient = mpg_integer();
+ remainder = mpg_integer();
+
+ /* do the division */
+ mpz_tdiv_qr(quotient->mpg_i, remainder->mpg_i, num->mpg_i, denom->mpg_i);
+ unref(num);
+ unref(denom);
+ unref(numerator);
+ unref(denominator);
+
+ sub = make_string("quotient", 8);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = quotient;
+
+ sub = make_string("remainder", 9);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = remainder;
+
+ return make_number((AWKNUM) 0.0);
+}
+
/*
* mpg_tofloat --- convert an arbitrary-precision integer operand to
* a float without loss of precision. It is assumed that the
@@ -1204,13 +1289,13 @@ mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
/*
* When implicitely converting a GMP integer operand to a MPFR float, use
* a precision sufficiently large to hold the converted value exactly.
- *
+ *
* $ ./gawk -M 'BEGIN { print 13 % 2 }'
* 1
* If the user-specified precision is used to convert the integer 13 to a
* float, one will get:
* $ ./gawk -M 'BEGIN { PREC=2; print 13 % 2.0 }'
- * 0
+ * 0
*/
prec = mpz_sizeinbase(mz, 2); /* most significant 1 bit position starting at 1 */
@@ -1224,7 +1309,7 @@ mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
else
prec = PRECISION_MIN;
/*
- * Always set the precision to avoid hysteresis, since do_mpfr_func
+ * Always set the precision to avoid hysteresis, since do_mpfr_func
* may copy our precision.
*/
if (prec != mpfr_get_prec(mf))
@@ -1235,7 +1320,7 @@ mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
}
-/* mpg_add --- add arbitrary-precision numbers */
+/* mpg_add --- add arbitrary-precision numbers */
static NODE *
mpg_add(NODE *t1, NODE *t2)
@@ -1318,7 +1403,7 @@ mpg_mul(NODE *t1, NODE *t2)
}
-/* mpg_pow --- exponentiation involving arbitrary-precision numbers */
+/* mpg_pow --- exponentiation involving arbitrary-precision numbers */
static NODE *
mpg_pow(NODE *t1, NODE *t2)
@@ -1417,11 +1502,11 @@ mpg_mod(NODE *t1, NODE *t2)
}
return r;
}
-
+
/*
* mpg_interpret --- pre-exec hook in the interpreter. Handles
* arithmetic operations with MPFR/GMP numbers.
- */
+ */
static int
mpg_interpret(INSTRUCTION **cp)
@@ -1502,7 +1587,7 @@ quotient:
if (op == Op_quotient)
DEREF(t2);
REPLACE(r);
- break;
+ break;
case Op_mod_i:
t2 = force_number(pc->memory);
diff --git a/msg.c b/msg.c
index b89254e6..2902a48b 100644
--- a/msg.c
+++ b/msg.c
@@ -2,23 +2,23 @@
* msg.c - routines for error messages.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2001, 2003, 2010-2013
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -76,19 +76,21 @@ err(bool isfatal, const char *s, const char *emsg, va_list argp)
val = mpg_update_var(FNR_node);
assert((val->flags & MPZN) != 0);
if (mpz_sgn(val->mpg_i) > 0) {
+ int len = FILENAME_node->var_value->stlen;
file = FILENAME_node->var_value->stptr;
(void) putc('(', stderr);
if (file)
- (void) fprintf(stderr, "FILENAME=%s ", file);
+ (void) fprintf(stderr, "FILENAME=%.*s ", len, file);
(void) mpfr_fprintf(stderr, "FNR=%Zd) ", val->mpg_i);
}
} else
#endif
if (FNR > 0) {
+ int len = FILENAME_node->var_value->stlen;
file = FILENAME_node->var_value->stptr;
(void) putc('(', stderr);
if (file)
- (void) fprintf(stderr, "FILENAME=%s ", file);
+ (void) fprintf(stderr, "FILENAME=%.*s ", len, file);
(void) fprintf(stderr, "FNR=%ld) ", FNR);
}
diff --git a/node.c b/node.c
index b63017aa..200d61dc 100644
--- a/node.c
+++ b/node.c
@@ -2,23 +2,23 @@
* node.c -- routines for node management
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2001, 2003-2015,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -30,7 +30,7 @@
static int is_ieee_magic_val(const char *val);
static NODE *r_make_number(double x);
-static AWKNUM get_ieee_magic_val(const char *val);
+static AWKNUM get_ieee_magic_val(char *val);
extern NODE **fmt_list; /* declared in eval.c */
NODE *(*make_number)(double) = r_make_number;
@@ -41,12 +41,13 @@ int (*cmp_numbers)(const NODE *, const NODE *) = cmp_awknums;
/* is_hex --- return true if a string looks like a hex value */
static bool
-is_hex(const char *str)
+is_hex(const char *str, const char *cpend)
{
+ /* on entry, we know the string length is >= 1 */
if (*str == '-' || *str == '+')
str++;
- if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ if (str + 1 < cpend && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
return true;
return false;
@@ -61,23 +62,35 @@ r_force_number(NODE *n)
char *cpend;
char save;
char *ptr;
- unsigned int newflags;
extern double strtod();
if ((n->flags & NUMCUR) != 0)
return n;
- /* all the conditionals are an attempt to avoid the expensive strtod */
+ /*
+ * We should always set NUMCUR. If USER_INPUT is set and it's a
+ * numeric string, we clear STRING and enable NUMBER, but if it's not
+ * numeric, we disable USER_INPUT.
+ */
- /* Note: only set NUMCUR if we actually convert some digits */
+ /* All the conditionals are an attempt to avoid the expensive strtod */
+ n->flags |= NUMCUR;
n->numbr = 0.0;
- if (n->stlen == 0) {
- return n;
- }
+ /* Trim leading white space, bailing out if there's nothing else */
+ for (cp = n->stptr, cpend = cp + n->stlen;
+ cp < cpend && isspace((unsigned char) *cp); cp++)
+ continue;
+
+ if (cp == cpend)
+ goto badnum;
+
+ /* At this point, we know the string is not entirely white space */
+ /* Trim trailing white space */
+ while (isspace((unsigned char) cpend[-1]))
+ cpend--;
- cp = n->stptr;
/*
* 2/2007:
* POSIX, by way of severe language lawyering, seems to
@@ -86,80 +99,52 @@ r_force_number(NODE *n)
* This also allows hexadecimal floating point. Ugh.
*/
if (! do_posix) {
- if (is_alpha((unsigned char) *cp)) {
- return n;
- } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
- if ((n->flags & MAYBE_NUM) != 0)
- n->flags &= ~MAYBE_NUM;
- n->flags |= NUMBER|NUMCUR;
- n->flags &= ~STRING;
- n->numbr = get_ieee_magic_val(n->stptr);
-
- return n;
+ if (is_alpha((unsigned char) *cp))
+ goto badnum;
+ else if (cpend == cp+4 && is_ieee_magic_val(cp)) {
+ n->numbr = get_ieee_magic_val(cp);
+ goto goodnum;
}
/* else
fall through */
}
- /* else not POSIX, so
+ /* else POSIX, so
fall through */
- cpend = cp + n->stlen;
- while (cp < cpend && isspace((unsigned char) *cp))
- cp++;
-
- if ( cp == cpend /* only spaces, or */
- || (! do_posix /* not POSIXLY paranoid and */
+ if ( (! do_posix /* not POSIXLY paranoid and */
&& (is_alpha((unsigned char) *cp) /* letter, or */
/* CANNOT do non-decimal and saw 0x */
- || (! do_non_decimal_data && is_hex(cp))))) {
- return n;
+ || (! do_non_decimal_data && is_hex(cp, cpend))))) {
+ goto badnum;
}
- if ((n->flags & MAYBE_NUM) != 0) {
- newflags = NUMBER;
- n->flags &= ~MAYBE_NUM;
- } else
- newflags = 0;
-
if (cpend - cp == 1) { /* only one character */
if (isdigit((unsigned char) *cp)) { /* it's a digit! */
n->numbr = (AWKNUM)(*cp - '0');
- n->flags |= newflags;
- n->flags |= NUMCUR;
- n->flags &= ~STRING;
- if (cp == n->stptr) /* no leading spaces */
+ if (n->stlen == 1) /* no white space */
n->flags |= NUMINT;
+ goto goodnum;
}
- return n;
+ goto badnum;
}
- if (do_non_decimal_data) { /* main.c assures false if do_posix */
- errno = 0;
- if (! do_traditional && get_numbase(cp, true) != 10) {
- n->numbr = nondec2awknum(cp, cpend - cp);
- n->flags |= NUMCUR;
- n->flags &= ~STRING;
- ptr = cpend;
- goto finish;
- }
+ errno = 0;
+ if (do_non_decimal_data /* main.c assures false if do_posix */
+ && ! do_traditional && get_numbase(cp, cpend - cp, true) != 10) {
+ /* nondec2awknum() saves and restores the byte after the string itself */
+ n->numbr = nondec2awknum(cp, cpend - cp, &ptr);
+ } else {
+ save = *cpend;
+ *cpend = '\0';
+ n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
+ *cpend = save;
}
- errno = 0;
- save = *cpend;
- *cpend = '\0';
- n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
-
- /* POSIX says trailing space is OK for NUMBER */
- while (isspace((unsigned char) *ptr))
- ptr++;
- *cpend = save;
-finish:
if (errno == 0) {
- if (ptr == cpend) {
- n->flags |= newflags;
- n->flags |= NUMCUR;
- }
+ if (ptr == cpend)
+ goto goodnum;
/* else keep the leading numeric value without updating flags */
+ /* fall through to badnum */
} else {
errno = 0;
/*
@@ -168,15 +153,29 @@ finish:
* We force the numeric value to 0 in such cases.
*/
n->numbr = 0;
+ /*
+ * Or should we accept it as a NUMBER even though strtod
+ * threw an error?
+ */
+ /* fall through to badnum */
}
+badnum:
+ n->flags &= ~USER_INPUT;
+ return n;
+goodnum:
+ if ((n->flags & USER_INPUT) != 0) {
+ /* leave USER_INPUT enabled to indicate that this is a strnum */
+ n->flags &= ~STRING;
+ n->flags |= NUMBER;
+ }
return n;
}
/*
* The following lookup table is used as an optimization in force_string;
- * (more complicated) variations on this theme didn't seem to pay off, but
+ * (more complicated) variations on this theme didn't seem to pay off, but
* systematic testing might be in order at some point.
*/
static const char *values[] = {
@@ -227,7 +226,7 @@ r_format_val(const char *format, int index, NODE *s)
* Once upon a time, we just blindly did this:
* sprintf(sp, format, s->numbr);
* s->stlen = strlen(sp);
- * s->stfmt = (char) index;
+ * s->stfmt = index;
* but that's no good if, e.g., OFMT is %s. So we punt,
* and just always format the value ourselves.
*/
@@ -242,7 +241,7 @@ r_format_val(const char *format, int index, NODE *s)
if (val == s->numbr) {
/* integral value, but outside range of %ld, use %.0f */
r = format_tree("%.0f", 4, dummy, 2);
- s->stfmt = -1;
+ s->stfmt = STFMT_UNUSED;
} else {
r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
assert(r != NULL);
@@ -250,7 +249,7 @@ r_format_val(const char *format, int index, NODE *s)
}
s->flags = oflags;
s->stlen = r->stlen;
- if ((s->flags & STRCUR) != 0)
+ if ((s->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
efree(s->stptr);
s->stptr = r->stptr;
freenode(r); /* Do not unref(r)! We want to keep s->stptr == r->stpr. */
@@ -269,15 +268,15 @@ r_format_val(const char *format, int index, NODE *s)
(void) sprintf(sp, "%ld", num);
s->stlen = strlen(sp);
}
- s->stfmt = -1;
+ s->stfmt = STFMT_UNUSED;
if ((s->flags & INTIND) != 0) {
s->flags &= ~(INTIND|NUMBER);
s->flags |= STRING;
}
}
- if (s->stptr != NULL)
+ if ((s->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
efree(s->stptr);
- emalloc(s->stptr, char *, s->stlen + 2, "format_val");
+ emalloc(s->stptr, char *, s->stlen + 1, "format_val");
memcpy(s->stptr, sp, s->stlen + 1);
no_malloc:
s->flags |= STRCUR;
@@ -303,7 +302,6 @@ r_dupnode(NODE *n)
getnode(r);
*r = *n;
- r->flags &= ~FIELD;
r->flags |= MALLOC;
r->valref = 1;
/*
@@ -315,18 +313,18 @@ r_dupnode(NODE *n)
r->wstlen = 0;
if ((n->flags & STRCUR) != 0) {
- emalloc(r->stptr, char *, n->stlen + 2, "r_dupnode");
+ emalloc(r->stptr, char *, n->stlen + 1, "r_dupnode");
memcpy(r->stptr, n->stptr, n->stlen);
r->stptr[n->stlen] = '\0';
if ((n->flags & WSTRCUR) != 0) {
r->wstlen = n->wstlen;
- emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 2), "r_dupnode");
+ emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 1), "r_dupnode");
memcpy(r->wstptr, n->wstptr, n->wstlen * sizeof(wchar_t));
r->wstptr[n->wstlen] = L'\0';
r->flags |= WSTRCUR;
}
}
-
+
return r;
}
@@ -386,18 +384,18 @@ make_str_node(const char *s, size_t len, int flags)
r->numbr = 0;
r->flags = (MALLOC|STRING|STRCUR);
r->valref = 1;
- r->stfmt = -1;
+ r->stfmt = STFMT_UNUSED;
r->wstptr = NULL;
r->wstlen = 0;
if ((flags & ALREADY_MALLOCED) != 0)
r->stptr = (char *) s;
else {
- emalloc(r->stptr, char *, len + 2, "make_str_node");
+ emalloc(r->stptr, char *, len + 1, "make_str_node");
memcpy(r->stptr, s, len);
}
r->stptr[len] = '\0';
-
+
if ((flags & SCAN) != 0) { /* scan for escape sequences */
const char *pf;
char *ptm;
@@ -447,6 +445,27 @@ make_str_node(const char *s, size_t len, int flags)
return r;
}
+/* make_typed_regex --- make a typed regex node */
+
+NODE *
+make_typed_regex(const char *re, size_t len)
+{
+ NODE *n, *exp, *n2;
+
+ exp = make_str_node(re, len, ALREADY_MALLOCED);
+ n = make_regnode(Node_regex, exp);
+ if (n == NULL)
+ fatal(_("could not make typed regex"));
+
+ n2 = make_string(re, len);
+ n2->typed_re = n;
+ n2->numbr = 0;
+ n2->flags |= NUMCUR|STRCUR|REGEX;
+ n2->flags &= ~(STRING|NUMBER);
+
+ return n2;
+}
+
/* unref --- remove reference to a particular node */
@@ -481,16 +500,16 @@ r_unref(NODE *tmp)
*
* Parse a C escape sequence. STRING_PTR points to a variable containing a
* pointer to the string to parse. That pointer is updated past the
- * characters we use. The value of the escape sequence is returned.
+ * characters we use. The value of the escape sequence is returned.
*
* A negative value means the sequence \ newline was seen, which is supposed to
- * be equivalent to nothing at all.
+ * be equivalent to nothing at all.
*
* If \ is followed by a null character, we return a negative value and leave
- * the string pointer pointing at the null character.
+ * the string pointer pointing at the null character.
*
* If \ is followed by 000, we return 0 and leave the string pointer after the
- * zeros. A value of 0 does not mean end of string.
+ * zeros. A value of 0 does not mean end of string.
*
* POSIX doesn't allow \x.
*/
@@ -570,9 +589,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)) {
@@ -614,7 +632,7 @@ parse_escape(const char **string_ptr)
/* get_numbase --- return the base to use for the number in 's' */
int
-get_numbase(const char *s, bool use_locale)
+get_numbase(const char *s, size_t len, bool use_locale)
{
int dec_point = '.';
const char *str = s;
@@ -628,7 +646,7 @@ get_numbase(const char *s, bool use_locale)
dec_point = loc.decimal_point[0]; /* XXX --- assumes one char */
#endif
- if (str[0] != '0')
+ if (len < 2 || str[0] != '0')
return 10;
/* leading 0x or 0X */
@@ -641,7 +659,7 @@ get_numbase(const char *s, bool use_locale)
*
* These beasts can have trailing whitespace. Deal with that too.
*/
- for (; *str != '\0'; str++) {
+ for (; len > 0; len--, str++) {
if (*str == 'e' || *str == 'E' || *str == dec_point)
return 10;
else if (! isdigit((unsigned char) *str))
@@ -698,7 +716,7 @@ str2wstr(NODE *n, size_t **ptr)
* realloc the wide string down in size.
*/
- emalloc(n->wstptr, wchar_t *, sizeof(wchar_t) * (n->stlen + 2), "str2wstr");
+ emalloc(n->wstptr, wchar_t *, sizeof(wchar_t) * (n->stlen + 1), "str2wstr");
wsp = n->wstptr;
/*
@@ -710,8 +728,7 @@ str2wstr(NODE *n, size_t **ptr)
* Create the array.
*/
if (ptr != NULL) {
- emalloc(*ptr, size_t *, sizeof(size_t) * n->stlen, "str2wstr");
- memset(*ptr, 0, sizeof(size_t) * n->stlen);
+ ezalloc(*ptr, size_t *, sizeof(size_t) * n->stlen, "str2wstr");
}
sp = n->stptr;
@@ -756,7 +773,7 @@ str2wstr(NODE *n, size_t **ptr)
* stopping early. This is particularly important
* for match() where we need to build the indices.
*/
- if (dfa_using_utf8()) {
+ if (using_utf8()) {
count = 1;
wc = 0xFFFD; /* unicode replacement character */
goto set_wc;
@@ -788,7 +805,7 @@ str2wstr(NODE *n, size_t **ptr)
n->flags |= WSTRCUR;
#define ARBITRARY_AMOUNT_TO_GIVE_BACK 100
if (n->stlen - n->wstlen > ARBITRARY_AMOUNT_TO_GIVE_BACK)
- erealloc(n->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 2), "str2wstr");
+ erealloc(n->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 1), "str2wstr");
return n;
}
@@ -815,7 +832,7 @@ wstr2str(NODE *n)
memset(& mbs, 0, sizeof(mbs));
length = n->wstlen;
- emalloc(newval, char *, (length * gawk_mb_cur_max) + 2, "wstr2str");
+ emalloc(newval, char *, (length * gawk_mb_cur_max) + 1, "wstr2str");
wp = n->wstptr;
for (cp = newval; length > 0; length--) {
@@ -827,6 +844,7 @@ wstr2str(NODE *n)
}
*cp = '\0';
+ /* N.B. caller just created n with make_string, so this free is safe */
efree(n->stptr);
n->stptr = newval;
n->stlen = cp - newval;
@@ -941,14 +959,18 @@ is_ieee_magic_val(const char *val)
/* get_ieee_magic_val --- return magic value for string */
static AWKNUM
-get_ieee_magic_val(const char *val)
+get_ieee_magic_val(char *val)
{
static bool first = true;
static AWKNUM inf;
static AWKNUM nan;
+ char save;
char *ptr;
+ save = val[4];
+ val[4] = '\0';
AWKNUM v = strtod(val, &ptr);
+ val[4] = save;
if (val == ptr) { /* Older strtod implementations don't support inf or nan. */
if (first) {
@@ -980,32 +1002,32 @@ void init_btowc_cache()
#define BLOCKCHUNK 100
-BLOCK nextfree[BLOCK_MAX] = {
- { 0, NULL}, /* invalid */
- { sizeof(NODE), NULL },
- { sizeof(BUCKET), NULL },
+struct block_header nextfree[BLOCK_MAX] = {
+ { NULL, sizeof(NODE) },
+ { NULL, sizeof(BUCKET) },
};
/* more_blocks --- get more blocks of memory and add to the free list;
- size of a block must be >= sizeof(BLOCK)
+ size of a block must be >= sizeof(struct block_item)
*/
void *
more_blocks(int id)
{
- BLOCK *freep, *np, *next;
+ struct block_item *freep, *np, *next;
char *p, *endp;
size_t size;
size = nextfree[id].size;
- emalloc(freep, BLOCK *, BLOCKCHUNK * size, "more_blocks");
+ assert(size >= sizeof(struct block_item));
+ emalloc(freep, struct block_item *, BLOCKCHUNK * size, "more_blocks");
p = (char *) freep;
endp = p + BLOCKCHUNK * size;
for (np = freep; ; np = next) {
- next = (BLOCK *) (p += size);
+ next = (struct block_item *) (p += size);
if (p >= endp) {
np->freep = NULL;
break;
diff --git a/nonposix.h b/nonposix.h
index b3497891..9a722dd9 100644
--- a/nonposix.h
+++ b/nonposix.h
@@ -2,22 +2,22 @@
* nonposix.h --- definitions needed on non-POSIX systems.
*/
-/*
+/*
* Copyright (C) 2012, 2013, 2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -56,6 +56,9 @@ unsigned int getegid (void);
int unsetenv (const char *);
int setenv (const char *, const char *, int);
void w32_maybe_set_errno (void);
+char *w32_setlocale (int, const char *);
+#define setlocale(c,v) w32_setlocale(c,v)
+
#endif /* __MINGW32__ */
#if defined(VMS) || defined(__DJGPP__) || defined(__MINGW32__)
diff --git a/old-extension/ChangeLog b/old-extension/ChangeLog
index 34da558f..99352c6e 100644
--- a/old-extension/ChangeLog
+++ b/old-extension/ChangeLog
@@ -1,3 +1,20 @@
+2017-06-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * bindarr.c (do_bind_array): Replace emalloc+memset with ezalloc.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+
+2015-04-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * bindarr.c (do_bind_array): Undo Arnold's change of 2014-12-18.
+
+2014-12-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * bindarr.c (do_bind_array): Do not waste a byte at the end of a string.
+ * fileop.c (do_fread): Ditto.
+
2014-01-07 Arnold D. Robbins <arnold@skeeve.com>
* dbarray.awk: Use full name for lib to load in extension() call.
diff --git a/old-extension/bindarr.c b/old-extension/bindarr.c
index 60959903..34e7e983 100644
--- a/old-extension/bindarr.c
+++ b/old-extension/bindarr.c
@@ -3,22 +3,22 @@
* to array and array elements.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -209,8 +209,7 @@ do_bind_array(int nargs)
assoc_clear(symbol);
- emalloc(aq, array_t *, sizeof(array_t), "do_bind_array");
- memset(aq, '\0', sizeof(array_t));
+ ezalloc(aq, array_t *, sizeof(array_t), "do_bind_array");
t = get_array_argument(1, false);
@@ -235,7 +234,7 @@ do_bind_array(int nargs)
}
/* copy the array -- this is passed as the second argument to the functions */
- emalloc(aname, char *, strlen(t->vname) + 2, "do_bind_array");
+ emalloc(aname, char *, 1 + strlen(symbol->vname) + 1, "do_bind_array");
aname[0] = '~'; /* any illegal character */
strcpy(& aname[1], symbol->vname);
td = make_array();
@@ -286,7 +285,7 @@ do_unbind_array(int nargs)
*symbol = *xn;
freenode(xn);
- return make_number(0);
+ return make_number(0);
}
diff --git a/old-extension/fileop.c b/old-extension/fileop.c
index 86f62576..97a51c81 100644
--- a/old-extension/fileop.c
+++ b/old-extension/fileop.c
@@ -5,20 +5,20 @@
/*
* Copyright (C) 2012 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -55,7 +55,7 @@ do_fread(int nargs)
force_number(arg);
rlen = get_number_ui(arg);
- emalloc(rbuf, char *, rlen + 2, "do_fread");
+ emalloc(rbuf, char *, rlen + 1, "do_fread");
if ((count = fread(rbuf, 1, rlen, f->fp)) < rlen) {
if (! feof(f->fp))
update_ERRNO_int(errno);
@@ -379,7 +379,7 @@ dlload(NODE *tree, void *dl)
}
-/* dlunload --- routine called when exiting */
+/* dlunload --- routine called when exiting */
void
dlunload()
diff --git a/old-extension/sparr.c b/old-extension/sparr.c
index a3d06e66..1e8642dd 100644
--- a/old-extension/sparr.c
+++ b/old-extension/sparr.c
@@ -5,20 +5,20 @@
/*
* Copyright (C) 2012 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -75,7 +75,7 @@ static void
store_SYS(NODE *symbol, NODE *subs, NODE *val, void *data)
{
sdata_t *sd = (sdata_t *) data;
-
+
if (subs != NULL && val != NULL && val->type == Node_val) {
force_string(subs);
if (strcmp(subs->stptr, "readline") == 0) {
@@ -98,7 +98,7 @@ load_READLINE(NODE *symbol, void *data)
int i;
bool long_line = false;
- if (! sd->load_file) /* non-existent SYS["readline"] or already loaded */
+ if (! sd->load_file) /* non-existent SYS["readline"] or already loaded */
return;
file = sd->filename;
@@ -145,7 +145,7 @@ load_READLINE(NODE *symbol, void *data)
}
fclose(fp);
sd->load_file = false; /* don't load this file again */
-}
+}
/* dlload --- load this library */
diff --git a/old-extension/spec_array.c b/old-extension/spec_array.c
index 34d15fc5..f933aa35 100644
--- a/old-extension/spec_array.c
+++ b/old-extension/spec_array.c
@@ -4,20 +4,20 @@
/*
* Copyright (C) 2012, 2014 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -52,7 +52,7 @@ typedef struct spec_array {
* void load_func(NODE *array, void *data)
*
* Use register_deferred_array(array, load_func, void *data) to
- * bind an array to the load routine.
+ * bind an array to the load routine.
*/
static NODE **deferred_array_init(NODE *, NODE *);
@@ -72,7 +72,7 @@ static afunc_t deferred_array_func[] = {
deferred_array_exists,
deferred_array_clear,
deferred_array_remove,
- deferred_array_list,
+ deferred_array_list,
deferred_array_copy,
null_afunc, /* dump */
(afunc_t) 0, /* store */
@@ -86,7 +86,7 @@ deferred_array_init(NODE *symbol, NODE *subs)
{
if (symbol != NULL) {
array_t *av = (array_t *) symbol->xarray;
- symbol->xarray = NULL; /* this is to avoid an assertion failure in null_array */
+ symbol->xarray = NULL; /* this is to avoid an assertion failure in null_array */
null_array(symbol); /* typeless empty array */
if (symbol->parent_array == NULL) {
/* main array */
@@ -141,7 +141,7 @@ static NODE **
deferred_array_remove(NODE *symbol, NODE *subs)
{
array_t *av = (array_t *) symbol->xarray;
-
+
(void) SUPER(aremove)(symbol, subs);
if (av) {
symbol->xarray = NULL;
@@ -157,7 +157,7 @@ static NODE **
deferred_array_clear(NODE *symbol, NODE *subs)
{
array_t *av = (array_t *) symbol->xarray;
-
+
(void) SUPER(aclear)(symbol, subs);
if (av) {
symbol->xarray = NULL;
@@ -181,7 +181,7 @@ deferred_array_clear(NODE *symbol, NODE *subs)
* The store routine must take an additional argument for the
* value. The value can be NULL if the specific element is
* removed from the array. The subscript (and the value) is NULL
- * when the entire array is deleted.
+ * when the entire array is deleted.
*
* void store_func(NODE *array, NODE *subs, NODE *value, void *data)
*
@@ -207,7 +207,7 @@ static afunc_t dyn_array_func[] = {
dyn_array_exists,
dyn_array_clear,
dyn_array_remove,
- dyn_array_list,
+ dyn_array_list,
dyn_array_copy,
null_afunc, /* dump */
dyn_array_store,
diff --git a/pc/ChangeLog b/pc/ChangeLog
index 1ff3bb1f..6300257c 100644
--- a/pc/ChangeLog
+++ b/pc/ChangeLog
@@ -1,8 +1,39 @@
+2017-01-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawkmisc.pc: Fix a typo.
+
+2017-01-21 Eli Zaretskii <eliz@gnu.org>
+
+ * Makefile.tst: Modify the locale values to valid ones on Windows.
+
+ * gawkmisc.pc: Undef setlocale and include locale.h.
+ (lc_var, w32_setlocale): New functions.
+
+ * Makefile (VAPTH): Set to allow Make to find sources in the
+ 'support' subdirectory.
+ (CFLAGS): Add "-I./support", as some headers are there.
+ (LIBOBJS): Add localeinfo$O.
+ (regex$O): Depend on regex_internal.c.
+ (localeinfo$O): New dependency.
+
+ * config.sed (SIZEOF_UNSIGNED_INT, SIZEOF_UNSIGNED_LONG): Set to 4
+ unconditioonally, as we no longer support 16-bit ports. The
+ previous definitions caused compilation errors, since config.h is
+ included by random.h before awk.h, where limits.h is included and
+ defines UINT_MAX etc.
+ * config.h: Regenerated.
+
+ * Makefile.tst: Sync with test/Makefile.in.
+
2016-11-04 Eli Zaretskii <eliz@gnu.org>
* gawkmisc.pc (w32_maybe_set_errno) [__MINGW32__]: New function,
to correct errno when it is not set to a useful value.
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+
2016-09-24 Eli Zaretskii <eliz@gnu.org>
Fix compilation warnings on MinGW with the latest runtime.
@@ -97,6 +128,10 @@
avoid warnings about 'usleep' in newer versions of mingw.org's
MinGW runtime.
+2016-01-28 Arnold D. Robbins <arnold@skeeve.com>
+
+ * config.h: Updated to current.
+
2015-05-29 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.tst (negtime): Sync with mainline.
diff --git a/pc/Makefile b/pc/Makefile
index 7bf8a7e1..921f320a 100644
--- a/pc/Makefile
+++ b/pc/Makefile
@@ -91,6 +91,9 @@ install = 1
# that $($X) can be expanded.
DO_LNK = $($(LNK))
DO_BIND= $($(BIND))
+#------------------------------------------------------------------------
+# To allow Make find files in the support subdirectory.
+VPATH = .;./support
#========================================================================
# End of general configuration. Some platform-specific configuration
# notes appear below.
@@ -198,7 +201,7 @@ BIND = EMPTY
PBIND = EMPTY
EMPTY=
-CFLAGS = $(CF) -DGAWK -I. -DHAVE_CONFIG_H -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT)
+CFLAGS = $(CF) -DGAWK -I. -I./support -DHAVE_CONFIG_H -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT)
# object files
AWKOBJS1 = array$O builtin$O eval$O field$O floatcomp$O gawkmisc$O io$O main$O
@@ -211,7 +214,7 @@ ALLOBJS = $(AWKOBJS) awkgram$O getid$O $(OBJ)
# LIBOBJS
# GNU and other stuff that gawk uses as library routines.
-LIBOBJS= getopt$O getopt1$O dfa$O regex$O random$O
+LIBOBJS= getopt$O getopt1$O dfa$O regex$O random$O localeinfo$O
GAWKOBJS = $(ALLOBJS) $(LIBOBJS)
@@ -260,10 +263,12 @@ getopt$O getopt1$O : getopt_int.h
io$O: popen.h socket.h in.h
-regex$O: regcomp.c regexec.c regex_internal.h
+regex$O: regcomp.c regexec.c regex_internal.c regex_internal.h
eval$O: interpret.h
+localeinfo$O: localeinfo.h
+
# A bug in ndmake requires the following rule
awkgram$O: awk.h awkgram.c
$(CC) -c $(CFLAGS) awkgram.c
diff --git a/pc/Makefile.tst b/pc/Makefile.tst
index 3b724e5f..de4028e9 100644
--- a/pc/Makefile.tst
+++ b/pc/Makefile.tst
@@ -105,13 +105,13 @@ CP = cp
#CP = : && command -c copy
#CP = command.com /c copy
-MV = cmd.exe /c ren
-#MV = mv
+#MV = cmd.exe /c ren
+MV = mv
-#MKDIR = mkdir
+MKDIR = mkdir
#MKDIR = gmkdir
#MKDIR = : && command -c mkdir
-MKDIR = command.com /c mkdir
+#MKDIR = command.com /c mkdir
# Set your unix-style date function here
#DATE = date
@@ -138,16 +138,16 @@ CLEANFILES = core core.* fmtspcl.ok
# try to keep these sorted. each letter starts a new line
BASIC_TESTS = \
- addcomma anchgsub argarray arrayind1 arrayparm arrayprm2 arrayprm3 \
+ addcomma anchgsub anchor argarray arrayind1 arrayind2 arrayind3 arrayparm arrayprm2 arrayprm3 \
arrayref arrymem1 arryref2 arryref3 arryref4 arryref5 arynasty \
arynocls aryprm1 aryprm2 aryprm3 aryprm4 aryprm5 aryprm6 aryprm7 \
aryprm8 aryprm9 arysubnm asgext awkpath \
back89 backgsub badassign1 badbuild \
callparam childin clobber closebad clsflnam compare compare2 concat1 concat2 \
- concat3 concat4 convfmt \
+ concat3 concat4 concat5 convfmt \
datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \
eofsplit exit2 exitval1 exitval2 exitval3 \
- fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \
+ fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \
fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \
fstabplus funsemnl funsmnam funstack \
getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \
@@ -164,15 +164,15 @@ BASIC_TESTS = \
opasnidx opasnslf \
paramasfunc1 paramasfunc2 \
paramdup paramres paramtyp paramuninitglobal parse1 parsefld parseme \
- pcntplus posix2008sub prdupval prec printf0 printf1 prmarscl prmreuse \
+ pcntplus posix2008sub prdupval prec printf0 printf1 printfchar prmarscl prmreuse \
prt1eval prtoeval \
- rand range1 readbuf rebrackloc rebt8b1 redfilnm \
+ rand randtest range1 readbuf rebrackloc rebt8b1 rebuild redfilnm \
regeq regexpbrack regexpbrack2 \
regexprange regrange reindops \
reparse resplit rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 \
rstest3 rstest4 rstest5 rswhite \
scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr splitdef \
- splitvar splitwht strcat1 strnum1 strtod subamp subback subi18n \
+ splitvar splitwht status-close strcat1 strnum1 strnum2 strtod subamp subback subi18n \
subsepnm subslash substr swaplns synerr1 synerr2 tradanch tweakfld \
uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs \
wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \
@@ -185,33 +185,39 @@ UNIX_TESTS = \
GAWK_EXT_TESTS = \
aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \
backw badargs beginfile1 beginfile2 binmode1 charasbytes \
- colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \
- crlf dbugeval delsub devfd devfd1 devfd2 dumpvars exit \
- fieldwdth fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \
+ colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 clos1way6 \
+ crlf dbugeval dbugeval2 dbugtypedre1 dbugtypedre2 delsub \
+ devfd devfd1 devfd2 dumpvars errno exit \
+ fieldwdth forcenum fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \
functab1 functab2 functab3 fwtest fwtest2 fwtest3 \
- genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops \
- icasefs icasers id igncdym igncfs ignrcas2 ignrcase \
+ genpot gensub gensub2 getlndir gnuops2 gnuops3 gnureops gsubind \
+ icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase \
incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
- include include2 indirectbuiltin indirectcall indirectcall2 \
- lint lintold lintwarn \
+ include include2 indirectbuiltin indirectcall indirectcall2 intarray \
+ lint lintexp lintindex lintint lintlength lintold lintset lintwarn \
mixed1 manyfiles match1 match2 match3 mbstr1 mbstr2 \
muldimposix \
nastyparm negtime next nondec nondec2 \
+ nonfatal1 nonfatal2 nonfatal3 \
patsplit posix printfbad1 printfbad2 printfbad3 printfbad4 printhuge procinfs \
- profile0 profile1 profile2 profile3 profile4 profile5 profile6 \
- profile7 profile8 pty1 \
+ profile0 profile1 profile2 profile3 profile4 profile5 profile6 profile7 \
+ profile8 profile9 profile10 pty1 \
rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin rsstart1 \
- rsstart2 rsstart3 rstest6 shadow sortfor sortfor2 sortu split_after_fpat \
+ rsstart2 rsstart3 rstest6 shadow shadowbuiltin \
+ sortfor sortfor2 sortu split_after_fpat \
splitarg4 strftime \
- strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \
+ strtonum strtonum1 switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \
symtab7 symtab8 symtab9 symtab10 \
+ typedregex1 typedregex2 typedregex3 typeof1 typeof2 typeof3 typeof4 \
+ timeout \
watchpoint1
+ARRAYDEBUG_TESTS = arrdbg
EXTRA_TESTS = inftest regtest ignrcas3
INET_TESTS = inetdayu inetdayt inetechu inetecht
MACHINE_TESTS = double1 double2 fmtspcl intformat
MPFR_TESTS = mpfrnr mpfrnegzero mpfrmemok1 mpfrrem mpfrrnd mpfrieee \
- mpfrexprange mpfrsort mpfrsqrt mpfrbigint
+ mpfrexprange mpfrsort mpfrsqrt mpfrbigint mpfrstrtonum mpgforcenum
LOCALE_CHARSET_TESTS = \
asort asorti backbigs1 backsmalls1 backsmalls2 \
@@ -219,13 +225,13 @@ LOCALE_CHARSET_TESTS = \
mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc
SHLIB_TESTS = \
- fnmatch filefuncs fork fork2 fts functab4 inplace1 inplace2 inplace3 \
+ apiterm fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \
ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time
# List of the tests which should be run with --lint option:
NEED_LINT = \
- defref fmtspcl lintwarn noeffect nofmtch shadow \
+ defref fmtspcl lintexp lintindex lintint lintlength lintwarn noeffect nofmtch shadow \
uninit2 uninit3 uninit4 uninit5 uninitialized
@@ -257,7 +263,7 @@ check: msg \
printlang \
basic-msg-start basic basic-msg-end \
unix-msg-start unix-tests unix-msg-end \
- extend-msg-start gawk-extensions extend-msg-end \
+ extend-msg-start gawk-extensions arraydebug-tests extend-msg-end \
machine-msg-start machine-tests machine-msg-end \
charset-tests-all \
shlib-msg-start shlib-tests shlib-msg-end \
@@ -271,15 +277,7 @@ unix-tests: $(UNIX_TESTS)
gawk-extensions: $(GAWK_EXT_TESTS)
charset-tests-all:
- @if locale -a | grep -i 'en_US.UTF.*8' > /dev/null && \
- locale -a | grep -i 'ru_RU.UTF.*8' > /dev/null && \
- locale -a | grep -i 'ja_JP.UTF.*8' > /dev/null ; \
- then \
- $(MAKE) charset-msg-start charset-tests charset-msg-end; \
- else \
- echo %%%%%%%%%% Inadequate locale support: skipping charset tests. ; \
- echo %%%%%%%%%% At least en_US.UTF-8, ru_RU.UTF-8 and ja_JP.UTF-8 are needed. ; \
- fi
+ $(MAKE) charset-msg-start charset-tests charset-msg-end
charset-tests: $(LOCALE_CHARSET_TESTS)
@@ -295,13 +293,16 @@ machine-tests: $(MACHINE_TESTS)
# in the next shlib-tests.
mpfr-tests:
@if $(AWK) --version | $(AWK) ' /MPFR/ { exit 1 }' ; then \
- echo MPFR tests not supported on this system ; \
+ @echo MPFR tests not supported on this system ; \
else $(MAKE) $(MPFR_TESTS) ; \
fi
+arraydebug-tests:
+ @echo gawk is not compiled to support the array debug tests
+
shlib-tests:
@if $(AWK) --version | $(AWK) ' /API/ { exit 1 }' ; then \
- echo shlib tests not supported on this system ; \
+ @echo shlib tests not supported on this system ; \
else $(MAKE) shlib-real-tests ; \
fi
@@ -345,9 +346,7 @@ charset-msg-start:
@echo "======== Starting tests that can vary based on character set or locale support ========"
@echo "**************************************************************************"
@echo "* Some or all of these tests may fail if you have inadequate or missing *"
- @echo "* locale support. At least en_US.UTF-8, ru_RU.UTF-8 and ja_JP.UTF-8 are *"
- @echo "* needed. However, if you see this message, the Makefile thinks you have *"
- @echo "* what you need ... *"
+ @echo "* locale support... *"
@echo "**************************************************************************"
charset-msg-end:
@@ -367,7 +366,7 @@ mpfr-msg-end:
lc_num1:
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -481,6 +480,12 @@ devfd::
@$(AWK) 1 /dev/fd/4 /dev/fd/5 4<"$(srcdir)"/devfd.in4 5<"$(srcdir)"/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+errno:
+ @echo $@
+ @echo Expect errno to fail with MinGW due to error message differences
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fflush::
@echo $@
@"$(srcdir)"/fflush.sh >_$@
@@ -664,49 +669,49 @@ rsnulbig2::
wideidx::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
wideidx2::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
widesub::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
widesub2::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
widesub3::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
widesub4::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
ignrcas2::
@echo $@
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
subamp::
@echo $@
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -749,7 +754,7 @@ rtlen01::
rtlenmb::
@echo $@
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
"$(srcdir)"/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -758,6 +763,16 @@ nondec2::
@$(AWK) --non-decimal-data -v a=0x1 -f "$(srcdir)"/$@.awk >_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+intarray::
+ @echo $@
+ @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+forcenum::
+ @echo $@
+ @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
nofile::
@echo $@
@$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -773,12 +788,12 @@ binmode1::
subi18n::
@echo $@
- @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f "$(srcdir)"/$@.awk > _$@
+ @GAWKLOCALE=ENU_USA.1252 ; $(AWK) -f "$(srcdir)"/$@.awk > _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
concat4::
@echo $@
- @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in > _$@
+ @GAWKLOCALE=ENU_USA.1252 ; $(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in > _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
devfd1::
@@ -801,13 +816,13 @@ mixed1::
mtchi18n::
@echo $@
- @GAWKLOCALE=ru_RU.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=RUS_RUS.1251 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
reint2::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) --re-interval -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -819,33 +834,33 @@ localenl::
mbprintf1::
@echo $@
@echo Expect mbprintf1 to fail with DJGPP and MinGW.
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
mbprintf2::
@echo $@
- @GAWKLOCALE=ja_JP.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=JPN_JPN.932 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
mbprintf3::
@echo $@
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
mbprintf4::
@echo $@
@echo Expect mbprintf4 to fail with MinGW and DJGPP
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
mbfw1::
@echo $@
@echo Expect mbfw1 to fail with DJGPP and MinGW.
- @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ @GAWKLOCALE=ENU_USA.1252 ; export GAWKLOCALE ; \
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -857,14 +872,14 @@ gsubtst6::
mbstr1::
@echo $@
@echo Expect mbstr1 to fail with MinGW.
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
mbstr2::
@echo $@
@echo Expect mbstr2 to fail with MinGW.
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -902,7 +917,7 @@ profile1:
@$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1
@$(AWK) -f ./ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out
@$(CMP) _$@.out1 _$@.out2 && rm _$@.out[12] || { echo EXIT CODE: $$? >>_$@ ; \
- cp "$(srcdir)"/dtdgport.awk > $@.ok ; }
+ cp "$(srcdir)"/dtdgport.awk $@.ok ; }
profile2:
@echo $@
@@ -918,13 +933,15 @@ profile3:
profile4:
@echo $@
+ @echo Expect profile4 to fail with MinGW
@GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
@sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
profile5:
@echo $@
- @GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
+ @echo Expect profile5 to abort with MinGW
+ @-GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
@sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
# @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@-$(TESTOUTCMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -943,10 +960,21 @@ profile7:
profile8:
@echo $@
+ @echo Expect profile8 to fail with MinGW
@$(AWK) --pretty=ap-$@.out -f "$(srcdir)"/$@.awk < /dev/null
@sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+profile9:
+ @echo $@
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+profile10:
+ @echo $@
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
posix2008sub:
@echo $@
@$(AWK) --posix -f "$(srcdir)"/$@.awk > _$@ 2>&1
@@ -959,14 +987,13 @@ next:
exit:
@echo $@
- @echo Expect exit to fail with MinGW due to null vs nul difference
@-AWK="$(AWKPROG)" "$(srcdir)"/$@.sh > _$@ 2>&1
# @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@-$(TESTOUTCMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
rri1::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -1010,6 +1037,16 @@ mpfrsqrt:
@$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mpfrstrtonum:
+ @echo $@
+ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+mpgforcenum:
+ @echo $@
+ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
mpfrrem:
@echo $@
@$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
@@ -1121,6 +1158,11 @@ testext::
@$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk
+getfile:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -v TESTEXT_QUIET=1 -ltestext -f $@.awk < $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
readdir:
@if [ "`uname`" = Linux ] && [ "`stat -f . 2>/dev/null | awk 'NR == 2 { print $$NF }'`" = nfs ]; then \
echo This test may fail on GNU/Linux systems when run on an NFS filesystem.; \
@@ -1157,7 +1199,7 @@ charasbytes:
# @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
# AWKPATH="$(srcdir)" $(AWK) -b -f $@.awk "$(srcdir)"/$@.in | \
# od -c -t x1 | tr ' ' ' ' | sed -e 's/ */ /g' -e 's/ *$$//' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -b -v BINMODE=2 -f $@.awk "$(srcdir)"/$@.in | \
od -c -t x1 | tr ' ' ' ' | sed -e 's/ */ /g' -e 's/ *$$//' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -1200,27 +1242,32 @@ clos1way:
dfamb1:
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+randtest::
+ @echo $@
+ @GAWK="$(AWKPROG)" "$(srcdir)"/randtest.sh >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
backbigs1:
@echo $@
@echo Expect backbigs1 to fail with MinGW and DJGPP
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
backsmalls1:
@echo $@
@echo Expect backsmalls1 to fail with MinGW and DJGPP
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
backsmalls2:
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -1233,7 +1280,7 @@ dbugeval::
printhuge::
@echo $@
- @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; \
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -1262,6 +1309,21 @@ negtime::
@TZ=GMT AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@AWKPATH="$(srcdir)" $(AWK) -f checknegtime.awk "$(srcdir)"/$@.ok _$@ && rm -f _$@
+dbugtypedre1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugtypedre2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugeval2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
muldimposix::
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --posix >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1316,11 +1378,26 @@ anchgsub:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+anchor:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
arrayind1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+arrayind2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+arrayind3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
arrayparm:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1486,6 +1563,11 @@ concat3:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+concat5:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
convfmt:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1572,6 +1654,11 @@ fldchgnf:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+fldterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fnamedat:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2009,6 +2096,11 @@ printf1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+printfchar:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
prmarscl:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2056,6 +2148,11 @@ rebt8b1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+rebuild:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
regeq:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2193,6 +2290,12 @@ splitwht:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+status-close:
+ @echo $@
+ @echo Expect status-close to fail with MinGW
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strcat1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2203,6 +2306,11 @@ strnum1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strnum2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strtod:
@echo $@
@echo Expect strtod to fail with DJGPP.
@@ -2360,6 +2468,12 @@ clos1way5:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+clos1way6:
+ @echo $@
+ @echo Expect clos1way6 to fail with MinGW
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
crlf:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2476,6 +2590,11 @@ gnureops:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+gsubind:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
icasefs:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2502,6 +2621,11 @@ igncfs:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+ignrcas4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
ignrcase:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2532,11 +2656,36 @@ lint:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+lintexp:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintindex:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintint:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintlength:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
lintold:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint-old < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+lintset:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
lintwarn:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2567,6 +2716,21 @@ nondec:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+nonfatal1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+nonfatal2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+nonfatal3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
patsplit:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2628,6 +2792,11 @@ shadow:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+shadowbuiltin:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
sortfor:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2658,6 +2827,11 @@ strtonum:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strtonum1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
switch2:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2693,6 +2867,47 @@ symtab7:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+typedregex1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typedregex2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typedregex3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+timeout:
+ @echo $@
+ @echo Expect timeout to fail with MinGW
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
double1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2754,6 +2969,11 @@ sprintfc:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+apiterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fnmatch:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/pc/config.h b/pc/config.h
index d584973a..7b076177 100644
--- a/pc/config.h
+++ b/pc/config.h
@@ -53,6 +53,9 @@
/* Define to 1 if you have the `fmod' function. */
#define HAVE_FMOD 1
+/* Define to 1 if you have the `fwrite_unlocked' function. */
+#undef HAVE_FWRITE_UNLOCKED
+
/* have getaddrinfo */
#ifdef __MINGW32__
#define HAVE_GETADDRINFO 1
@@ -201,6 +204,9 @@
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
/* Define to 1 if you have the `snprintf' function. */
#ifdef __MINGW32__
#define HAVE_SNPRINTF 1
@@ -378,6 +384,9 @@
#define HAVE_USLEEP 1
#endif
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
/* Define to 1 if you have the <wchar.h> header file. */
#ifdef __MINGW32__
#define HAVE_WCHAR_H 1
@@ -422,9 +431,6 @@
/* enable severe portability problems */
#undef I_DONT_KNOW_WHAT_IM_DOING
-/* libc is broken for regex handling */
-#undef LIBC_IS_BORKED
-
/* disable lint checks */
#undef NO_LINT
@@ -438,7 +444,7 @@
#define PACKAGE_NAME "GNU Awk"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "GNU Awk 4.1.4"
+#define PACKAGE_STRING "GNU Awk 4.1.61"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "gawk"
@@ -447,29 +453,16 @@
#define PACKAGE_URL "http://www.gnu.org/software/gawk/"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "4.1.4"
+#define PACKAGE_VERSION "4.1.61"
/* Define to 1 if *printf supports %F format */
#undef PRINTF_HAS_F_FORMAT
-/* Define as the return type of signal handlers (`int' or `void'). */
-#define RETSIGTYPE void
-
-#if defined(__DJGPP__) || defined(__MINGW32__)
-#include <limits.h>
-#endif
-
/* The size of `unsigned int', as computed by sizeof. */
-#if UINT_MAX == 65536
-#define SIZEOF_UNSIGNED_INT 2
-#elif UINT_MAX == 4294967295U
#define SIZEOF_UNSIGNED_INT 4
-#endif
/* The size of `unsigned long', as computed by sizeof. */
-#if ULONG_MAX == 4294967295UL
#define SIZEOF_UNSIGNED_LONG 4
-#endif
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
@@ -512,7 +505,7 @@
/* Version number of package */
-#define VERSION "4.1.4"
+#define VERSION "4.1.61"
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
diff --git a/pc/config.sed b/pc/config.sed
index a95ee2ef..ae2200c6 100644
--- a/pc/config.sed
+++ b/pc/config.sed
@@ -247,16 +247,8 @@ s/^#undef RETSIGTYPE *$/#define RETSIGTYPE void/
#if defined(__DJGPP__) || defined(__MINGW32__)\
#include <limits.h>\
#endif
-/^#undef SIZEOF_UNSIGNED_INT *$/c\
-#if UINT_MAX == 65536\
-#define SIZEOF_UNSIGNED_INT 2\
-#elif UINT_MAX == 4294967295U\
-#define SIZEOF_UNSIGNED_INT 4\
-#endif
-/^#undef SIZEOF_UNSIGNED_LONG *$/c\
-#if ULONG_MAX == 4294967295UL\
-#define SIZEOF_UNSIGNED_LONG 4\
-#endif
+s/^#undef SIZEOF_UNSIGNED_INT *$/#define SIZEOF_UNSIGNED_INT 4/
+s/^#undef SIZEOF_UNSIGNED_LONG *$/#define SIZEOF_UNSIGNED_LONG 4/
s/^#undef STDC_HEADERS *$/#define STDC_HEADERS 1/
s/^#undef TIME_WITH_SYS_TIME *$/#define TIME_WITH_SYS_TIME 1/
/^#undef inline *$/c\
diff --git a/pc/gawkmisc.pc b/pc/gawkmisc.pc
index 817e8167..c6c92a46 100644
--- a/pc/gawkmisc.pc
+++ b/pc/gawkmisc.pc
@@ -619,6 +619,64 @@ wctob (wint_t wc)
return EOF;
}
+
+#undef setlocale
+#include <locale.h>
+
+/* On Posix systems, 'setlocale' looks at LC_* variables in the
+ environment, and Gawk users might expect that on Windows as well.
+ The replacement implementation below does that, and also fixes a
+ few additional quirks with locales on Windows. */
+static const char *
+lc_var (int category)
+{
+ static const char *loc_name[LC_MAX - LC_MIN + 1] = {
+ "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"
+ };
+
+ /* This function assumes LC_* categories are small numbers between 0
+ and 5, as shown above, so if that changes at some point, complain
+ vociferously. */
+ if (LC_ALL != 0 || LC_CTYPE != 2 || LC_TIME != 5)
+ abort ();
+ /* Ensured by the caller, so should never happen. */
+ if (category < LC_MIN || category > LC_MAX)
+ return "????";
+ return loc_name[category];
+}
+
+char *
+w32_setlocale (int category, const char *value)
+{
+ const char *new_locale = value;
+
+ if (LC_MIN <= category && category <= LC_MAX
+ && value && *value == '\0')
+ {
+ const char *lc_val = getenv ("LC_ALL");
+
+ if (!lc_val)
+ lc_val = getenv (lc_var (category));
+ if (!lc_val)
+ lc_val = getenv ("LANG");
+ if (lc_val)
+ new_locale = lc_val;
+ }
+
+ /* If VALUE includes a codeset, i.e. a Windows codepage number, we
+ must also set the LC_CTYPE locale to the same value, because
+ LC_CTYPE is the only category which is documented to be able to
+ change the codepage. */
+ if (category != LC_ALL && category != LC_CTYPE)
+ {
+ const char *p = strchr (new_locale, '.');
+
+ if (p && isdigit (p[1]))
+ setlocale (LC_CTYPE, new_locale);
+ }
+ return setlocale (category, new_locale);
+}
+
/*
* On MS-Windows with MinGW, execvp causes the shell and the re-exec'ed
* dgawk to compete for the keyboard input.
diff --git a/pc/popen.c b/pc/popen.c
index 73770d98..425d32b9 100644
--- a/pc/popen.c
+++ b/pc/popen.c
@@ -104,7 +104,7 @@ scriptify(const char *command)
free(cmd);
cmd = NULL;
}
- if (fp) fclose(fp);
+ if (fp) fclose(fp);
return(cmd);
}
diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt
new file mode 100644
index 00000000..cd930077
--- /dev/null
+++ b/po/CMakeLists.txt
@@ -0,0 +1,133 @@
+# Most of this copied from the repository of Stellarium
+# http://sourceforge.net/projects/stellarium/
+
+# Special targets for translations:
+#
+# translations
+# Converts all PO files to GMO files. Note that it does *not* update
+# the PO files or the PO templates -- in fact, these files are never
+# updated automatically.
+#
+# generate-pot
+# Re-creates all POT files unconditionally.
+#
+# update-po
+# Updates all PO files unconditionally. Note that it takes care of
+# updating the POT files.
+#
+# translations-<DOMAIN>
+# generate-pot-<DOMAIN>
+# update-po-<DOMAIN>
+# Same as above, but only affect the files in the corresponding
+# po/<DOMAIN> directory. (DOMAIN is actually the base name of the POT
+# file in the subdirectory, but that should match the directory name
+# anyway.)
+
+ADD_CUSTOM_TARGET(translations)
+ADD_CUSTOM_TARGET(generate-pot)
+ADD_CUSTOM_TARGET(update-po)
+
+# GETTEXT_CREATE_TRANSLATIONS(domain [DEFAULT_TARGET] lang1 ... langN)
+#
+# Creates custom build rules to create and install (G)MO files for the
+# specified languages. If the DEFAULT_TARGET option is used, the
+# translations will also be created when building the default target.
+#
+# "domain" is the translation domain, eg. "gawk". A POT file
+# with the name ${domain}.pot must exist in the directory of the
+# CMakeLists.txt file invoking the macro.
+#
+# This macro also creates the "translations-${domain}" and
+# "update-po-${domain}" targets (see above for an explanation).
+#
+MACRO(GETTEXT_CREATE_TRANSLATIONS _domain _firstLang)
+
+ SET(_gmoFiles)
+ GET_FILENAME_COMPONENT(_absPotFile ${_domain}.pot ABSOLUTE)
+
+ # Update these PO files when building the "update-po-<DOMAIN>" and
+ # "update-po" targets.
+ ADD_CUSTOM_TARGET(update-po-${_domain})
+ ADD_DEPENDENCIES(update-po update-po-${_domain})
+
+ # Make sure the POT file is updated before updating the PO files.
+ ADD_DEPENDENCIES(update-po-${_domain} generate-pot-${_domain})
+
+ SET(_addToAll)
+ IF(${_firstLang} STREQUAL "DEFAULT_TARGET")
+ SET(_addToAll "ALL")
+ SET(_firstLang)
+ ENDIF(${_firstLang} STREQUAL "DEFAULT_TARGET")
+
+ FOREACH (_lang ${ARGN})
+ GET_FILENAME_COMPONENT(_absFile ${_lang}.po ABSOLUTE)
+ FILE(RELATIVE_PATH _relFile ${PROJECT_SOURCE_DIR} ${_absFile})
+ SET(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
+
+ # Convert a PO file into a GMO file.
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${_gmoFile}
+ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
+ DEPENDS ${_absFile}
+ )
+
+ # Update the PO file unconditionally when building the
+ # "update-po-<DOMAIN>" target. Note that to see the file being
+ # processed, we have to run "cmake -E echo", because the
+ # COMMENT is not displayed by cmake...
+ ADD_CUSTOM_COMMAND(
+ TARGET update-po-${_domain}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "** Updating ${_relFile}"
+ COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE}
+ --quiet --update -m --backup=none -s
+ ${_absFile} ${_absPotFile}
+ VERBATIM
+ )
+
+ INSTALL(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_domain}.mo)
+ SET(_gmoFiles ${_gmoFiles} ${_gmoFile})
+
+ ENDFOREACH (_lang)
+
+ # Create the GMO files when building the "translations-<DOMAIN>" and
+ # "translations" targets.
+ ADD_CUSTOM_TARGET(translations-${_domain} ${_addToAll} DEPENDS ${_gmoFiles})
+ ADD_DEPENDENCIES(translations translations-${_domain})
+
+ENDMACRO(GETTEXT_CREATE_TRANSLATIONS )
+
+SET(gawk_DOMAIN gawk)
+SET(gawk_POT ${gawk_DOMAIN}.pot)
+
+file(READ LINGUAS linguas)
+string(REGEX REPLACE "\n" ";" linguas ${linguas})
+GETTEXT_CREATE_TRANSLATIONS(${gawk_DOMAIN} DEFAULT_TARGET ${linguas})
+
+ADD_CUSTOM_TARGET(
+ generate-pot-${gawk_DOMAIN}
+ ${GETTEXT_XGETTEXT_EXECUTABLE}
+ -o ${CMAKE_CURRENT_SOURCE_DIR}/${gawk_POT}
+ -C
+ --keyword=_
+ --keyword=N_
+ --keyword=q_
+ --keyword=translate:2
+ --add-comments=TRANSLATORS:
+ --directory=${CMAKE_BINARY_DIR}
+ --directory=${CMAKE_SOURCE_DIR}
+ --output-dir=${CMAKE_BINARY_DIR}
+ --files-from=${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in
+ --copyright-holder=FSF
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ COMMENT "Generating ${gawk_POT}"
+ VERBATIM
+)
+# TODO: It would be nice to just depend on the exact files in POTFILES.in
+#file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${gawk_POT} UiHeaders)
+#ADD_DEPENDENCIES(generate-pot-${gawk_DOMAIN} UiHeaders)
+#ADD_DEPENDENCIES(generate-pot-${gawk_DOMAIN} gawk_UIS_H)
+# Make sure the UI headers are created first.
+ADD_DEPENDENCIES(generate-pot-${gawk_DOMAIN} StelGuiLib) # ??? FIXME
+# Generate this POT file when building the "generate-pot" target.
+ADD_DEPENDENCIES(generate-pot generate-pot-${gawk_DOMAIN})
diff --git a/po/ChangeLog b/po/ChangeLog
index 4685f91c..2db026b6 100644
--- a/po/ChangeLog
+++ b/po/ChangeLog
@@ -1,3 +1,13 @@
+2017-02-01 Arnold D. Robbins <arnold@skeeve.com>
+
+ * POTFILES.in: Update list of files and sort it.
+
+2017-01-27 Rafael Fontenelle <rafaelff@gnome.org>
+
+ * POTFILES.in: Fix path of some files listed there so that
+ update via commands like 'make gawk.pot-update' or
+ 'intltool-update <lang>' will work.
+
2017-01-27 Arnold D. Robbins <arnold@skeeve.com>
* LINGUAS: Updated with pt_BR.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0781efc1..bc8c9c72 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,5 @@
# List of source files containing translatable strings.
-# Copyright (C) 1999, 2002, 2012 Free Software Foundation, Inc.
+# Copyright (C) 1999, 2002, 2012, 2017 Free Software Foundation, Inc.
array.c
awkgram.c
@@ -7,7 +7,6 @@ builtin.c
cint_array.c
command.c
debug.c
-dfa.c
eval.c
ext.c
extension/filefuncs.c
@@ -29,8 +28,6 @@ field.c
floatcomp.c
gawkapi.c
gawkmisc.c
-getopt.c
-getopt1.c
int_array.c
io.c
main.c
@@ -39,13 +36,17 @@ msg.c
node.c
posix/gawkmisc.c
profile.c
-random.c
re.c
-regcomp.c
-regex.c
-regex_internal.c
-regexec.c
replace.c
str_array.c
+support/dfa.c
+support/getopt.c
+support/getopt1.c
+support/localeinfo.c
+support/random.c
+support/regcomp.c
+support/regex.c
+support/regex_internal.c
+support/regexec.c
symbol.c
version.c
diff --git a/po/it.po b/po/it.po
index cb8cd8cf..6aaaa733 100644
--- a/po/it.po
+++ b/po/it.po
@@ -1,13 +1,13 @@
# Italian messages for GNU Awk
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
# Antonio Colombo <azc100@gmail.com>.
#
msgid ""
msgstr ""
"Project-Id-Version: GNU Awk 4.0.73, API: 0.0\n"
"Report-Msgid-Bugs-To: bug-gawk@gnu.org\n"
-"POT-Creation-Date: 2016-08-25 08:40+0300\n"
-"PO-Revision-Date: 2015-05-25 19:36+0100\n"
+"POT-Creation-Date: 2017-04-13 00:49+0200\n"
+"PO-Revision-Date: 2017-04-14 00:13+0100\n"
"Last-Translator: Antonio Colombo <azc100@gmail.com>\n"
"Language-Team: Italian <it@li.org>\n"
"Language: it\n"
@@ -34,482 +34,482 @@ msgstr "tentativo di usare il parametro scalare `%s' come un vettore"
msgid "attempt to use scalar `%s' as an array"
msgstr "tentativo di usare scalare '%s' come vettore"
-#: array.c:412 array.c:579 builtin.c:85 builtin.c:1612 builtin.c:1658
-#: builtin.c:1671 builtin.c:2160 builtin.c:2179 eval.c:1141 eval.c:1145
-#: eval.c:1556
+#: array.c:412 array.c:579 builtin.c:85 builtin.c:1637 builtin.c:1683
+#: builtin.c:1696 builtin.c:2219 builtin.c:2246 eval.c:1130 eval.c:1134
+#: eval.c:1542
#, c-format
msgid "attempt to use array `%s' in a scalar context"
msgstr "tentativo di usare vettore `%s' in un contesto scalare"
#: array.c:586
#, c-format
-msgid "delete: index `%s' not in array `%s'"
-msgstr "delete: indice `%s' non presente nel vettore `%s'"
+msgid "delete: index `%.*s' not in array `%s'"
+msgstr "delete: indice `%.*s' non presente nel vettore `%s'"
#: array.c:600
#, c-format
msgid "attempt to use scalar `%s[\"%.*s\"]' as an array"
msgstr "tentativo di usare scalare`%s[\"%.*s\"]' come vettore"
-#: array.c:779
+#: array.c:788
msgid "adump: first argument not an array"
msgstr "adump: primo argomento non-vettoriale"
-#: array.c:818
+#: array.c:830
msgid "asort: second argument not an array"
msgstr "asort: secondo argomento non-vettoriale"
-#: array.c:819
+#: array.c:831
msgid "asorti: second argument not an array"
msgstr "asorti: secondo argomento non-vettoriale"
-#: array.c:826
+#: array.c:838
msgid "asort: first argument not an array"
msgstr "asort: primo argomento non-vettoriale"
-#: array.c:827
+#: array.c:839
msgid "asorti: first argument not an array"
msgstr "asorti: primo argomento non-vettoriale"
-#: array.c:834
+#: array.c:846
msgid "asort: cannot use a subarray of first arg for second arg"
msgstr ""
"asort: non consentito un secondo argomento che sia un sottovettore del primo "
"argomento"
-#: array.c:835
+#: array.c:847
msgid "asorti: cannot use a subarray of first arg for second arg"
msgstr ""
"asorti: non consentito un secondo argomento che sia un sottovettore del "
"primo argomento"
-#: array.c:840
+#: array.c:852
msgid "asort: cannot use a subarray of second arg for first arg"
msgstr ""
"asort: non consentito un primo argomento che sia un sottovettore del secondo "
"argomento"
-#: array.c:841
+#: array.c:853
msgid "asorti: cannot use a subarray of second arg for first arg"
msgstr ""
"asorti: non consentito un primo argomento che sia un sottovettore del "
"secondo argomento"
-#: array.c:1316
+#: array.c:1321
#, c-format
msgid "`%s' is invalid as a function name"
msgstr "`%s' non è un nome funzione valido"
-#: array.c:1320
+#: array.c:1325
#, c-format
msgid "sort comparison function `%s' is not defined"
msgstr "funzione di confronto del sort `%s' non definita"
-#: awkgram.y:225
+#: awkgram.y:247
#, c-format
msgid "%s blocks must have an action part"
msgstr "blocchi %s richiedono una `azione'"
-#: awkgram.y:228
+#: awkgram.y:250
msgid "each rule must have a pattern or an action part"
msgstr "ogni regola deve avere una parte `espressione' o una parte `azione'"
-#: awkgram.y:319 awkgram.y:330
+#: awkgram.y:363 awkgram.y:377
msgid "old awk does not support multiple `BEGIN' or `END' rules"
msgstr "il vecchio awk non supporta più di una regola `BEGIN' o `END'"
-#: awkgram.y:367
+#: awkgram.y:421
#, c-format
msgid "`%s' is a built-in function, it cannot be redefined"
msgstr "`%s' è una funzione interna, non si può ridefinire"
-#: awkgram.y:416
+#: awkgram.y:497
msgid "regexp constant `//' looks like a C++ comment, but is not"
msgstr "espressione regolare costante `//' sembra un commento C++, ma non lo è"
-#: awkgram.y:420
+#: awkgram.y:501
#, c-format
msgid "regexp constant `/%s/' looks like a C comment, but is not"
msgstr "espressione regolare costante `/%s/' sembra un commento C, ma non lo è"
-#: awkgram.y:512
+#: awkgram.y:651
#, c-format
msgid "duplicate case values in switch body: %s"
msgstr "valori di `case' doppi all'interno di uno `switch': %s"
-#: awkgram.y:533
+#: awkgram.y:672
msgid "duplicate `default' detected in switch body"
msgstr "valori di default doppi all'interno di uno `switch'"
-#: awkgram.y:793 awkgram.y:3774
+#: awkgram.y:933 awkgram.y:4216
msgid "`break' is not allowed outside a loop or switch"
msgstr "`break' non consentito fuori da un ciclo o da uno `switch'"
-#: awkgram.y:802 awkgram.y:3766
+#: awkgram.y:943 awkgram.y:4208
msgid "`continue' is not allowed outside a loop"
msgstr "`continue' non consentito fuori da un un ciclo"
-#: awkgram.y:812
+#: awkgram.y:954
#, c-format
msgid "`next' used in %s action"
msgstr "`next' usato in `azione' %s"
-#: awkgram.y:821
+#: awkgram.y:964
#, c-format
msgid "`nextfile' used in %s action"
msgstr "`nextfile' usato in `azione' %s"
-#: awkgram.y:845
+#: awkgram.y:990
msgid "`return' used outside function context"
msgstr "`return' usato fuori da una funzione"
-#: awkgram.y:919
+#: awkgram.y:1065
msgid "plain `print' in BEGIN or END rule should probably be `print \"\"'"
msgstr "`print' da solo in BEGIN o END dovrebbe forse essere `print \"\"'"
-#: awkgram.y:985 awkgram.y:1034
+#: awkgram.y:1132 awkgram.y:1182
msgid "`delete' is not allowed with SYMTAB"
msgstr "`delete' non consentito in SYMTAB"
-#: awkgram.y:987 awkgram.y:1036
+#: awkgram.y:1134 awkgram.y:1184
msgid "`delete' is not allowed with FUNCTAB"
msgstr "`delete' non consentito in FUNCTAB"
-#: awkgram.y:1021 awkgram.y:1025
+#: awkgram.y:1169 awkgram.y:1173
msgid "`delete(array)' is a non-portable tawk extension"
msgstr "`delete(array)' è un'estensione tawk non-portabile"
-#: awkgram.y:1146
+#: awkgram.y:1309
msgid "multistage two-way pipelines don't work"
msgstr "`pipeline' multistadio bidirezionali non funzionano"
-#: awkgram.y:1264
+#: awkgram.y:1469
msgid "regular expression on right of assignment"
msgstr "espressione regolare usata per assegnare un valore"
-#: awkgram.y:1275
+#: awkgram.y:1484 awkgram.y:1497
msgid "regular expression on left of `~' or `!~' operator"
msgstr "espressione regolare prima di operatore `~' o `!~'"
-#: awkgram.y:1291 awkgram.y:1433
+#: awkgram.y:1514 awkgram.y:1662
msgid "old awk does not support the keyword `in' except after `for'"
msgstr "il vecchio awk non supporta la parola-chiave `in' se non dopo `for'"
-#: awkgram.y:1301
+#: awkgram.y:1524
msgid "regular expression on right of comparison"
msgstr "espressione regolare a destra in un confronto"
-#: awkgram.y:1413
+#: awkgram.y:1642
#, c-format
msgid "non-redirected `getline' invalid inside `%s' rule"
msgstr "`getline' non ridiretta invalida all'interno della regola `%s'"
-#: awkgram.y:1416
+#: awkgram.y:1645
msgid "non-redirected `getline' undefined inside END action"
msgstr "`getline' non ri-diretta indefinita dentro `azione' END"
-#: awkgram.y:1435
+#: awkgram.y:1664
msgid "old awk does not support multidimensional arrays"
msgstr "il vecchio awk non supporta vettori multidimensionali"
-#: awkgram.y:1532
+#: awkgram.y:1761
msgid "call of `length' without parentheses is not portable"
msgstr "chiamata a `length' senza parentesi non portabile"
-#: awkgram.y:1598
+#: awkgram.y:1835
msgid "indirect function calls are a gawk extension"
msgstr "chiamate a funzione indirette sono un'estensione gawk"
-#: awkgram.y:1611
+#: awkgram.y:1848
#, c-format
msgid "can not use special variable `%s' for indirect function call"
msgstr ""
"non riesco a usare la variabile speciale `%s' come parametro indiretto di "
"funzione"
-#: awkgram.y:1637
+#: awkgram.y:1874
#, c-format
msgid "attempt to use non-function `%s' in function call"
msgstr "tentativo di usare la non-funzione `%s' in una chiamata di funzione"
-#: awkgram.y:1701
+#: awkgram.y:1938
msgid "invalid subscript expression"
msgstr "espressione indice invalida"
-#: awkgram.y:2047 awkgram.y:2067 gawkapi.c:206 gawkapi.c:223 msg.c:126
+#: awkgram.y:2300 awkgram.y:2320 gawkapi.c:235 gawkapi.c:252 msg.c:128
msgid "warning: "
msgstr "attenzione: "
-#: awkgram.y:2065 gawkapi.c:192 gawkapi.c:221 msg.c:158
+#: awkgram.y:2318 gawkapi.c:207 gawkapi.c:250 msg.c:160
msgid "fatal: "
msgstr "fatale: "
-#: awkgram.y:2116
+#: awkgram.y:2368
msgid "unexpected newline or end of string"
msgstr "carattere 'a capo' o fine stringa non previsti"
-#: awkgram.y:2397 awkgram.y:2473 awkgram.y:2696 debug.c:523 debug.c:539
-#: debug.c:2812 debug.c:5101
+#: awkgram.y:2656 awkgram.y:2732 awkgram.y:2955 debug.c:523 debug.c:539
+#: debug.c:2814 debug.c:5108
#, c-format
msgid "can't open source file `%s' for reading (%s)"
msgstr "non riesco ad aprire file sorgente `%s' in lettura (%s)"
-#: awkgram.y:2398 awkgram.y:2523
+#: awkgram.y:2657 awkgram.y:2782
#, c-format
msgid "can't open shared library `%s' for reading (%s)"
msgstr "non riesco ad aprire shared library `%s' in lettura (%s)"
-#: awkgram.y:2400 awkgram.y:2474 awkgram.y:2524 builtin.c:135 debug.c:5252
+#: awkgram.y:2659 awkgram.y:2733 awkgram.y:2783 builtin.c:146 debug.c:5259
msgid "reason unknown"
msgstr "ragione indeterminata"
-#: awkgram.y:2409 awkgram.y:2433
+#: awkgram.y:2668 awkgram.y:2692
#, c-format
msgid "can't include `%s' and use it as a program file"
msgstr "non riesco a includere `%s' per usarlo come file di programma"
-#: awkgram.y:2422
+#: awkgram.y:2681
#, c-format
msgid "already included source file `%s'"
msgstr "file sorgente `%s' già incluso"
-#: awkgram.y:2423
+#: awkgram.y:2682
#, c-format
msgid "already loaded shared library `%s'"
msgstr "shared library `%s' già inclusa"
-#: awkgram.y:2458
+#: awkgram.y:2717
msgid "@include is a gawk extension"
msgstr "@include è un'estensione gawk"
-#: awkgram.y:2464
+#: awkgram.y:2723
msgid "empty filename after @include"
msgstr "nome-file mancante dopo @include"
-#: awkgram.y:2508
+#: awkgram.y:2767
msgid "@load is a gawk extension"
msgstr "@load è un'estensione gawk"
-#: awkgram.y:2514
+#: awkgram.y:2773
msgid "empty filename after @load"
msgstr "nome-file mancante dopo @include"
-#: awkgram.y:2648
+#: awkgram.y:2907
msgid "empty program text on command line"
msgstr "programma nullo sulla riga comandi"
-#: awkgram.y:2763
+#: awkgram.y:3022
#, c-format
msgid "can't read sourcefile `%s' (%s)"
msgstr "non riesco a leggere file sorgente `%s' (%s)"
-#: awkgram.y:2774
+#: awkgram.y:3033
#, c-format
msgid "source file `%s' is empty"
msgstr "file sorgente `%s' vuoto"
-#: awkgram.y:2833
+#: awkgram.y:3092
#, c-format
msgid "PEBKAC error: invalid character '\\%03o' in source code"
msgstr "errore PEBKAC: carattere invalido '\\%03o' nel codice sorgente"
-#: awkgram.y:2964
+#: awkgram.y:3345
msgid "source file does not end in newline"
msgstr "file sorgente non termina con carattere 'a capo'"
-#: awkgram.y:3081
+#: awkgram.y:3465
msgid "unterminated regexp ends with `\\' at end of file"
msgstr "espressione regolare non completata termina con `\\' a fine file"
-#: awkgram.y:3108
+#: awkgram.y:3492
#, c-format
msgid "%s: %d: tawk regex modifier `/.../%c' doesn't work in gawk"
msgstr ""
"%s: %d: modificatore di espressione regolare tawk `/.../%c' non valido in "
"gawk"
-#: awkgram.y:3112
+#: awkgram.y:3496
#, c-format
msgid "tawk regex modifier `/.../%c' doesn't work in gawk"
msgstr "modificatore di espressione regolare tawk `/.../%c' non valido in gawk"
-#: awkgram.y:3119
+#: awkgram.y:3509
msgid "unterminated regexp"
msgstr "espressione regolare non completata"
-#: awkgram.y:3123
+#: awkgram.y:3513
msgid "unterminated regexp at end of file"
msgstr "espressione regolare non completata a fine file"
-#: awkgram.y:3181
+#: awkgram.y:3592
msgid "use of `\\ #...' line continuation is not portable"
msgstr "uso di `\\ #...' continuazione riga non portabile"
-#: awkgram.y:3197
+#: awkgram.y:3612
msgid "backslash not last character on line"
msgstr "'\\' non è l'ultimo carattere della riga"
-#: awkgram.y:3235 awkgram.y:3237
+#: awkgram.y:3650 awkgram.y:3652
msgid "multidimensional arrays are a gawk extension"
msgstr "i vettori multidimensionali sono un'estensione gawk"
-#: awkgram.y:3262
+#: awkgram.y:3677
msgid "POSIX does not allow operator `**='"
msgstr "POSIX non permette l'operatore `**='"
-#: awkgram.y:3264
+#: awkgram.y:3679
msgid "old awk does not support operator `**='"
msgstr "il vecchio awk non supporta l'operatore `**='"
-#: awkgram.y:3273
+#: awkgram.y:3688
msgid "POSIX does not allow operator `**'"
msgstr "POSIX non permette l'operatore `**'"
-#: awkgram.y:3275
+#: awkgram.y:3690
msgid "old awk does not support operator `**'"
msgstr "il vecchio awk non supporta l'operatore `**'"
-#: awkgram.y:3310
+#: awkgram.y:3725
msgid "operator `^=' is not supported in old awk"
msgstr "l'operatore `^=' non è supportato nel vecchio awk"
-#: awkgram.y:3318
+#: awkgram.y:3733
msgid "operator `^' is not supported in old awk"
msgstr "l'operatore `^' non è supportato nel vecchio awk"
-#: awkgram.y:3415 awkgram.y:3433 command.y:1187
+#: awkgram.y:3830 awkgram.y:3848 command.y:1187
msgid "unterminated string"
msgstr "stringa non terminata"
-#: awkgram.y:3654
+#: awkgram.y:4069
#, c-format
msgid "invalid char '%c' in expression"
msgstr "carattere '%c' non valido in un'espressione"
-#: awkgram.y:3701
+#: awkgram.y:4143
#, c-format
msgid "`%s' is a gawk extension"
msgstr "`%s' è un'estensione gawk"
-#: awkgram.y:3706
+#: awkgram.y:4148
#, c-format
msgid "POSIX does not allow `%s'"
msgstr "POSIX non permette `%s'"
-#: awkgram.y:3714
+#: awkgram.y:4156
#, c-format
msgid "`%s' is not supported in old awk"
msgstr "`%s' non è supportato nel vecchio awk"
-#: awkgram.y:3804
+#: awkgram.y:4246
msgid "`goto' considered harmful!\n"
msgstr "`goto' considerato pericoloso!\n"
-#: awkgram.y:3873
+#: awkgram.y:4315
#, c-format
msgid "%d is invalid as number of arguments for %s"
msgstr "%d non valido come numero di argomenti per %s"
-#: awkgram.y:3908
+#: awkgram.y:4350
#, c-format
msgid "%s: string literal as last arg of substitute has no effect"
msgstr "%s: una stringa come ultimo argomento di `substitute' non ha effetto"
-#: awkgram.y:3913
+#: awkgram.y:4355
#, c-format
msgid "%s third parameter is not a changeable object"
msgstr "il terzo parametro di '%s' non è un oggetto modificabile"
-#: awkgram.y:3996 awkgram.y:3999
+#: awkgram.y:4447 awkgram.y:4450
msgid "match: third argument is a gawk extension"
msgstr "match: il terzo argomento è un'estensione gawk"
-#: awkgram.y:4053 awkgram.y:4056
+#: awkgram.y:4504 awkgram.y:4507
msgid "close: second argument is a gawk extension"
msgstr "close: il secondo argomento è un'estensione gawk"
-#: awkgram.y:4068
+#: awkgram.y:4519
msgid "use of dcgettext(_\"...\") is incorrect: remove leading underscore"
msgstr ""
"uso scorretto di dcgettext(_\"...\"): togliere il carattere '_' iniziale"
-#: awkgram.y:4083
+#: awkgram.y:4534
msgid "use of dcngettext(_\"...\") is incorrect: remove leading underscore"
msgstr ""
"uso scorretto di dcngettext(_\"...\"): togliere il carattere '_' iniziale"
-#: awkgram.y:4102
+#: awkgram.y:4553
msgid "index: regexp constant as second argument is not allowed"
msgstr "index: espressione regolare come secondo argomento non consentita"
-#: awkgram.y:4155
+#: awkgram.y:4606
#, c-format
msgid "function `%s': parameter `%s' shadows global variable"
msgstr "funzione `%s': parametro `%s' nasconde variabile globale"
-#: awkgram.y:4214 debug.c:4087 debug.c:4130 debug.c:5250
+#: awkgram.y:4655 debug.c:4093 debug.c:4136 debug.c:5257
#, c-format
msgid "could not open `%s' for writing (%s)"
msgstr "non riesco ad aprire `%s' in scrittura (%s)"
-#: awkgram.y:4215
+#: awkgram.y:4656
msgid "sending variable list to standard error"
-msgstr "mando lista variabili a 'standard error'"
+msgstr "mando lista variabili a `standard error'"
-#: awkgram.y:4223
+#: awkgram.y:4664
#, c-format
msgid "%s: close failed (%s)"
msgstr "%s: `close' non riuscita (%s)"
-#: awkgram.y:4248
+#: awkgram.y:4689
msgid "shadow_funcs() called twice!"
msgstr "shadow_funcs() chiamata due volte!"
-#: awkgram.y:4256
+#: awkgram.y:4697
msgid "there were shadowed variables."
msgstr "c'erano variabili nascoste."
-#: awkgram.y:4327
+#: awkgram.y:4776
#, c-format
msgid "function name `%s' previously defined"
msgstr "funzione di nome `%s' definita in precedenza"
-#: awkgram.y:4373
+#: awkgram.y:4822
#, c-format
msgid "function `%s': can't use function name as parameter name"
msgstr ""
"funzione `%s': non è possibile usare nome della funzione come nome parametro"
-#: awkgram.y:4376
+#: awkgram.y:4825
#, c-format
msgid "function `%s': can't use special variable `%s' as a function parameter"
msgstr ""
"funzione `%s': non è possibile usare la variabile speciale `%s' come "
"parametro di funzione"
-#: awkgram.y:4384
+#: awkgram.y:4833
#, c-format
msgid "function `%s': parameter #%d, `%s', duplicates parameter #%d"
msgstr "funzione `%s': parametro #%d, `%s', duplica parametro #%d"
-#: awkgram.y:4471 awkgram.y:4477
+#: awkgram.y:4920 awkgram.y:4926
#, c-format
msgid "function `%s' called but never defined"
msgstr "funzione `%s' chiamata ma mai definita"
-#: awkgram.y:4481
+#: awkgram.y:4930
#, c-format
msgid "function `%s' defined but never called directly"
msgstr "funzione `%s' definita ma mai chiamata direttamente"
-#: awkgram.y:4513
+#: awkgram.y:4962
#, c-format
msgid "regexp constant for parameter #%d yields boolean value"
msgstr ""
"espressione regolare di valore costante per parametro #%d genera valore "
"booleano"
-#: awkgram.y:4528
+#: awkgram.y:4977
#, c-format
msgid ""
"function `%s' called with space between name and `(',\n"
@@ -518,268 +518,282 @@ msgstr ""
"funzione `%s' chiamata con spazio tra il nome e `(',\n"
"o usata come variabile o vettore"
-#: awkgram.y:4734
+#: awkgram.y:5192
msgid "division by zero attempted"
msgstr "tentativo di dividere per zero"
-#: awkgram.y:4743
+#: awkgram.y:5201
#, c-format
msgid "division by zero attempted in `%%'"
msgstr "tentativo di dividere per zero in `%%'"
-#: awkgram.y:5064
+#: awkgram.y:5527
msgid ""
"cannot assign a value to the result of a field post-increment expression"
msgstr ""
"impossibile assegnare un valore al risultato di un'espressione di post-"
"incremento di un campo"
-#: awkgram.y:5067
+#: awkgram.y:5530
#, c-format
msgid "invalid target of assignment (opcode %s)"
msgstr "destinazione di assegnazione non valida (codice operativo %s)"
-#: builtin.c:133
+#: builtin.c:140
#, c-format
msgid "%s to \"%s\" failed (%s)"
msgstr "%s a \"%s\" non riuscita (%s)"
-#: builtin.c:134
+#: builtin.c:144
msgid "standard output"
msgstr "standard output"
-#: builtin.c:148
+#: builtin.c:145
+msgid "standard error"
+msgstr "standard error"
+
+#: builtin.c:159
msgid "exp: received non-numeric argument"
msgstr "exp: l'argomento ricevuto non è numerico"
-#: builtin.c:154
+#: builtin.c:165
#, c-format
msgid "exp: argument %g is out of range"
msgstr "exp: argomento %g fuori intervallo"
-#: builtin.c:229
+#: builtin.c:242
#, c-format
-msgid "fflush: cannot flush: pipe `%s' opened for reading, not writing"
+msgid "fflush: cannot flush: pipe `%.*s' opened for reading, not writing"
msgstr ""
-"fflush: non riesco a scaricare: `pipe' `%s' aperta in lettura, non in "
+"fflush: non riesco a scaricare: `pipe' `%.*s' aperta in lettura, non in "
"scrittura"
-#: builtin.c:232
+#: builtin.c:245
#, c-format
-msgid "fflush: cannot flush: file `%s' opened for reading, not writing"
+msgid "fflush: cannot flush: file `%.*s' opened for reading, not writing"
msgstr ""
-"fflush: non riesco a scaricare: file `%s' aperto in lettura, non in scrittura"
+"fflush: non riesco a scaricare: file `%.*s' aperto in lettura, non in "
+"scrittura"
-#: builtin.c:241
+#: builtin.c:256
#, c-format
-msgid "fflush: cannot flush: two-way pipe `%s' has closed write end"
+msgid "fflush: cannot flush file `%.*s': %s"
+msgstr "fflush: non riesco a scaricare file `%.*s': %s"
+
+#: builtin.c:261
+#, c-format
+msgid "fflush: cannot flush: two-way pipe `%.*s' has closed write end"
msgstr ""
-"fflush: non riesco a scaricare: `pipe' bidirezionale `%s' ha chiuso il lato "
-"in scrittura"
+"fflush: non riesco a scaricare: `pipe' bidirezionale `%.*s' ha chiuso il "
+"lato in scrittura"
-#: builtin.c:247
+#: builtin.c:267
#, c-format
-msgid "fflush: `%s' is not an open file, pipe or co-process"
-msgstr "fflush: `%s' non è un file aperto, una `pipe' o un co-processo"
+msgid "fflush: `%.*s' is not an open file, pipe or co-process"
+msgstr "fflush: `%.*s' non è un file aperto, una `pipe' o un co-processo"
-#: builtin.c:354
+#: builtin.c:374
msgid "index: received non-string first argument"
msgstr "index: il primo argomento ricevuto non è una stringa"
-#: builtin.c:356
+#: builtin.c:376
msgid "index: received non-string second argument"
msgstr "index: il secondo argomento ricevuto non è una stringa"
-#: builtin.c:469 mpfr.c:781
+#: builtin.c:489 mpfr.c:776
msgid "int: received non-numeric argument"
msgstr "int: l'argomento ricevuto non è numerico"
-#: builtin.c:506
+#: builtin.c:507
+msgid "`isarray' is deprecated. Use `typeof' instead"
+msgstr "`isarray' è una funzione deprecata. Usare `typeof' al suo posto"
+
+#: builtin.c:532
msgid "length: received array argument"
msgstr "length: l'argomento ricevuto è un vettore"
-#: builtin.c:509
+#: builtin.c:535
msgid "`length(array)' is a gawk extension"
msgstr "`length(array)' è un'estensione gawk"
-#: builtin.c:528
+#: builtin.c:554
msgid "length: received non-string argument"
msgstr "length: l'argomento ricevuto non è una stringa"
-#: builtin.c:557
+#: builtin.c:583
msgid "log: received non-numeric argument"
msgstr "log: l'argomento ricevuto non è numerico"
-#: builtin.c:560
+#: builtin.c:586
#, c-format
msgid "log: received negative argument %g"
msgstr "log: argomento ricevuto negativo %g"
-#: builtin.c:758 builtin.c:763 builtin.c:914
+#: builtin.c:784 builtin.c:789 builtin.c:940
msgid "fatal: must use `count$' on all formats or none"
msgstr "fatale: `count$' va usato per tutti i formati o per nessuno"
-#: builtin.c:833
+#: builtin.c:859
#, c-format
msgid "field width is ignored for `%%' specifier"
msgstr "larghezza campo ignorata per la specifica `%%'"
-#: builtin.c:835
+#: builtin.c:861
#, c-format
msgid "precision is ignored for `%%' specifier"
msgstr "precisione ignorata per la specifica `%%'"
-#: builtin.c:837
+#: builtin.c:863
#, c-format
msgid "field width and precision are ignored for `%%' specifier"
msgstr "larghezza campo e precisone ignorate per la specifica `%%'"
-#: builtin.c:888
+#: builtin.c:914
msgid "fatal: `$' is not permitted in awk formats"
msgstr "fatale: operatore `$' non consentito nei formati awk"
-#: builtin.c:897
+#: builtin.c:923
msgid "fatal: arg count with `$' must be > 0"
msgstr "fatale: numero argomenti con `$' dev'essere > 0"
-#: builtin.c:901
+#: builtin.c:927
#, c-format
msgid "fatal: arg count %ld greater than total number of supplied arguments"
msgstr "fatale: numero argomenti %ld > del numero totale argomenti specificati"
-#: builtin.c:905
+#: builtin.c:931
msgid "fatal: `$' not permitted after period in format"
msgstr "fatale: `$' non consentito dopo il punto in un formato"
-#: builtin.c:924
+#: builtin.c:950
msgid "fatal: no `$' supplied for positional field width or precision"
msgstr "fatale: manca `$' per i campi posizionali larghezza o precisione"
-#: builtin.c:994
+#: builtin.c:1020
msgid "`l' is meaningless in awk formats; ignored"
msgstr "`l' non ha senso nei formati awk; ignorato"
-#: builtin.c:998
+#: builtin.c:1024
msgid "fatal: `l' is not permitted in POSIX awk formats"
msgstr "fatale: `l' non consentito nei formati POSIX awk"
-#: builtin.c:1011
+#: builtin.c:1037
msgid "`L' is meaningless in awk formats; ignored"
msgstr "`L' non ha senso nei formati awk; ignorato"
-#: builtin.c:1015
+#: builtin.c:1041
msgid "fatal: `L' is not permitted in POSIX awk formats"
msgstr "fatale: `L' non consentito nei formati POSIX awk"
-#: builtin.c:1028
+#: builtin.c:1054
msgid "`h' is meaningless in awk formats; ignored"
msgstr "`h' non ha senso nei formati awk; ignorato"
-#: builtin.c:1032
+#: builtin.c:1058
msgid "fatal: `h' is not permitted in POSIX awk formats"
msgstr "fatale: `h' non consentito nei formati POSIX awk"
-#: builtin.c:1058
+#: builtin.c:1083
#, c-format
msgid "[s]printf: value %g is too big for %%c format"
msgstr "[s]printf: valore %g troppo elevato per il formato %%c"
-#: builtin.c:1071
+#: builtin.c:1096
#, c-format
msgid "[s]printf: value %g is not a valid wide character"
msgstr "[s]printf: valore %g non è un carattere multibyte valido "
-#: builtin.c:1457
+#: builtin.c:1482
#, c-format
msgid "[s]printf: value %g is out of range for `%%%c' format"
msgstr "[s]printf: valore %g fuori intervallo per il formato `%%%c'"
-#: builtin.c:1555
+#: builtin.c:1580
#, c-format
msgid "ignoring unknown format specifier character `%c': no argument converted"
msgstr "carattere di formato ignoto `%c' ignorato: nessun argomento convertito"
-#: builtin.c:1560
+#: builtin.c:1585
msgid "fatal: not enough arguments to satisfy format string"
msgstr ""
"fatale: argomenti in numero minore di quelli richiesti dalla stringa di "
"formato"
-#: builtin.c:1562
+#: builtin.c:1587
msgid "^ ran out for this one"
msgstr "^ esauriti a questo punto"
-#: builtin.c:1569
+#: builtin.c:1594
msgid "[s]printf: format specifier does not have control letter"
msgstr "[s]printf: specifica di formato senza un carattere di controllo"
-#: builtin.c:1572
+#: builtin.c:1597
msgid "too many arguments supplied for format string"
msgstr "troppi argomenti specificati per questa stringa di formato"
-#: builtin.c:1631
+#: builtin.c:1656
msgid "sprintf: no arguments"
msgstr "sprintf: nessun argomento"
-#: builtin.c:1654 builtin.c:1665
+#: builtin.c:1679 builtin.c:1690
msgid "printf: no arguments"
msgstr "printf: nessun argomento"
-#: builtin.c:1676
+#: builtin.c:1705
msgid "printf: attempt to write to closed write end of two-way pipe"
msgstr ""
"printf: tentativo di scrivere al lato in scrittura, chiuso, di una `pipe' "
"bidirezionale"
-#: builtin.c:1713
+#: builtin.c:1746
msgid "sqrt: received non-numeric argument"
msgstr "sqrt: l'argomento ricevuto non è numerico"
-#: builtin.c:1717
+#: builtin.c:1750
#, c-format
msgid "sqrt: called with negative argument %g"
msgstr "sqrt: chiamata con argomento negativo %g"
-#: builtin.c:1748
+#: builtin.c:1781
#, c-format
msgid "substr: length %g is not >= 1"
msgstr "substr: lunghezza %g non >= 1"
-#: builtin.c:1750
+#: builtin.c:1783
#, c-format
msgid "substr: length %g is not >= 0"
msgstr "substr: lunghezza %g non >= 0"
-#: builtin.c:1764
+#: builtin.c:1797
#, c-format
msgid "substr: non-integer length %g will be truncated"
msgstr "substr: lunghezza non intera %g: sarà troncata"
-#: builtin.c:1769
+#: builtin.c:1802
#, c-format
msgid "substr: length %g too big for string indexing, truncating to %g"
msgstr "substr: lunghezza %g troppo elevata per indice stringa, tronco a %g"
-#: builtin.c:1781
+#: builtin.c:1814
#, c-format
msgid "substr: start index %g is invalid, using 1"
msgstr "substr: indice di partenza %g non valido, uso 1"
-#: builtin.c:1786
+#: builtin.c:1819
#, c-format
msgid "substr: non-integer start index %g will be truncated"
msgstr "substr: indice di partenza non intero %g: sarà troncato"
-#: builtin.c:1809
+#: builtin.c:1842
msgid "substr: source string is zero length"
msgstr "substr: stringa di partenza lunga zero"
-#: builtin.c:1823
+#: builtin.c:1856
#, c-format
msgid "substr: start index %g is past end of string"
msgstr "substr: indice di partenza %g oltre la fine della stringa"
-#: builtin.c:1831
+#: builtin.c:1864
#, c-format
msgid ""
"substr: length %g at start index %g exceeds length of first argument (%lu)"
@@ -787,217 +801,261 @@ msgstr ""
"substr: lunghezza %g all'indice di partenza %g supera la lunghezza del primo "
"argomento (%lu)"
-#: builtin.c:1903
+#: builtin.c:1937
msgid "strftime: format value in PROCINFO[\"strftime\"] has numeric type"
msgstr ""
"strftime: il valore del formato in PROCINFO[\"strftime\"] è di tipo numerico"
-#: builtin.c:1926
+#: builtin.c:1957
msgid "strftime: received non-numeric second argument"
msgstr "strftime: il secondo argomento ricevuto non è numerico"
-#: builtin.c:1936
+#: builtin.c:1967
msgid "strftime: second argument less than 0 or too big for time_t"
msgstr "strftime: il secondo argomento è < 0 o troppo elevato per time_t"
-#: builtin.c:1943
+#: builtin.c:1974
msgid "strftime: second argument out of range for time_t"
msgstr "strftime: il secondo argomento è fuori intervallo per time_t"
-#: builtin.c:1952
+#: builtin.c:1983
msgid "strftime: received non-string first argument"
msgstr "strftime: il primo argomento ricevuto non è una stringa"
-#: builtin.c:1959
+#: builtin.c:1990
msgid "strftime: received empty format string"
msgstr "strftime: il formato ricevuto è una stringa nulla"
-#: builtin.c:2028
+#: builtin.c:2061
+#, c-format
+msgid "setenv(TZ, %s) failed (%s)"
+msgstr "setenv(TZ, %s) non riuscita (%s)"
+
+#: builtin.c:2068
+#, c-format
+msgid "setenv(TZ, %s) restoration failed (%s)"
+msgstr "setenv(TZ, %s) ripristino non riuscito (%s)"
+
+#: builtin.c:2072
+#, c-format
+msgid "unsetenv(TZ) failed (%s)"
+msgstr "unsetenv(TZ) non riuscita (%s)"
+
+#: builtin.c:2101
msgid "mktime: received non-string argument"
msgstr "mktime: l'argomento ricevuto non è una stringa"
-#: builtin.c:2045
+#: builtin.c:2118
msgid "mktime: at least one of the values is out of the default range"
msgstr "mktime: almeno un valore è fuori dall'intervallo di default"
-#: builtin.c:2081
+#: builtin.c:2154
msgid "'system' function not allowed in sandbox mode"
msgstr "funzione 'system' non consentita in modo `sandbox'"
-#: builtin.c:2086
+#: builtin.c:2159
msgid "system: received non-string argument"
msgstr "system: l'argomento ricevuto non è una stringa"
-#: builtin.c:2165 builtin.c:2230
+#: builtin.c:2228 builtin.c:2302
msgid "print: attempt to write to closed write end of two-way pipe"
msgstr ""
"print: tentativo di scrivere al lato in scrittura, chiuso, di una `pipe' "
"bidirezionale"
-#: builtin.c:2248
+#: builtin.c:2325
#, c-format
msgid "reference to uninitialized field `$%d'"
msgstr "riferimento a variabile non inizializzata `$%d'"
-#: builtin.c:2333
+#: builtin.c:2410
msgid "tolower: received non-string argument"
msgstr "tolower: l'argomento ricevuto non è una stringa"
-#: builtin.c:2364
+#: builtin.c:2441
msgid "toupper: received non-string argument"
msgstr "toupper: l'argomento ricevuto non è una stringa"
-#: builtin.c:2397 mpfr.c:681
+#: builtin.c:2474 mpfr.c:676
msgid "atan2: received non-numeric first argument"
msgstr "atan2: il primo argomento ricevuto non è numerico"
-#: builtin.c:2399 mpfr.c:683
+#: builtin.c:2476 mpfr.c:678
msgid "atan2: received non-numeric second argument"
msgstr "atan2: il secondo argomento ricevuto non è numerico"
-#: builtin.c:2418
+#: builtin.c:2495
msgid "sin: received non-numeric argument"
msgstr "sin: l'argomento ricevuto non è numerico"
-#: builtin.c:2434
+#: builtin.c:2511
msgid "cos: received non-numeric argument"
msgstr "cos: l'argomento ricevuto non è numerico"
-#: builtin.c:2487 mpfr.c:1180
+#: builtin.c:2625 mpfr.c:1171
msgid "srand: received non-numeric argument"
msgstr "srand: l'argomento ricevuto non è numerico"
-#: builtin.c:2518
+#: builtin.c:2656
msgid "match: third argument is not an array"
msgstr "match: terzo argomento non-vettoriale"
-#: builtin.c:2779
+#: builtin.c:2923
#, c-format
msgid "gensub: third argument `%.*s' treated as 1"
msgstr "gensub: il terzo argomento `%.*s' trattato come 1"
-#: builtin.c:2794
-#, c-format
-msgid "gensub: third argument %g treated as 1"
-msgstr "gensub: il terzo argomento %g trattato come 1"
-
-#: builtin.c:3096
+#: builtin.c:3245
#, c-format
msgid "%s: can be called indirectly only with two arguments"
msgstr "%s: può essere chiamata indirettamente solo con due argomenti"
-#: builtin.c:3186
+#: builtin.c:3345
#, c-format
msgid "indirect call to %s requires at least two arguments"
msgstr "chiamata indiretta a %s richiede almeno due argomenti"
-#: builtin.c:3238
+#: builtin.c:3400
msgid "lshift: received non-numeric first argument"
msgstr "lshift: il primo argomento ricevuto non è numerico"
-#: builtin.c:3240
+#: builtin.c:3402
msgid "lshift: received non-numeric second argument"
msgstr "lshift: il secondo argomento ricevuto non è numerico"
-#: builtin.c:3246
+#: builtin.c:3408
#, c-format
-msgid "lshift(%f, %f): negative values will give strange results"
-msgstr "lshift(%f, %f): valori negativi daranno risultati strani"
+msgid "lshift(%f, %f): negative values are not allowed"
+msgstr "lshift(%f, %f): valori negativi non sono consentiti"
-#: builtin.c:3248
+#: builtin.c:3412
#, c-format
msgid "lshift(%f, %f): fractional values will be truncated"
msgstr "lshift(%f, %f): valori decimali saranno troncati"
-#: builtin.c:3250
+#: builtin.c:3414
#, c-format
msgid "lshift(%f, %f): too large shift value will give strange results"
msgstr "lshift(%f, %f): valori troppo alti daranno risultati strani"
-#: builtin.c:3275
+#: builtin.c:3439
msgid "rshift: received non-numeric first argument"
msgstr "rshift: il primo argomento ricevuto non è numerico"
-#: builtin.c:3277
+#: builtin.c:3441
msgid "rshift: received non-numeric second argument"
msgstr "rshift: il secondo argomento ricevuto non è numerico"
-#: builtin.c:3283
+#: builtin.c:3447
#, c-format
-msgid "rshift(%f, %f): negative values will give strange results"
-msgstr "rshift(%f, %f): valori negativi daranno risultati strani"
+msgid "rshift(%f, %f): negative values are not allowed"
+msgstr "rshift(%f, %f): valori negativi non sono consentiti"
-#: builtin.c:3285
+#: builtin.c:3451
#, c-format
msgid "rshift(%f, %f): fractional values will be truncated"
msgstr "rshift(%f, %f): valori decimali saranno troncati"
-#: builtin.c:3287
+#: builtin.c:3453
#, c-format
msgid "rshift(%f, %f): too large shift value will give strange results"
msgstr "rshift(%f, %f): valori troppo alti daranno risultati strani"
-#: builtin.c:3312 mpfr.c:992
+#: builtin.c:3478 mpfr.c:984
msgid "and: called with less than two arguments"
msgstr "and: chiamata con meno di due argomenti"
-#: builtin.c:3317
+#: builtin.c:3483
#, c-format
msgid "and: argument %d is non-numeric"
msgstr "and: l'argomento %d non è numerico"
-#: builtin.c:3321
+#: builtin.c:3487
#, c-format
-msgid "and: argument %d negative value %g will give strange results"
-msgstr "and: argomento %d, valore negativo %g darà risultati strani"
+msgid "and: argument %d negative value %g is not allowed"
+msgstr "and: argomento %d, valore negativo %g non consentito"
-#: builtin.c:3344 mpfr.c:1024
+#: builtin.c:3510 mpfr.c:1016
msgid "or: called with less than two arguments"
msgstr "or: chiamata con meno di due argomenti"
-#: builtin.c:3349
+#: builtin.c:3515
#, c-format
msgid "or: argument %d is non-numeric"
msgstr "or: l'argomento %d non è numerico"
-#: builtin.c:3353
+#: builtin.c:3519
#, c-format
-msgid "or: argument %d negative value %g will give strange results"
-msgstr "or: argomento %d, valore negativo %g darà risultati strani"
+msgid "or: argument %d negative value %g is not allowed"
+msgstr "or: argomento %d, valore negativo %g non consentito"
-#: builtin.c:3375 mpfr.c:1055
+#: builtin.c:3541 mpfr.c:1047
msgid "xor: called with less than two arguments"
msgstr "xor: chiamata con meno di due argomenti"
-#: builtin.c:3381
+#: builtin.c:3547
#, c-format
msgid "xor: argument %d is non-numeric"
msgstr "xor: l'argomento %d non è numerico"
-#: builtin.c:3385
+#: builtin.c:3551
#, c-format
-msgid "xor: argument %d negative value %g will give strange results"
-msgstr "xor: argomento %d, valore negativo %g darà risultati strani"
+msgid "xor: argument %d negative value %g is not allowed"
+msgstr "xor: argomento %d, valore negativo %g non consentito"
-#: builtin.c:3410 mpfr.c:811
+#: builtin.c:3576 mpfr.c:806
msgid "compl: received non-numeric argument"
msgstr "compl: l'argomento ricevuto non è numerico"
-#: builtin.c:3416
+#: builtin.c:3581
#, c-format
-msgid "compl(%f): negative value will give strange results"
-msgstr "compl(%f): valore negativo, darà risultati strani"
+msgid "compl(%f): negative value is not allowed"
+msgstr "compl(%f): valore negativo non consentito"
-#: builtin.c:3418
+#: builtin.c:3584
#, c-format
msgid "compl(%f): fractional value will be truncated"
msgstr "compl(%f): valori decimali saranno troncati"
-#: builtin.c:3588
+#: builtin.c:3768
#, c-format
msgid "dcgettext: `%s' is not a valid locale category"
msgstr "dcgettext: `%s' non è una categoria `locale' valida"
+#: builtin.c:3993 mpfr.c:1204
+msgid "intdiv: third argument is not an array"
+msgstr "intdiv: il terzo argomento non è un vettore"
+
+#: builtin.c:4001 mpfr.c:1212
+msgid "intdiv: received non-numeric first argument"
+msgstr "intdiv: il primo argomento ricevuto non è numerico"
+
+#: builtin.c:4003 mpfr.c:1214
+msgid "intdiv: received non-numeric second argument"
+msgstr "intdiv: il secondo argomento ricevuto non è numerico"
+
+#: builtin.c:4012 mpfr.c:1248
+msgid "intdiv: division by zero attempted"
+msgstr "intdiv: tentativo di dividere per zero"
+
+#: builtin.c:4078
+#, c-format
+msgid ""
+"typeof detected invalid flags combination `%s'; please file a bug report."
+msgstr ""
+"typeof ha trovato una combinazione di flag `%s' non valida; siete pregati di "
+"notificare questo bug."
+
+#: builtin.c:4093
+#, c-format
+msgid "typeof: invalid argument type `%s'"
+msgstr "typeof: tipo di argomento sconosciuto `%s'"
+
+#: builtin.c:4097
+#, c-format
+msgid "typeof: unknown argument type `%s'"
+msgstr "typeof: tipo di argomento sconosciuto `%s'"
+
#: command.y:226
#, c-format
msgid "Type (g)awk statement(s). End with the command \"end\"\n"
@@ -1312,7 +1370,7 @@ msgstr ""
"dove [N] - (equivalente a backtrace) stampa tracia di tutti gli elementi o "
"degli N più interni (più esterni se N <0)"
-#: command.y:1016 debug.c:401 msg.c:135
+#: command.y:1016 debug.c:401 gawkapi.c:221 msg.c:137
#, c-format
msgid "error: "
msgstr "errore: "
@@ -1549,28 +1607,28 @@ msgstr "vettore `%s' vuoto\n"
#: debug.c:1119 debug.c:1171
#, c-format
-msgid "[\"%s\"] not in array `%s'\n"
-msgstr "[\"%s\"] non presente nel vettore `%s\n"
+msgid "[\"%.*s\"] not in array `%s'\n"
+msgstr "[\"%.*s\"] non presente nel vettore `%s'\n"
#: debug.c:1175
#, c-format
-msgid "`%s[\"%s\"]' is not an array\n"
-msgstr "`%s[\"%s\"]' non è un vettore\n"
+msgid "`%s[\"%.*s\"]' is not an array\n"
+msgstr "`%s[\"%.*s\"]' non è un vettore\n"
-#: debug.c:1236 debug.c:5010
+#: debug.c:1236 debug.c:5017
#, c-format
msgid "`%s' is not a scalar variable"
msgstr "`%s' non è una variabile scalare"
-#: debug.c:1258 debug.c:5040
+#: debug.c:1258
#, c-format
-msgid "attempt to use array `%s[\"%s\"]' in a scalar context"
-msgstr "tentativo di usare vettore `%s[\"%s\"]' in un contesto scalare"
+msgid "attempt to use array `%s[\".*%s\"]' in a scalar context"
+msgstr "tentativo di usare vettore `%s[\".*%s\"]' in un contesto scalare"
-#: debug.c:1280 debug.c:5051
+#: debug.c:1280
#, c-format
-msgid "attempt to use scalar `%s[\"%s\"]' as array"
-msgstr "tentativo di usare scalare `%s[\"%s\"]' come vettore"
+msgid "attempt to use scalar `%s[\".*%s\"]' as array"
+msgstr "tentativo di usare scalare `%s[\".*%s\"]' come vettore"
#: debug.c:1423
#, c-format
@@ -1594,330 +1652,308 @@ msgstr "Nessun elemento numerato watch [da sorvegliare] da visualizzare %ld"
#: debug.c:1528
#, c-format
-msgid "%d: [\"%s\"] not in array `%s'\n"
-msgstr "%d: [\"%s\"] non presente nel vettore `%s'\n"
+msgid "%d: [\"%.*s\"] not in array `%s'\n"
+msgstr "%d: [\"%.*s\"] non presente nel vettore `%s'\n"
#: debug.c:1767
msgid "attempt to use scalar value as array"
msgstr "tentativo di usare valore scalare come vettore"
-#: debug.c:1856
+#: debug.c:1858
#, c-format
msgid "Watchpoint %d deleted because parameter is out of scope.\n"
msgstr "Watchpoint %d cancellato perché il parametro è fuori intervallo.\n"
-#: debug.c:1867
+#: debug.c:1869
#, c-format
msgid "Display %d deleted because parameter is out of scope.\n"
msgstr ""
"Visualizzazione %d cancellata perché il parametro è fuori intervallo.\n"
-#: debug.c:1900
+#: debug.c:1902
#, c-format
msgid " in file `%s', line %d\n"
msgstr " nel file `%s', riga %d\n"
-#: debug.c:1921
+#: debug.c:1923
#, c-format
msgid " at `%s':%d"
msgstr " a `%s':%d"
-#: debug.c:1937 debug.c:2000
+#: debug.c:1939 debug.c:2002
#, c-format
msgid "#%ld\tin "
msgstr "#%ld\tin "
-#: debug.c:1974
+#: debug.c:1976
#, c-format
msgid "More stack frames follow ...\n"
msgstr "Ulteriori elementi stack seguono...\n"
-#: debug.c:2017
+#: debug.c:2019
msgid "invalid frame number"
msgstr "numero elemento non valido"
-#: debug.c:2200
+#: debug.c:2202
#, c-format
msgid "Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d"
msgstr ""
"Nota: breakpoint %d (abilitato, ignora prossimi %ld passaggi), anche "
"impostato a %s:%d"
-#: debug.c:2207
+#: debug.c:2209
#, c-format
msgid "Note: breakpoint %d (enabled), also set at %s:%d"
msgstr "Nota: breakpoint %d (abilitato), anche impostato a %s:%d"
-#: debug.c:2214
+#: debug.c:2216
#, c-format
msgid "Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d"
msgstr ""
"Nota: breakpoint %d (disabilitato, ignora prossimi %ld passaggi), anche "
"impostato a %s:%d"
-#: debug.c:2221
+#: debug.c:2223
#, c-format
msgid "Note: breakpoint %d (disabled), also set at %s:%d"
msgstr "Nota: breakpoint %d (disabilitato), anche impostato a %s:%d"
-#: debug.c:2238
+#: debug.c:2240
#, c-format
msgid "Breakpoint %d set at file `%s', line %d\n"
msgstr "Breakpoint %d impostato al file `%s', riga %d\n"
-#: debug.c:2340
+#: debug.c:2342
#, c-format
msgid "Can't set breakpoint in file `%s'\n"
msgstr "Non riesco a impostare breakpoint nel file `%s'\n"
-#: debug.c:2369 debug.c:2492 debug.c:3350
+#: debug.c:2371 debug.c:2494 debug.c:3356
#, c-format
msgid "line number %d in file `%s' out of range"
msgstr "numero riga %d nel file `%s' fuori intervallo"
-#: debug.c:2373
+#: debug.c:2375
#, c-format
msgid "Can't find rule!!!\n"
msgstr "Non riesco a trovare la regola!!!\n"
-#: debug.c:2375
+#: debug.c:2377
#, c-format
msgid "Can't set breakpoint at `%s':%d\n"
msgstr "Non riesco a impostare breakpoint a `%s':%d\n"
-#: debug.c:2387
+#: debug.c:2389
#, c-format
msgid "Can't set breakpoint in function `%s'\n"
msgstr "Non riesco a impostare breakpoint nella funzione `%s'\n"
-#: debug.c:2403
+#: debug.c:2405
#, c-format
msgid "breakpoint %d set at file `%s', line %d is unconditional\n"
msgstr "breakpoint %d impostato al file `%s', riga %d è senza condizioni\n"
-#: debug.c:2508 debug.c:2530
+#: debug.c:2510 debug.c:2532
#, c-format
msgid "Deleted breakpoint %d"
msgstr "Cancellato breakpoint %d"
-#: debug.c:2514
+#: debug.c:2516
#, c-format
msgid "No breakpoint(s) at entry to function `%s'\n"
msgstr "No breakpoint all'entrata nella funzione `%s'\n"
-#: debug.c:2541
+#: debug.c:2543
#, c-format
msgid "No breakpoint at file `%s', line #%d\n"
msgstr "No breakpoint al file `%s', riga #%d\n"
-#: debug.c:2596 debug.c:2637 debug.c:2657 debug.c:2700
+#: debug.c:2598 debug.c:2639 debug.c:2659 debug.c:2702
msgid "invalid breakpoint number"
msgstr "numero breakpoint non valido"
-#: debug.c:2612
+#: debug.c:2614
msgid "Delete all breakpoints? (y or n) "
msgstr "Cancello tutti i breakpoint? (y oppure n) "
-#: debug.c:2613 debug.c:2923 debug.c:2976
+#: debug.c:2615 debug.c:2929 debug.c:2982
msgid "y"
msgstr "y"
-#: debug.c:2662
+#: debug.c:2664
#, c-format
msgid "Will ignore next %ld crossing(s) of breakpoint %d.\n"
msgstr "Prossimi %ld passaggi dal breakpoint %d ignorati.\n"
-#: debug.c:2666
+#: debug.c:2668
#, c-format
msgid "Will stop next time breakpoint %d is reached.\n"
msgstr "Farò uno stop al prossimo passaggio dal breakpoint %d.\n"
-#: debug.c:2783
+#: debug.c:2785
#, c-format
msgid "Can only debug programs provided with the `-f' option.\n"
msgstr "Debug possibile solo per programmi con opzione `-f' specificata.\n"
-#: debug.c:2908
+#: debug.c:2914
#, c-format
msgid "Failed to restart debugger"
msgstr "Non sono riuscito a far ripartire il debugger"
-#: debug.c:2922
+#: debug.c:2928
msgid "Program already running. Restart from beginning (y/n)? "
msgstr "Programma già in esecuzione. Lo faccio ripartire dall'inizio (y/n)? "
-#: debug.c:2926
+#: debug.c:2932
#, c-format
msgid "Program not restarted\n"
msgstr "Programma non fatto ripartire\n"
-#: debug.c:2936
+#: debug.c:2942
#, c-format
msgid "error: cannot restart, operation not allowed\n"
msgstr "errore: non riesco a far ripartire, operazione non consentita\n"
-#: debug.c:2942
+#: debug.c:2948
#, c-format
msgid "error (%s): cannot restart, ignoring rest of the commands\n"
msgstr "errore (%s): non riesco a far ripartire, ignoro i comandi rimanenti\n"
-#: debug.c:2950
+#: debug.c:2956
#, c-format
msgid "Starting program: \n"
msgstr "Partenza del programma: \n"
-#: debug.c:2959
+#: debug.c:2966
#, c-format
-msgid "Program exited %s with exit value: %d\n"
-msgstr "Programma completato %s, valore in uscita: %d\n"
+msgid "Program exited abnormally with exit value: %d\n"
+msgstr "Programma completato anormalmente, valore in uscita: %d\n"
-#: debug.c:2975
+#: debug.c:2967
+#, c-format
+msgid "Program exited normally with exit value: %d\n"
+msgstr "Programma completato normalmente, valore in uscita: %d\n"
+
+#: debug.c:2981
msgid "The program is running. Exit anyway (y/n)? "
msgstr "Il programma è in esecuzione. Esco comunque (y/n)? "
-#: debug.c:3010
+#: debug.c:3016
#, c-format
msgid "Not stopped at any breakpoint; argument ignored.\n"
msgstr "Non interrotto ad alcun breakpoint: argomento ignorato.\n"
-#: debug.c:3015
+#: debug.c:3021
#, c-format
msgid "invalid breakpoint number %d."
msgstr "numero di breakpoint non valido %d."
-#: debug.c:3020
+#: debug.c:3026
#, c-format
msgid "Will ignore next %ld crossings of breakpoint %d.\n"
msgstr "Prossimi %ld passaggi dal breakpoint %d ignorati.\n"
-#: debug.c:3207
+#: debug.c:3213
#, c-format
msgid "'finish' not meaningful in the outermost frame main()\n"
msgstr "'finish' non significativo nell'elemento iniziale main()\n"
-#: debug.c:3212
+#: debug.c:3218
#, c-format
msgid "Run till return from "
msgstr "Esegui fino al ritorno da "
-#: debug.c:3255
+#: debug.c:3261
#, c-format
msgid "'return' not meaningful in the outermost frame main()\n"
msgstr "'return' non significativo nell'elemento iniziale main()\n"
-#: debug.c:3369
+#: debug.c:3375
#, c-format
msgid "Can't find specified location in function `%s'\n"
msgstr "Non trovo la posizione specificata nella funzione `%s'\n"
-#: debug.c:3377
+#: debug.c:3383
#, c-format
msgid "invalid source line %d in file `%s'"
msgstr "riga sorgente invalida %d nel file `%s'"
-#: debug.c:3392
+#: debug.c:3398
#, c-format
msgid "Can't find specified location %d in file `%s'\n"
msgstr "Non trovo posizione specificata %d nel file `%s'\n"
-#: debug.c:3424
+#: debug.c:3430
#, c-format
msgid "element not in array\n"
msgstr "elemento non presente nel vettore\n"
-#: debug.c:3424
+#: debug.c:3430
#, c-format
msgid "untyped variable\n"
msgstr "variabile di tipo sconosciuto\n"
-#: debug.c:3466
+#: debug.c:3472
#, c-format
msgid "Stopping in %s ...\n"
msgstr "Mi fermo in %s ...\n"
-#: debug.c:3543
+#: debug.c:3549
#, c-format
msgid "'finish' not meaningful with non-local jump '%s'\n"
msgstr "'finish' not significativo per salti non-locali '%s'\n"
-#: debug.c:3550
+#: debug.c:3556
#, c-format
msgid "'until' not meaningful with non-local jump '%s'\n"
msgstr "'until' not significativo per salti non-locali '%s'\n"
-#: debug.c:4231
+#: debug.c:4237
msgid "\t------[Enter] to continue or q [Enter] to quit------"
msgstr "\t------[Invio] per continuare o q [Invio] per uscire------"
-#: debug.c:4232
+#: debug.c:4238
msgid "q"
msgstr "q"
#: debug.c:5047
#, c-format
-msgid "[\"%s\"] not in array `%s'"
-msgstr "[\"%s\"] non presente nel vettore `%s'"
+msgid "attempt to use array `%s[\"%.*s\"]' in a scalar context"
+msgstr "tentativo di usare vettore `%s[\"%.*s\"]' in un contesto scalare"
+
+#: debug.c:5054
+#, c-format
+msgid "[\"%.*s\"] not in array `%s'"
+msgstr "[\"%.*s\"] non presente nel vettore `%s'"
-#: debug.c:5253
+#: debug.c:5058
+#, c-format
+msgid "attempt to use scalar `%s[\"%.*s\"]' as array"
+msgstr "tentativo di usare scalare `%s[\"%.*s\"]' come vettore"
+
+#: debug.c:5260
#, c-format
msgid "sending output to stdout\n"
msgstr "output inviato a stdout\n"
-#: debug.c:5293
+#: debug.c:5300
msgid "invalid number"
msgstr "numero non valido"
-#: debug.c:5427
+#: debug.c:5434
#, c-format
msgid "`%s' not allowed in current context; statement ignored"
msgstr "`%s' non consentito nel contesto corrente; istruzione ignorata"
-#: debug.c:5435
+#: debug.c:5442
msgid "`return' not allowed in current context; statement ignored"
msgstr "`return' non consentito nel contesto corrente; istruzione ignorata"
-#: debug.c:5650
+#: debug.c:5657
#, c-format
msgid "No symbol `%s' in current context"
msgstr "Simbolo `%s' non esiste nel contesto corrente"
-#: dfa.c:1090 dfa.c:1093 dfa.c:1112 dfa.c:1122 dfa.c:1135 dfa.c:1163 dfa.c:1172
-#: dfa.c:1175 dfa.c:1180 dfa.c:1202 dfa.c:1205
-msgid "unbalanced ["
-msgstr "[ non chiusa"
-
-#: dfa.c:1148
-msgid "invalid character class"
-msgstr "character class non valida"
-
-#: dfa.c:1271
-msgid "character class syntax is [[:space:]], not [:space:]"
-msgstr "sintassi character class è [[:spazio:]], non [:spazio:]"
-
-#: dfa.c:1332
-msgid "unfinished \\ escape"
-msgstr "sequenza escape \\ non completa"
-
-#: dfa.c:1499
-msgid "invalid content of \\{\\}"
-msgstr "contenuto di \\{\\} non valido"
-
-#: dfa.c:1502
-msgid "regular expression too big"
-msgstr "espressione regolare troppo complessa"
-
-#: dfa.c:1916
-msgid "unbalanced ("
-msgstr "( non chiusa"
-
-#: dfa.c:2044
-msgid "no syntax specified"
-msgstr "nessuna sintassi specificata"
-
-#: dfa.c:2052
-msgid "unbalanced )"
-msgstr ") non aperta"
-
#: eval.c:398
#, c-format
msgid "unknown nodetype %d"
@@ -1933,11 +1969,11 @@ msgstr "codice operativo sconosciuto %d"
msgid "opcode %s not an operator or keyword"
msgstr "codice operativo %s non è un operatore o una parola chiave"
-#: eval.c:476
+#: eval.c:478
msgid "buffer overflow in genflags2str"
msgstr "superamento limiti buffer in 'genflags2str'"
-#: eval.c:678
+#: eval.c:680
#, c-format
msgid ""
"\n"
@@ -1948,357 +1984,263 @@ msgstr ""
"\t# `Stack' (Pila) Chiamate Funzione:\n"
"\n"
-#: eval.c:707
+#: eval.c:708
msgid "`IGNORECASE' is a gawk extension"
msgstr "`IGNORECASE' è un'estensione gawk"
-#: eval.c:739
+#: eval.c:729
msgid "`BINMODE' is a gawk extension"
msgstr "`BINMODE' è un'estensione gawk"
-#: eval.c:797
+#: eval.c:786
#, c-format
msgid "BINMODE value `%s' is invalid, treated as 3"
msgstr "valore di BINMODE `%s' non valido, considerato come 3"
-#: eval.c:914
+#: eval.c:909
#, c-format
msgid "bad `%sFMT' specification `%s'"
msgstr "specificazione invalida `%sFMT' `%s'"
-#: eval.c:988
+#: eval.c:977
msgid "turning off `--lint' due to assignment to `LINT'"
msgstr "disabilito `--lint' a causa di assegnamento a `LINT'"
-#: eval.c:1166
+#: eval.c:1155
#, c-format
msgid "reference to uninitialized argument `%s'"
msgstr "riferimento ad argomento non inizializzato `%s'"
-#: eval.c:1167
+#: eval.c:1156
#, c-format
msgid "reference to uninitialized variable `%s'"
msgstr "riferimento a variabile non inizializzata `%s'"
-#: eval.c:1185
+#: eval.c:1174
msgid "attempt to field reference from non-numeric value"
msgstr "tentativo di riferimento a un campo da valore non-numerico"
-#: eval.c:1187
+#: eval.c:1176
msgid "attempt to field reference from null string"
msgstr "tentativo di riferimento a un campo da una stringa nulla"
-#: eval.c:1195
+#: eval.c:1184
#, c-format
msgid "attempt to access field %ld"
msgstr "tentativo di accedere al campo %ld"
-#: eval.c:1204
+#: eval.c:1193
#, c-format
msgid "reference to uninitialized field `$%ld'"
msgstr "riferimento a campo non inizializzato `$%ld'"
-#: eval.c:1291
+#: eval.c:1280
#, c-format
msgid "function `%s' called with more arguments than declared"
msgstr "funzione `%s' chiamata con più argomenti di quelli previsti"
-#: eval.c:1498
+#: eval.c:1487
#, c-format
msgid "unwind_stack: unexpected type `%s'"
msgstr "unwind_stack: tipo non previsto `%s'"
-#: eval.c:1594
+#: eval.c:1580
msgid "division by zero attempted in `/='"
msgstr "divisione per zero tentata in `/='"
-#: eval.c:1601
+#: eval.c:1587
#, c-format
msgid "division by zero attempted in `%%='"
msgstr "divisione per zero tentata in `%%='"
-#: ext.c:66 ext.c:148
+#: ext.c:63
msgid "extensions are not allowed in sandbox mode"
msgstr "le estensioni non sono consentite in modo `sandbox'"
-#: ext.c:69
+#: ext.c:66
msgid "-l / @load are gawk extensions"
msgstr "-l / @load sono estensioni gawk"
-#: ext.c:72
+#: ext.c:69
msgid "load_ext: received NULL lib_name"
msgstr "load_ext: il nome libreria ricevuto è NULL"
-#: ext.c:75
+#: ext.c:72
#, c-format
msgid "load_ext: cannot open library `%s' (%s)\n"
msgstr "load_ext: non riesco ad aprire libreria `%s' (%s)\n"
-#: ext.c:81
+#: ext.c:78
#, c-format
msgid ""
"load_ext: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n"
msgstr ""
"load_ext: libreria `%s': non definisce `plugin_is_GPL_compatible' (%s)\n"
-#: ext.c:87
+#: ext.c:84
#, c-format
msgid "load_ext: library `%s': cannot call function `%s' (%s)\n"
msgstr "load_ext: libreria `%s': non riesco a chiamare funzione `%s' (%s)\n"
-#: ext.c:91
+#: ext.c:88
#, c-format
msgid "load_ext: library `%s' initialization routine `%s' failed\n"
msgstr ""
"load_ext: libreria `%s' routine di inizializzazione `%s' non riuscita\n"
-#: ext.c:151
-#, fuzzy
-msgid "`extension' is a gawk extension"
-msgstr "`%s' è un'estensione gawk"
-
-#: ext.c:154
-#, fuzzy
-msgid "extension: received NULL lib_name"
-msgstr "load_ext: il nome libreria ricevuto è NULL"
-
-#: ext.c:157
-#, fuzzy, c-format
-msgid "extension: cannot open library `%s' (%s)"
-msgstr "load_ext: non riesco ad aprire libreria `%s' (%s)\n"
-
-#: ext.c:163
-#, fuzzy, c-format
-msgid ""
-"extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)"
-msgstr ""
-"load_ext: libreria `%s': non definisce `plugin_is_GPL_compatible' (%s)\n"
-
-#: ext.c:167
-#, fuzzy, c-format
-msgid "extension: library `%s': cannot call function `%s' (%s)"
-msgstr "load_ext: libreria `%s': non riesco a chiamare funzione `%s' (%s)\n"
-
-#: ext.c:198
+#: ext.c:106
msgid "make_builtin: missing function name"
msgstr "make_builtin: manca nome di funzione"
-#: ext.c:213
+#: ext.c:121
#, c-format
msgid "make_builtin: can't redefine function `%s'"
msgstr "make_builtin: non riesco a ridefinire funzione `%s'"
-#: ext.c:217
+#: ext.c:125
#, c-format
msgid "make_builtin: function `%s' already defined"
msgstr "make_builtin: funzione `%s' già definita"
-#: ext.c:221
+#: ext.c:129
#, c-format
msgid "make_builtin: function name `%s' previously defined"
msgstr "make_builtin: funzione di nome `%s' definita in precedenza"
-#: ext.c:223
+#: ext.c:131
#, c-format
msgid "make_builtin: can't use gawk built-in `%s' as function name"
msgstr ""
"make_builtin: nome funzione interna gawk `%s' non ammesso come nome funzione"
-#: ext.c:226 ext.c:281
+#: ext.c:134
#, c-format
msgid "make_builtin: negative argument count for function `%s'"
msgstr "make_builtin: contatore argomenti negativo per la funzione `%s'"
-#: ext.c:253
-#, fuzzy
-msgid "extension: missing function name"
-msgstr "make_builtin: manca nome di funzione"
-
-#: ext.c:256 ext.c:260
-#, c-format
-msgid "extension: illegal character `%c' in function name `%s'"
-msgstr ""
-
-#: ext.c:268
-#, fuzzy, c-format
-msgid "extension: can't redefine function `%s'"
-msgstr "make_builtin: non riesco a ridefinire funzione `%s'"
-
-#: ext.c:272
-#, fuzzy, c-format
-msgid "extension: function `%s' already defined"
-msgstr "make_builtin: funzione `%s' già definita"
-
-#: ext.c:276
-#, fuzzy, c-format
-msgid "extension: function name `%s' previously defined"
-msgstr "funzione di nome `%s' definita in precedenza"
-
-#: ext.c:278
-#, fuzzy, c-format
-msgid "extension: can't use gawk built-in `%s' as function name"
-msgstr ""
-"make_builtin: nome funzione interna gawk `%s' non ammesso come nome funzione"
-
-#: ext.c:358
+#: ext.c:210
#, c-format
msgid "function `%s': argument #%d: attempt to use scalar as an array"
msgstr "funzione `%s': argomento #%d: tentativo di usare scalare come vettore"
-#: ext.c:362
+#: ext.c:214
#, c-format
msgid "function `%s': argument #%d: attempt to use array as a scalar"
msgstr "funzione `%s': argomento #%d: tentativo di usare vettore come scalare"
-#: ext.c:376
+#: ext.c:228
msgid "dynamic loading of library not supported"
msgstr "caricamento dinamico di libreria non supportato"
-#: extension/filefuncs.c:164
-msgid "chdir: called with incorrect number of arguments, expecting 1"
-msgstr "chdir: chiamata con numero di argomenti errato, 1 previsto"
-
-#: extension/filefuncs.c:444
+#: extension/filefuncs.c:441
#, c-format
msgid "stat: unable to read symbolic link `%s'"
msgstr "stat: non riesco a leggere il link simbolico `%s'"
-#: extension/filefuncs.c:477
-msgid "stat: called with wrong number of arguments"
-msgstr "stat: chiamata con numero di argomenti errato"
-
-#: extension/filefuncs.c:484 extension/filefuncs.c:534
+#: extension/filefuncs.c:475 extension/filefuncs.c:519
msgid "stat: bad parameters"
msgstr "stat: parametri errati"
-#: extension/filefuncs.c:527
-msgid "statvfs: called with wrong number of arguments"
-msgstr "statvfs: chiamata con numero di argomenti errato"
-
-#: extension/filefuncs.c:598
+#: extension/filefuncs.c:583
#, c-format
msgid "fts init: could not create variable %s"
msgstr "ftp init: non riesco a creare variabile %s"
-#: extension/filefuncs.c:619
+#: extension/filefuncs.c:604
msgid "fts is not supported on this system"
msgstr "fts non disponibile su questo sistema"
-#: extension/filefuncs.c:638
+#: extension/filefuncs.c:623
msgid "fill_stat_element: could not create array"
msgstr "fill_stat_element: non riesco a creare vettore"
-#: extension/filefuncs.c:647
+#: extension/filefuncs.c:632
msgid "fill_stat_element: could not set element"
msgstr "fill_stat_element: non riesco a impostare elemento"
-#: extension/filefuncs.c:662
+#: extension/filefuncs.c:647
msgid "fill_path_element: could not set element"
msgstr "fill_path_element: non riesco a impostare elemento"
-#: extension/filefuncs.c:678
+#: extension/filefuncs.c:663
msgid "fill_error_element: could not set element"
msgstr "fill_error_element: non riesco a impostare elemento"
-#: extension/filefuncs.c:725 extension/filefuncs.c:772
+#: extension/filefuncs.c:710 extension/filefuncs.c:757
msgid "fts-process: could not create array"
msgstr "fts-process: non riesco a creare vettore"
-#: extension/filefuncs.c:735 extension/filefuncs.c:782
-#: extension/filefuncs.c:800
+#: extension/filefuncs.c:720 extension/filefuncs.c:767
+#: extension/filefuncs.c:785
msgid "fts-process: could not set element"
msgstr "fts-process: non riesco a impostare elemento"
-#: extension/filefuncs.c:849
+#: extension/filefuncs.c:834
msgid "fts: called with incorrect number of arguments, expecting 3"
msgstr "fts: chiamata con numero di argomenti errato, 3 previsti"
-#: extension/filefuncs.c:852
+#: extension/filefuncs.c:837
msgid "fts: bad first parameter"
msgstr "fts: primo parametro errato"
-#: extension/filefuncs.c:858
+#: extension/filefuncs.c:843
msgid "fts: bad second parameter"
msgstr "fts: secondo parametro errato"
-#: extension/filefuncs.c:864
+#: extension/filefuncs.c:849
msgid "fts: bad third parameter"
msgstr "fts: terzo parametro errato"
-#: extension/filefuncs.c:871
+#: extension/filefuncs.c:856
msgid "fts: could not flatten array\n"
msgstr "fts: non sono riuscito a appiattire un vettore\n"
-#: extension/filefuncs.c:889
+#: extension/filefuncs.c:874
msgid "fts: ignoring sneaky FTS_NOSTAT flag. nyah, nyah, nyah."
msgstr "fts: ignoro flag infido FTS_NOSTAT. nooo, nooo, nooo."
-#: extension/filefuncs.c:906
+#: extension/filefuncs.c:891
msgid "fts: clear_array() failed\n"
msgstr "fts: clear_array() non riuscita\n"
-#: extension/fnmatch.c:112
-msgid "fnmatch: called with less than three arguments"
-msgstr "fnmatch: chiamata con meno di tre argomenti"
-
-#: extension/fnmatch.c:115
-msgid "fnmatch: called with more than three arguments"
-msgstr "fnmatch: chiamata con più di tre argomenti"
-
-#: extension/fnmatch.c:118
+#: extension/fnmatch.c:113
msgid "fnmatch: could not get first argument"
msgstr "fnmatch: primo argomento non disponibile"
-#: extension/fnmatch.c:123
+#: extension/fnmatch.c:118
msgid "fnmatch: could not get second argument"
msgstr "fnmatch: secondo argomento non disponibile"
-#: extension/fnmatch.c:128
+#: extension/fnmatch.c:123
msgid "fnmatch: could not get third argument"
msgstr "fnmatch: terzo argomento non disponibile"
-#: extension/fnmatch.c:141
+#: extension/fnmatch.c:136
msgid "fnmatch is not implemented on this system\n"
msgstr "fnmatch non disponibile su questo sistema\n"
-#: extension/fnmatch.c:173
+#: extension/fnmatch.c:168
msgid "fnmatch init: could not add FNM_NOMATCH variable"
msgstr "fnmatch init: non riesco ad aggiungere variabile FNM_NOMATCH"
-#: extension/fnmatch.c:183
+#: extension/fnmatch.c:178
#, c-format
msgid "fnmatch init: could not set array element %s"
msgstr "fnmatch init: non riesco a impostare elemento vettoriale %s"
-#: extension/fnmatch.c:193
+#: extension/fnmatch.c:188
msgid "fnmatch init: could not install FNM array"
msgstr "fnmatch init: non riesco a installare vettore FNM"
-#: extension/fork.c:81
-msgid "fork: called with too many arguments"
-msgstr "fork: chiamata con troppi argomenti"
-
-#: extension/fork.c:94
+#: extension/fork.c:91
msgid "fork: PROCINFO is not an array!"
msgstr "fork: PROCINFO non è un vettore!"
-#: extension/fork.c:118
-msgid "waitpid: called with too many arguments"
-msgstr "waitpid: chiamata con troppi argomenti"
-
-#: extension/fork.c:126
-msgid "wait: called with no arguments"
-msgstr "wait: chiamata senza argomenti"
-
-#: extension/fork.c:143
-msgid "wait: called with too many arguments"
-msgstr "wait: chiamata con troppi argomenti"
-
#: extension/inplace.c:131
msgid "inplace_begin: in-place editing already active"
msgstr "inplace_begin: modifica in-place già attiva"
-#: extension/inplace.c:134 extension/inplace.c:211
+#: extension/inplace.c:134
#, c-format
msgid "inplace_begin: expects 2 arguments but called with %d"
msgstr "inplace_begin: 2 argumenti richiesti, ma chiamata con %d"
@@ -2349,6 +2291,11 @@ msgstr "inplace_begin: dup2(%d, stdout) non riuscita (%s)"
msgid "inplace_begin: close(%d) failed (%s)"
msgstr "inplace_begin: close(%d) non riuscita (%s)"
+#: extension/inplace.c:211
+#, c-format
+msgid "inplace_end: expects 2 arguments but called with %d"
+msgstr "inplace_end: 2 argumenti richiesti, ma chiamata con %d"
+
#: extension/inplace.c:214
msgid "inplace_end: cannot retrieve 1st argument as a string filename"
msgstr ""
@@ -2383,120 +2330,99 @@ msgstr "inplace_end: link(`%s', `%s') non riuscita (%s)"
msgid "inplace_end: rename(`%s', `%s') failed (%s)"
msgstr "inplace_end: rename(`%s', `%s') non riuscito (%s)"
-#: extension/ordchr.c:69
-msgid "ord: called with too many arguments"
-msgstr "ord: chiamata con troppi argomenti"
-
-#: extension/ordchr.c:75
-msgid "ord: called with no arguments"
-msgstr "ord: chiamata senza argomenti"
-
-#: extension/ordchr.c:77
+#: extension/ordchr.c:71
msgid "ord: called with inappropriate argument(s)"
msgstr "ord: chiamata con argomento/i non corretto/i"
-#: extension/ordchr.c:99
-msgid "chr: called with too many arguments"
-msgstr "chr: chiamata con troppi argomenti"
-
-#: extension/ordchr.c:109
-msgid "chr: called with no arguments"
-msgstr "chr: chiamata senza argomenti"
-
-#: extension/ordchr.c:111
+#: extension/ordchr.c:98
msgid "chr: called with inappropriate argument(s)"
msgstr "chr: chiamata con argomento/i non corretto/i"
-#: extension/readdir.c:271
+#: extension/readdir.c:273
#, c-format
msgid "dir_take_control_of: opendir/fdopendir failed: %s"
msgstr "dir_take_control_of: opendir/fdopendir non riuscita: %s"
-#: extension/readfile.c:113
-msgid "readfile: called with too many arguments"
-msgstr "readfile: chiamata con troppi argomenti"
-
-#: extension/readfile.c:137
-msgid "readfile: called with no arguments"
-msgstr "readfile: chiamata senza argomenti"
+#: extension/readfile.c:134
+msgid "readfile: called with wrong kind of argument"
+msgstr "readfile: chiamata con un tipo di argomento errato"
#: extension/revoutput.c:127
msgid "revoutput: could not initialize REVOUT variable"
msgstr "revoutput: non riesco a inizializzare la variabile REVOUT"
-#: extension/rwarray.c:113 extension/rwarray0.c:109
-msgid "writea: called with too many arguments"
-msgstr "writea: chiamata con troppi argomenti"
-
-#: extension/rwarray.c:120 extension/rwarray0.c:116
+#: extension/rwarray.c:118 extension/rwarray0.c:113
#, c-format
msgid "do_writea: argument 0 is not a string\n"
msgstr "do_writea: argomento 0 non è una stringa\n"
-#: extension/rwarray.c:126 extension/rwarray0.c:122
+#: extension/rwarray.c:124 extension/rwarray0.c:119
#, c-format
msgid "do_writea: argument 1 is not an array\n"
msgstr "do_writea: argomento 1 non-vettoriale\n"
-#: extension/rwarray.c:173 extension/rwarray0.c:169
+#: extension/rwarray.c:171 extension/rwarray0.c:166
#, c-format
msgid "write_array: could not flatten array\n"
msgstr "write_array: non sono riuscito a appiattire un vettore\n"
-#: extension/rwarray.c:187 extension/rwarray0.c:183
+#: extension/rwarray.c:185 extension/rwarray0.c:180
#, c-format
msgid "write_array: could not release flattened array\n"
msgstr "write_array: non sono riuscito a rilasciare un vettore appiattito\n"
-#: extension/rwarray.c:269 extension/rwarray0.c:265
-msgid "reada: called with too many arguments"
-msgstr "reada: chiamata con troppi argomenti"
+#: extension/rwarray.c:249
+#, c-format
+msgid "array value has unknown type %d"
+msgstr "valore di vettore di tipo sconosciuto %d"
-#: extension/rwarray.c:276 extension/rwarray0.c:272
+#: extension/rwarray.c:286 extension/rwarray0.c:266
#, c-format
msgid "do_reada: argument 0 is not a string\n"
msgstr "do_reada: argomento 0 non è una stringa\n"
-#: extension/rwarray.c:282 extension/rwarray0.c:278
+#: extension/rwarray.c:292 extension/rwarray0.c:272
#, c-format
msgid "do_reada: argument 1 is not an array\n"
msgstr "do_reada: argomento 1 non-vettoriale\n"
-#: extension/rwarray.c:326 extension/rwarray0.c:322
+#: extension/rwarray.c:336 extension/rwarray0.c:316
#, c-format
msgid "do_reada: clear_array failed\n"
msgstr "do_reada: clear_array non riuscita\n"
-#: extension/rwarray.c:363 extension/rwarray0.c:358
+#: extension/rwarray.c:373 extension/rwarray0.c:352
#, c-format
msgid "read_array: set_array_element failed\n"
msgstr "read_array: set_array_element non riuscita\n"
-#: extension/time.c:113
-msgid "gettimeofday: ignoring arguments"
-msgstr "gettimeofday: ignoro argomenti"
+#: extension/rwarray.c:480
+#, c-format
+msgid "treating recovered value with unknown type code %d as a string"
+msgstr ""
+"valore recuperato, con codice di tipo sconosciuto %d, trattato come stringa"
-#: extension/time.c:144
+#: extension/time.c:141
msgid "gettimeofday: not supported on this platform"
msgstr "gettimeofday: non supportato in questa architettura"
-#: extension/time.c:165
-msgid "sleep: called with too many arguments"
-msgstr "sleep: chiamata con troppi argomenti"
-
-#: extension/time.c:168
+#: extension/time.c:162
msgid "sleep: missing required numeric argument"
msgstr "sleep: manca necessario argomento numerico"
-#: extension/time.c:174
+#: extension/time.c:168
msgid "sleep: argument is negative"
msgstr "sleep: l'argomento è negativo"
-#: extension/time.c:208
+#: extension/time.c:202
msgid "sleep: not supported on this platform"
msgstr "sleep: non supportato in questa architettura"
-#: field.c:346
+#: field.c:290
+msgid "input record too large"
+msgstr "record in input troppo lungo"
+
+#: field.c:390
msgid "NF set to negative value"
msgstr "NF impostato a un valore negativo"
@@ -2529,7 +2455,7 @@ msgstr ""
"split: non consentito un secondo argomento che sia un sottovettore del "
"quarto argomento"
-#: field.c:1019
+#: field.c:1022
msgid "split: null string for third arg is a gawk extension"
msgstr "split: la stringa nulla come terzo arg. è un'estensione gawk"
@@ -2541,408 +2467,397 @@ msgstr "patsplit: secondo argomento non-vettoriale"
msgid "patsplit: second argument is not an array"
msgstr "patsplit: secondo argomento non-vettoriale"
-#: field.c:1070
+#: field.c:1073
msgid "patsplit: third argument must be non-null"
msgstr "patsplit: il terzo argomento non può essere nullo"
-#: field.c:1074
+#: field.c:1077
msgid "patsplit: cannot use the same array for second and fourth args"
msgstr ""
"patsplit: non si può usare un unico vettore come secondo e quarto argomento"
-#: field.c:1079
+#: field.c:1082
msgid "patsplit: cannot use a subarray of second arg for fourth arg"
msgstr ""
"patsplit: non consentito un quarto argomento che sia un sottovettore del "
"secondo argomento"
-#: field.c:1082
+#: field.c:1085
msgid "patsplit: cannot use a subarray of fourth arg for second arg"
msgstr ""
"patsplit: non consentito un secondo argomento che sia un sottovettore del "
"quarto argomento"
-#: field.c:1120
+#: field.c:1135
msgid "`FIELDWIDTHS' is a gawk extension"
msgstr "`FIELDWIDTHS' è un'estensione gawk"
-#: field.c:1184
+#: field.c:1205
#, c-format
-msgid "invalid FIELDWIDTHS value, near `%s'"
-msgstr "valore di FIELDWIDTHS non valido, vicino a `%s'"
+msgid "invalid FIELDWIDTHS value, for field %d, near `%s'"
+msgstr "valore di FIELDWIDTHS non valido, per il campo %d, vicino a `%s'"
-#: field.c:1257
+#: field.c:1278
msgid "null string for `FS' is a gawk extension"
msgstr "la stringa nulla usata come `FS' è un'estensione gawk"
-#: field.c:1261
+#: field.c:1282
msgid "old awk does not support regexps as value of `FS'"
msgstr "il vecchio awk non supporta espressioni come valori di `FS'"
-#: field.c:1384
+#: field.c:1417
msgid "`FPAT' is a gawk extension"
msgstr "`FPAT' è un'estensione gawk"
-#: gawkapi.c:146
+#: gawkapi.c:152
msgid "awk_value_to_node: received null retval"
msgstr "awk_value_to_node: ricevuto retval nullo"
-#: gawkapi.c:383
+#: gawkapi.c:474
msgid "node_to_awk_value: received null node"
msgstr "node_to_awk_value: ricevuto nodo nullo"
-#: gawkapi.c:386
+#: gawkapi.c:477
msgid "node_to_awk_value: received null val"
msgstr "node_to_awk_value: ricevuto valore nullo"
-#: gawkapi.c:808
+#: gawkapi.c:534 gawkapi.c:568 gawkapi.c:595 gawkapi.c:629
+#, c-format
+msgid ""
+"node_to_awk_value detected invalid flags combination `%s'; please file a bug "
+"report."
+msgstr ""
+"node_to_awk_value ha trovato la combinazione flag invalida `%s'; siete "
+"pregati di notificare questo bug."
+
+#: gawkapi.c:997
msgid "remove_element: received null array"
msgstr "remove_element: ricevuto vettore nullo"
-#: gawkapi.c:811
+#: gawkapi.c:1000
msgid "remove_element: received null subscript"
msgstr "remove_element: ricevuto indice nullo"
-#: gawkapi.c:948
-#, c-format
-msgid "api_flatten_array: could not convert index %d\n"
-msgstr "api_flatten_array: non sono riuscito a convertire l'indice %d\n"
-
-#: gawkapi.c:953
-#, c-format
-msgid "api_flatten_array: could not convert value %d\n"
-msgstr "api_flatten_array: non sono riuscito a convertire il valore %d\n"
-
-#: getopt.c:604 getopt.c:633
-#, c-format
-msgid "%s: option '%s' is ambiguous; possibilities:"
-msgstr "%s: opzione '%s' ambigua; possibilità:"
-
-#: getopt.c:679 getopt.c:683
-#, c-format
-msgid "%s: option '--%s' doesn't allow an argument\n"
-msgstr "%s: l'opzione '--%s' non ammette un argomento\n"
-
-#: getopt.c:692 getopt.c:697
-#, c-format
-msgid "%s: option '%c%s' doesn't allow an argument\n"
-msgstr "%s: l'opzione '%c%s' non ammette un argomento\n"
-
-#: getopt.c:740 getopt.c:759
-#, c-format
-msgid "%s: option '--%s' requires an argument\n"
-msgstr "%s: l'opzione '--%s' richiede un argomento\n"
-
-#: getopt.c:797 getopt.c:800
+#: gawkapi.c:1133
#, c-format
-msgid "%s: unrecognized option '--%s'\n"
-msgstr "%s: opzione sconosciuta '--%s'\n"
-
-#: getopt.c:808 getopt.c:811
-#, c-format
-msgid "%s: unrecognized option '%c%s'\n"
-msgstr "%s: opzione sconosciuta '%c%s'\n"
-
-#: getopt.c:860 getopt.c:863
-#, c-format
-msgid "%s: invalid option -- '%c'\n"
-msgstr "%s: opzione non valida -- '%c'\n"
+msgid "api_flatten_array_typed: could not convert index %d to %s\n"
+msgstr ""
+"api_flatten_array_typed: non sono riuscito a convertire l'indice %d a %s\n"
-#: getopt.c:916 getopt.c:933 getopt.c:1143 getopt.c:1161
+#: gawkapi.c:1138
#, c-format
-msgid "%s: option requires an argument -- '%c'\n"
-msgstr "%s: l'opzione richiede un argomento -- '%c'\n"
+msgid "api_flatten_array_typed: could not convert value %d to %s\n"
+msgstr ""
+"api_flatten_array_typed: non sono riuscito a convertire il valore %d a %s\n"
-#: getopt.c:989 getopt.c:1005
-#, c-format
-msgid "%s: option '-W %s' is ambiguous\n"
-msgstr "%s: l'opzione '-W %s' è ambigua\n"
+#: gawkapi.c:1249
+msgid "cannot find end of BEGINFILE rule"
+msgstr "non riesco a trovare la fine di una regola BEGINFILE"
-#: getopt.c:1029 getopt.c:1047
+#: gawkapi.c:1303
#, c-format
-msgid "%s: option '-W %s' doesn't allow an argument\n"
-msgstr "%s: l'opzione '-W %s' non ammette un argomento\n"
-
-#: getopt.c:1068 getopt.c:1086
-#, c-format
-msgid "%s: option '-W %s' requires an argument\n"
-msgstr "%s: l'opzione '-W %s' richiede un argomento\n"
+msgid "cannot open unrecognized file type `%s' for `%s'"
+msgstr "non riesco ad aprire file di tipo non riconosciuto `%s' per `%s'"
#: io.c:426
#, c-format
msgid "command line argument `%s' is a directory: skipped"
msgstr "l'argomento in riga comando `%s' è una directory: ignorata"
-#: io.c:429 io.c:547
+#: io.c:429 io.c:546
#, c-format
msgid "cannot open file `%s' for reading (%s)"
msgstr "non riesco ad aprire file `%s' in lettura (%s)"
-#: io.c:674
+#: io.c:675
#, c-format
msgid "close of fd %d (`%s') failed (%s)"
msgstr "chiusura di fd %d (`%s') non riuscita (%s)"
-#: io.c:752
+#: io.c:753
msgid "redirection not allowed in sandbox mode"
msgstr "ri-direzione non consentita in modo `sandbox'"
-#: io.c:786
+#: io.c:787
#, c-format
-msgid "expression in `%s' redirection only has numeric value"
-msgstr "espressione nella ri-direzione `%s' ha solo un valore numerico"
+msgid "expression in `%s' redirection is a number"
+msgstr "espressione nella ri-direzione `%s' è un numero"
-#: io.c:792
+#: io.c:791
#, c-format
msgid "expression for `%s' redirection has null string value"
msgstr "espressione nella ri-direzione `%s' ha per valore la stringa nulla"
-#: io.c:797
+#: io.c:796
#, c-format
-msgid "filename `%s' for `%s' redirection may be result of logical expression"
+msgid ""
+"filename `%.*s' for `%s' redirection may be result of logical expression"
msgstr ""
-"nome-file `%s' per la ri-direzione `%s' può essere il risultato di una "
+"nome-file `%.*s' per la ri-direzione `%s' può essere il risultato di una "
"espressione logica"
-#: io.c:845
+#: io.c:844
#, c-format
msgid "unnecessary mixing of `>' and `>>' for file `%.*s'"
msgstr "mistura non necessaria di `>' e `>>' per il file `%.*s'"
-#: io.c:902
+#: io.c:896 io.c:921
+#, c-format
+msgid "get_file cannot create pipe `%s' with fd %d"
+msgstr "get_file non riesce a creare una `pipe' `%s' con fd %d"
+
+#: io.c:911
#, c-format
msgid "can't open pipe `%s' for output (%s)"
msgstr "non riesco ad aprire `pipe' `%s' in scrittura (%s)"
-#: io.c:915
+#: io.c:926
#, c-format
msgid "can't open pipe `%s' for input (%s)"
msgstr "non riesco ad aprire `pipe' `%s' in lettura (%s)"
-#: io.c:946
+#: io.c:950
+#, c-format
+msgid ""
+"get_file socket creation not supported on this platform for `%s' with fd %d"
+msgstr ""
+"creazione di socket get_file non disponibile su questa piattaforma per `%s' "
+"con fd %d"
+
+#: io.c:961
#, c-format
msgid "can't open two way pipe `%s' for input/output (%s)"
msgstr ""
"non riesco ad aprire `pipe' bidirezionale `%s' in lettura/scrittura (%s)"
-#: io.c:1030
+#: io.c:1048
#, c-format
msgid "can't redirect from `%s' (%s)"
msgstr "non riesco a ri-dirigere da `%s' (%s)"
-#: io.c:1033
+#: io.c:1051
#, c-format
msgid "can't redirect to `%s' (%s)"
msgstr "non riesco a ri-dirigere a `%s' (%s)"
-#: io.c:1084
+#: io.c:1153
msgid ""
"reached system limit for open files: starting to multiplex file descriptors"
msgstr ""
"numero massimo consentito di file aperti raggiunto: comincio a riutilizzare "
"i descrittori di file"
-#: io.c:1100
+#: io.c:1169
#, c-format
msgid "close of `%s' failed (%s)."
msgstr "chiusura di `%s' non riuscita (%s)."
-#: io.c:1108
+#: io.c:1177
msgid "too many pipes or input files open"
msgstr "troppe `pipe' o file di input aperti"
-#: io.c:1130
+#: io.c:1203
msgid "close: second argument must be `to' or `from'"
msgstr "close: il secondo argomento deve essere `a' o `da'"
-#: io.c:1147
+#: io.c:1221
#, c-format
msgid "close: `%.*s' is not an open file, pipe or co-process"
msgstr "close: `%.*s' non è un file aperto, una `pipe' o un co-processo"
-#: io.c:1152
+#: io.c:1226
msgid "close of redirection that was never opened"
msgstr "chiusura di una ri-direzione mai aperta"
-#: io.c:1249
+#: io.c:1325
#, c-format
msgid "close: redirection `%s' not opened with `|&', second argument ignored"
msgstr "close: ri-direzione `%s' non aperta con `|&', ignoro secondo argomento"
-#: io.c:1266
+#: io.c:1342
#, c-format
msgid "failure status (%d) on pipe close of `%s' (%s)"
msgstr "errore ritornato (%d) dalla chiusura della `pipe' `%s' (%s)"
-#: io.c:1269
+#: io.c:1345
#, c-format
msgid "failure status (%d) on file close of `%s' (%s)"
msgstr "errore ritornato (%d) dalla chiusura del file `%s' (%s)"
-#: io.c:1289
+#: io.c:1365
#, c-format
msgid "no explicit close of socket `%s' provided"
msgstr "nessuna chiusura esplicita richiesta per `socket' `%s'"
-#: io.c:1292
+#: io.c:1368
#, c-format
msgid "no explicit close of co-process `%s' provided"
msgstr "nessuna chiusura esplicita richiesta per co-processo `%s'"
-#: io.c:1295
+#: io.c:1371
#, c-format
msgid "no explicit close of pipe `%s' provided"
msgstr "nessuna chiusura esplicita richiesta per `pipe' `%s'"
-#: io.c:1298
+#: io.c:1374
#, c-format
msgid "no explicit close of file `%s' provided"
msgstr "nessuna chiusura esplicita richiesta per file `%s'"
-#: io.c:1328 io.c:1387 main.c:645 main.c:687
+#: io.c:1411
+#, c-format
+msgid "fflush: cannot flush standard output: %s"
+msgstr "fflush: non riesco a terminare lo standard output: %s"
+
+#: io.c:1412
+#, c-format
+msgid "fflush: cannot flush standard error: %s"
+msgstr "fflush: non riesco a terminare lo standard error: %s"
+
+#: io.c:1417 io.c:1507 main.c:639 main.c:686
#, c-format
msgid "error writing standard output (%s)"
msgstr "errore scrivendo 'standard output' (%s)"
-#: io.c:1333 io.c:1393 main.c:647
+#: io.c:1418 io.c:1517 main.c:641
#, c-format
msgid "error writing standard error (%s)"
msgstr "errore scrivendo 'standard error' (%s)"
-#: io.c:1341
+#: io.c:1457
#, c-format
msgid "pipe flush of `%s' failed (%s)."
msgstr "scaricamento di `pipe' `%s' non riuscito (%s)."
-#: io.c:1344
+#: io.c:1460
#, c-format
msgid "co-process flush of pipe to `%s' failed (%s)."
msgstr "scaricamento da co-processo di `pipe' a `%s' non riuscito (%s)."
-#: io.c:1347
+#: io.c:1463
#, c-format
msgid "file flush of `%s' failed (%s)."
msgstr "scaricamento di file `%s' non riuscito (%s)."
-#: io.c:1465
+#: io.c:1589
#, c-format
msgid "local port %s invalid in `/inet'"
msgstr "porta locale %s invalida in `/inet'"
-#: io.c:1483
+#: io.c:1610
#, c-format
msgid "remote host and port information (%s, %s) invalid"
msgstr "host remoto e informazione di porta (%s, %s) invalidi"
-#: io.c:1711
+#: io.c:1853
msgid "TCP/IP communications are not supported"
msgstr "comunicazioni TCP/IP non supportate"
-#: io.c:1905
+#: io.c:2055
#, c-format
msgid "could not open `%s', mode `%s'"
msgstr "non riesco ad aprire `%s', modo `%s'"
-#: io.c:1961
+#: io.c:2111
#, c-format
msgid "close of master pty failed (%s)"
msgstr "close di `pty' principale non riuscita (%s)"
-#: io.c:1963 io.c:2141 io.c:2342
+#: io.c:2113 io.c:2291 io.c:2535
#, c-format
msgid "close of stdout in child failed (%s)"
msgstr "close di `stdout' nel processo-figlio non riuscita (%s)"
-#: io.c:1966
+#: io.c:2116
#, c-format
msgid "moving slave pty to stdout in child failed (dup: %s)"
msgstr ""
"trasferimento di `pty' secondaria a `stdout' nel processo-figlio non "
"riuscita (dup: %s)"
-#: io.c:1968 io.c:2146
+#: io.c:2118 io.c:2296
#, c-format
msgid "close of stdin in child failed (%s)"
msgstr "close di `stdin' nel processo-figlio non riuscita (%s)"
-#: io.c:1971
+#: io.c:2121
#, c-format
msgid "moving slave pty to stdin in child failed (dup: %s)"
msgstr ""
"trasferimento di 'pty' secondaria a 'stdin' nel processo-figlio non riuscito "
"(dup: %s)"
-#: io.c:1973
+#: io.c:2123
#, c-format
msgid "close of slave pty failed (%s)"
msgstr "close di 'pty' secondaria non riuscita (%s)"
-#: io.c:2076 io.c:2144 io.c:2313 io.c:2345
+#: io.c:2226 io.c:2294 io.c:2506 io.c:2538
#, c-format
msgid "moving pipe to stdout in child failed (dup: %s)"
msgstr ""
"passaggio di `pipe' a `stdout' nel processo-figlio non riuscito (dup: %s)"
-#: io.c:2083 io.c:2149
+#: io.c:2233 io.c:2299
#, c-format
msgid "moving pipe to stdin in child failed (dup: %s)"
msgstr ""
"passaggio di `pipe' a `stdin' nel processo-figlio non riuscito (dup: %s)"
-#: io.c:2109 io.c:2335
+#: io.c:2259 io.c:2528
msgid "restoring stdout in parent process failed\n"
msgstr "ripristino di `stdout' nel processo-padre non riuscito\n"
-#: io.c:2117
+#: io.c:2267
msgid "restoring stdin in parent process failed\n"
msgstr "ripristino di `stdin' nel processo-padre non riuscito\n"
-#: io.c:2152 io.c:2347 io.c:2362
+#: io.c:2302 io.c:2540 io.c:2555
#, c-format
msgid "close of pipe failed (%s)"
msgstr "close di `pipe' non riuscita (%s)"
-#: io.c:2211
+#: io.c:2361
msgid "`|&' not supported"
msgstr "`|&' non supportato"
-#: io.c:2298
+#: io.c:2491
#, c-format
msgid "cannot open pipe `%s' (%s)"
msgstr "non riesco ad aprire `pipe' `%s' (%s)"
-#: io.c:2356
+#: io.c:2549
#, c-format
msgid "cannot create child process for `%s' (fork: %s)"
msgstr "non riesco a creare processo-figlio per `%s' (fork: %s)"
-#: io.c:2493
+#: io.c:2687
msgid "getline: attempt to read from closed read end of two-way pipe"
msgstr ""
"getline: tentativo di elggere dal lato in scrittura, chiuso, di una `pipe' "
"bidirezionale"
-#: io.c:2795
+#: io.c:3006
msgid "register_input_parser: received NULL pointer"
msgstr "register_input_parser: ricevuto puntatore NULL"
-#: io.c:2823
+#: io.c:3034
#, c-format
msgid "input parser `%s' conflicts with previously installed input parser `%s'"
msgstr ""
"input parser `%s' in conflitto con l'input parser `%s' installato in "
"precedenza"
-#: io.c:2830
+#: io.c:3041
#, c-format
msgid "input parser `%s' failed to open `%s'"
msgstr "l'input parser `%s' non è riuscito ad aprire `%s'"
-#: io.c:2850
+#: io.c:3061
msgid "register_output_wrapper: received NULL pointer"
msgstr "register_output_wrapper: ricevuto puntatore NULL"
-#: io.c:2878
+#: io.c:3089
#, c-format
msgid ""
"output wrapper `%s' conflicts with previously installed output wrapper `%s'"
@@ -2950,16 +2865,16 @@ msgstr ""
"output wrapper `%s' in conflitto con l'output wrapper `%s' installato in "
"precedenza"
-#: io.c:2885
+#: io.c:3096
#, c-format
msgid "output wrapper `%s' failed to open `%s'"
msgstr "l'output wrapper `%s' non è riuscito ad aprire `%s'"
-#: io.c:2906
+#: io.c:3117
msgid "register_output_processor: received NULL pointer"
msgstr "register_output_processor: ricevuto puntatore NULL"
-#: io.c:2935
+#: io.c:3146
#, c-format
msgid ""
"two-way processor `%s' conflicts with previously installed two-way processor "
@@ -2968,198 +2883,202 @@ msgstr ""
"processore doppio `%s' in conflitto con il processore doppio installato in "
"precedenza `%s'"
-#: io.c:2944
+#: io.c:3155
#, c-format
msgid "two way processor `%s' failed to open `%s'"
msgstr "il processore doppio `%s' non è riuscito ad aprire `%s'"
-#: io.c:3069
+#: io.c:3280
#, c-format
msgid "data file `%s' is empty"
msgstr "file dati `%s' vuoto"
-#: io.c:3111 io.c:3119
+#: io.c:3322 io.c:3330
msgid "could not allocate more input memory"
msgstr "non riesco ad allocare ulteriore memoria per l'input"
-#: io.c:3697
+#: io.c:3950
msgid "multicharacter value of `RS' is a gawk extension"
msgstr "valore multicarattere per `RS' è un'estensione gawk"
-#: io.c:3844
+#: io.c:4104
msgid "IPv6 communication is not supported"
msgstr "comunicazioni IPv6 non supportate"
-#: main.c:334
+#: main.c:322
msgid "environment variable `POSIXLY_CORRECT' set: turning on `--posix'"
msgstr "variable d'ambiente `POSIXLY_CORRECT' impostata: attivo `--posix'"
-#: main.c:340
+#: main.c:328
msgid "`--posix' overrides `--traditional'"
msgstr "`--posix' annulla `--traditional'"
-#: main.c:351
+#: main.c:339
msgid "`--posix'/`--traditional' overrides `--non-decimal-data'"
msgstr "`--posix'/`--traditional' annulla `--non-decimal-data'"
-#: main.c:355
+#: main.c:343
#, c-format
msgid "running %s setuid root may be a security problem"
msgstr "eseguire %s con `setuid' root può essere un rischio per la sicurezza"
-#: main.c:359
+#: main.c:347
msgid "`--posix' overrides `--characters-as-bytes'"
msgstr "`--posix' annulla `--characters-as-bytes'"
-#: main.c:417
+#: main.c:405
#, c-format
msgid "can't set binary mode on stdin (%s)"
msgstr "non è possibile impostare modalità binaria su `stdin'(%s)"
-#: main.c:420
+#: main.c:408
#, c-format
msgid "can't set binary mode on stdout (%s)"
msgstr "non è possibile impostare modalità binaria su `stdout'(%s)"
-#: main.c:422
+#: main.c:410
#, c-format
msgid "can't set binary mode on stderr (%s)"
msgstr "non è possibile impostare modalità binaria su `stderr'(%s)"
-#: main.c:482
+#: main.c:470
msgid "no program text at all!"
msgstr "manca del tutto il testo del programma!"
-#: main.c:576
+#: main.c:563
#, c-format
msgid "Usage: %s [POSIX or GNU style options] -f progfile [--] file ...\n"
msgstr "Uso: %s [opzioni in stile POSIX o GNU] -f file-prog. [--] file ...\n"
-#: main.c:578
+#: main.c:565
#, c-format
msgid "Usage: %s [POSIX or GNU style options] [--] %cprogram%c file ...\n"
msgstr "Usage: %s [opzioni in stile POSIX o GNU] [--] %cprogramma%c file ...\n"
-#: main.c:583
+#: main.c:570
msgid "POSIX options:\t\tGNU long options: (standard)\n"
msgstr "Opzioni POSIX:\t\topzioni lunghe GNU: (standard)\n"
-#: main.c:584
+#: main.c:571
msgid "\t-f progfile\t\t--file=progfile\n"
msgstr "\t-f fileprog\t\t--file=file-prog.\n"
-#: main.c:585
+#: main.c:572
msgid "\t-F fs\t\t\t--field-separator=fs\n"
msgstr "\t-F fs\t\t\t--field-separator=fs\n"
-#: main.c:586
+#: main.c:573
msgid "\t-v var=val\t\t--assign=var=val\n"
msgstr "\t-v var=valore\t\t--assign=var=valore\n"
-#: main.c:587
+#: main.c:574
msgid "Short options:\t\tGNU long options: (extensions)\n"
msgstr "Opzioni brevi:\t\topzioni lunghe GNU: (estensioni)\n"
-#: main.c:588
+#: main.c:575
msgid "\t-b\t\t\t--characters-as-bytes\n"
msgstr "\t-b\t\t\t--characters-as-bytes\n"
-#: main.c:589
+#: main.c:576
msgid "\t-c\t\t\t--traditional\n"
msgstr "\t-c\t\t\t--traditional\n"
-#: main.c:590
+#: main.c:577
msgid "\t-C\t\t\t--copyright\n"
msgstr "\t-C\t\t\t--copyright\n"
-#: main.c:591
+#: main.c:578
msgid "\t-d[file]\t\t--dump-variables[=file]\n"
msgstr "\t-d[file]\t\t--dump-variables[=file]\n"
-#: main.c:592
+#: main.c:579
msgid "\t-D[file]\t\t--debug[=file]\n"
msgstr "\t-D[file]\t\t--debug[=file]\n"
-#: main.c:593
+#: main.c:580
msgid "\t-e 'program-text'\t--source='program-text'\n"
msgstr "\t-e 'testo-del-programma'\t--source='testo-del-programma'\n"
-#: main.c:594
+#: main.c:581
msgid "\t-E file\t\t\t--exec=file\n"
msgstr "\t-E file\t\t\t--exec=file\n"
-#: main.c:595
+#: main.c:582
msgid "\t-g\t\t\t--gen-pot\n"
msgstr "\t-g\t\t\t--gen-pot\n"
-#: main.c:596
+#: main.c:583
msgid "\t-h\t\t\t--help\n"
msgstr "\t-h\t\t\t--help\n"
-#: main.c:597
+#: main.c:584
msgid "\t-i includefile\t\t--include=includefile\n"
msgstr "\t-i include_file\t\t--include=include_file\n"
-#: main.c:598
+#: main.c:585
msgid "\t-l library\t\t--load=library\n"
msgstr "\t-l libreria\t\t--load=libreria\n"
#. TRANSLATORS: the "fatal" and "invalid" here are literal
#. values, they should not be translated. Thanks.
#.
-#: main.c:603
+#: main.c:590
msgid "\t-L[fatal|invalid]\t--lint[=fatal|invalid]\n"
msgstr "\t-L[fatal|invalid]\t--lint[=fatal|invalid]\n"
-#: main.c:604
+#: main.c:591
msgid "\t-M\t\t\t--bignum\n"
msgstr "\t-M\t\t\t--bignum\n"
-#: main.c:605
+#: main.c:592
msgid "\t-N\t\t\t--use-lc-numeric\n"
msgstr "\t-N\t\t\t--use-lc-numeric\n"
-#: main.c:606
+#: main.c:593
msgid "\t-n\t\t\t--non-decimal-data\n"
msgstr "\t-n\t\t\t--non-decimal-data\n"
-#: main.c:607
+#: main.c:594
msgid "\t-o[file]\t\t--pretty-print[=file]\n"
msgstr "\t-o[file]\t\t--pretty-print[=file]\n"
-#: main.c:608
+#: main.c:595
msgid "\t-O\t\t\t--optimize\n"
msgstr "\t-O\t\t\t--optimize\n"
-#: main.c:609
+#: main.c:596
msgid "\t-p[file]\t\t--profile[=file]\n"
msgstr "\t-p[file]\t\t--profile[=file]\n"
-#: main.c:610
+#: main.c:597
msgid "\t-P\t\t\t--posix\n"
msgstr "\t-P\t\t\t--posix\n"
-#: main.c:611
+#: main.c:598
msgid "\t-r\t\t\t--re-interval\n"
msgstr "\t-r\t\t\t--re-interval\n"
-#: main.c:612
+#: main.c:599
+msgid "\t-s\t\t\t--no-optimize\n"
+msgstr "\t-s\t\t\t--no-optimize\n"
+
+#: main.c:600
msgid "\t-S\t\t\t--sandbox\n"
msgstr "\t-S\t\t\t--sandbox\n"
-#: main.c:613
+#: main.c:601
msgid "\t-t\t\t\t--lint-old\n"
msgstr "\t-t\t\t\t--lint-old\n"
-#: main.c:614
+#: main.c:602
msgid "\t-V\t\t\t--version\n"
msgstr "\t-V\t\t\t--version\n"
-#: main.c:616
+#: main.c:604
msgid "\t-W nostalgia\t\t--nostalgia\n"
msgstr "\t-W nostalgia\t\t--nostalgia\n"
-#: main.c:619
+#: main.c:607
msgid "\t-Y\t\t--parsedebug\n"
msgstr "\t-Y\t\t--parsedebug\n"
@@ -3168,7 +3087,7 @@ msgstr "\t-Y\t\t--parsedebug\n"
#. for this application. Please add _another line_ with the
#. address for translation bugs.
#. no-wrap
-#: main.c:628
+#: main.c:616
msgid ""
"\n"
"To report bugs, see node `Bugs' in `gawk.info', which is\n"
@@ -3181,7 +3100,7 @@ msgstr ""
"Problemi di traduzione, segnalare ad: azc100@gmail.com.\n"
"\n"
-#: main.c:632
+#: main.c:620
msgid ""
"gawk is a pattern scanning and processing language.\n"
"By default it reads standard input and writes standard output.\n"
@@ -3191,7 +3110,7 @@ msgstr ""
"Senza parametri, legge da 'standard input' e scrive su 'standard output'.\n"
"\n"
-#: main.c:636
+#: main.c:624
msgid ""
"Examples:\n"
"\tgawk '{ sum += $1 }; END { print sum }' file\n"
@@ -3201,7 +3120,7 @@ msgstr ""
"\tgawk '{ sum += $1 }; END { print sum }' file\n"
"\tgawk -F: '{ print $1 }' /etc/passwd\n"
-#: main.c:661
+#: main.c:656
#, c-format
msgid ""
"Copyright (C) 1989, 1991-%d Free Software Foundation.\n"
@@ -3220,7 +3139,7 @@ msgstr ""
"Licenza, o (a tua scelta) a una qualsiasi versione successiva.\n"
"\n"
-#: main.c:669
+#: main.c:664
msgid ""
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
@@ -3234,7 +3153,7 @@ msgstr ""
"Vedi la 'GNU General Public License' per ulteriori dettagli.\n"
"\n"
-#: main.c:675
+#: main.c:670
msgid ""
"You should have received a copy of the GNU General Public License\n"
"along with this program. If not, see http://www.gnu.org/licenses/.\n"
@@ -3243,16 +3162,11 @@ msgstr ""
"assieme a questo programma; se non è così, vedi http://www.gnu.org/"
"licenses/.\n"
-#: main.c:712
+#: main.c:711
msgid "-Ft does not set FS to tab in POSIX awk"
msgstr "-Ft non imposta FS a `tab' nell'awk POSIX"
-#: main.c:999
-#, c-format
-msgid "unknown value for field spec: %d\n"
-msgstr "valore non noto per specifica campo: %d\n"
-
-#: main.c:1097
+#: main.c:1113
#, c-format
msgid ""
"%s: `%s' argument to `-v' not in `var=value' form\n"
@@ -3261,143 +3175,147 @@ msgstr ""
"%s: `%s' argomento di `-v' non in forma `var=valore'\n"
"\n"
-#: main.c:1123
+#: main.c:1139
#, c-format
msgid "`%s' is not a legal variable name"
msgstr "`%s' non è un nome di variabile ammesso"
-#: main.c:1126
+#: main.c:1142
#, c-format
msgid "`%s' is not a variable name, looking for file `%s=%s'"
msgstr "`%s' non è un nome di variabile, cerco il file `%s=%s'"
-#: main.c:1130
+#: main.c:1146
#, c-format
msgid "cannot use gawk builtin `%s' as variable name"
msgstr "nome funzione interna gawk `%s' non ammesso come nome variabile"
-#: main.c:1135
+#: main.c:1151
#, c-format
msgid "cannot use function `%s' as variable name"
msgstr "non è possibile usare nome di funzione `%s' come nome di variabile"
-#: main.c:1190
+#: main.c:1206
msgid "floating point exception"
msgstr "eccezione floating point"
-#: main.c:1197
+#: main.c:1213
msgid "fatal error: internal error"
msgstr "errore fatale: errore interno"
-#: main.c:1212
+#: main.c:1228
msgid "fatal error: internal error: segfault"
msgstr "errore fatale: errore interno: segfault"
-#: main.c:1224
+#: main.c:1240
msgid "fatal error: internal error: stack overflow"
msgstr "errore fatale: errore interno: stack overflow"
-#: main.c:1283
+#: main.c:1299
#, c-format
msgid "no pre-opened fd %d"
msgstr "manca `fd' pre-aperta %d"
-#: main.c:1290
+#: main.c:1306
#, c-format
msgid "could not pre-open /dev/null for fd %d"
msgstr "non riesco a pre-aprire /dev/null per `fd' %d"
-#: main.c:1504
+#: main.c:1520
msgid "empty argument to `-e/--source' ignored"
msgstr "argomento di `-e/--source' nullo, ignorato"
-#: main.c:1575
+#: main.c:1591
msgid "-M ignored: MPFR/GMP support not compiled in"
msgstr "-M ignorato: supporto per MPFR/GMP non generato"
-#: main.c:1596
+#: main.c:1616
#, c-format
msgid "%s: option `-W %s' unrecognized, ignored\n"
msgstr "%s: opzione `-W %s' non riconosciuta, ignorata\n"
-#: main.c:1649
+#: main.c:1669
#, c-format
msgid "%s: option requires an argument -- %c\n"
msgstr "%s: l'opzione richiede un argomento -- %c\n"
-#: mpfr.c:559
+#: mpfr.c:554
#, c-format
msgid "PREC value `%.*s' is invalid"
msgstr "valore PREC `%.*s' non valido"
-#: mpfr.c:617
+#: mpfr.c:612
#, c-format
msgid "RNDMODE value `%.*s' is invalid"
msgstr "valore di RNDMODE `%.*s' non valido"
-#: mpfr.c:714
+#: mpfr.c:709
#, c-format
msgid "%s: received non-numeric argument"
msgstr "%s: l'argomento ricevuto non è numerico"
-#: mpfr.c:824
-msgid "compl(%Rg): negative value will give strange results"
-msgstr "compl(%Rg): valore negativo, darà risultati strani"
+#: mpfr.c:818
+msgid "compl(%Rg): negative value is not allowed"
+msgstr "compl(%Rg): valore negativo non consentito"
-#: mpfr.c:828
+#: mpfr.c:823
msgid "comp(%Rg): fractional value will be truncated"
msgstr "comp(%Rg): valore decimale sarà troncato"
-#: mpfr.c:840
+#: mpfr.c:834
#, c-format
-msgid "cmpl(%Zd): negative values will give strange results"
-msgstr "cmpl(%Zd): valori negativi, daranno risultati strani"
+msgid "compl(%Zd): negative values is not allowed"
+msgstr "compl(%Zd): valori negativi non consentiti"
-#: mpfr.c:859
+#: mpfr.c:852
#, c-format
msgid "%s: received non-numeric argument #%d"
msgstr "%s: l'argomento ricevuto non è numerico #%d"
-#: mpfr.c:869
+#: mpfr.c:862
msgid "%s: argument #%d has invalid value %Rg, using 0"
msgstr "%s: argomento #%d con valore non valido %Rg, uso 0"
-#: mpfr.c:881
-msgid "%s: argument #%d negative value %Rg will give strange results"
-msgstr "%s: argomento #%d con valore negativo %Rg, darà risultati strani"
+#: mpfr.c:873
+msgid "%s: argument #%d negative value %Rg is not allowed"
+msgstr "%s: argomento #%d con valore negativo %Rg non consentito"
-#: mpfr.c:887
+#: mpfr.c:880
msgid "%s: argument #%d fractional value %Rg will be truncated"
msgstr "%s: argomento #%d, valore decimale sarà troncato"
-#: mpfr.c:902
+#: mpfr.c:894
#, c-format
-msgid "%s: argument #%d negative value %Zd will give strange results"
-msgstr "%s: argomento #%d con valore negativo %Zd, darà risultati strani"
+msgid "%s: argument #%d negative value %Zd is not allowed"
+msgstr "%s: argomento #%d con valore negativo %Zd non consentito"
#: msg.c:68
#, c-format
msgid "cmd. line:"
msgstr "riga com.:"
-#: node.c:434
+#: node.c:432
msgid "backslash at end of string"
msgstr "'\\' a fine stringa"
-#: node.c:513
+#: node.c:458
+msgid "could not make typed regex"
+msgstr "non sono riuscito a creare una `typed regex'"
+
+#: node.c:532
#, c-format
msgid "old awk does not support the `\\%c' escape sequence"
msgstr "il vecchio awk non supporta la sequenza di escape '\\%c'"
-#: node.c:564
+#: node.c:583
msgid "POSIX does not allow `\\x' escapes"
msgstr "POSIX non permette escape `\\x'"
-#: node.c:570
+#: node.c:589
msgid "no hex digits in `\\x' escape sequence"
msgstr "niente cifre esadecimali nella sequenza di escape `\\x'"
-#: node.c:592
+#: node.c:610
#, c-format
msgid ""
"hex escape \\x%.*s of %d characters probably not interpreted the way you "
@@ -3406,12 +3324,12 @@ msgstr ""
"sequenza di escape esadec.\\x%.*s di %d caratteri probabilmente non "
"interpretata nel modo previsto"
-#: node.c:607
+#: node.c:625
#, c-format
msgid "escape sequence `\\%c' treated as plain `%c'"
msgstr "sequenza di escape `\\%c' considerata come semplice `%c'"
-#: node.c:744
+#: node.c:762
msgid ""
"Invalid multibyte data detected. There may be a mismatch between your data "
"and your locale."
@@ -3430,16 +3348,16 @@ msgid "%s %s `%s': could not set close-on-exec: (fcntl F_SETFD: %s)"
msgstr ""
"%s %s `%s': non riesco a impostare 'close-on-exec': (fcntl F_SETFD: %s)"
-#: profile.c:94
+#: profile.c:97
#, c-format
msgid "could not open `%s' for writing: %s"
msgstr "non riesco ad aprire `%s' in scrittura: %s"
-#: profile.c:96
+#: profile.c:99
msgid "sending profile to standard error"
msgstr "mando profilo a 'standard error'"
-#: profile.c:216
+#: profile.c:250
#, c-format
msgid ""
"\t# %s rule(s)\n"
@@ -3448,7 +3366,7 @@ msgstr ""
"\t# %s regola(e)\n"
"\n"
-#: profile.c:221
+#: profile.c:258
#, c-format
msgid ""
"\t# Rule(s)\n"
@@ -3457,16 +3375,16 @@ msgstr ""
"\t# Regola(e)\n"
"\n"
-#: profile.c:295
+#: profile.c:343
#, c-format
msgid "internal error: %s with null vname"
msgstr "errore interno: %s con `vname' nullo"
-#: profile.c:561
+#: profile.c:612
msgid "internal error: builtin with null fname"
msgstr "errore interno: funzione interna con `fname' nullo"
-#: profile.c:1006
+#: profile.c:1125
#, c-format
msgid ""
"\t# Loaded extensions (-l and/or @load)\n"
@@ -3475,12 +3393,12 @@ msgstr ""
"\t# Estensioni caricate (-l e/o @load)\n"
"\n"
-#: profile.c:1029
+#: profile.c:1174
#, c-format
msgid "\t# gawk profile, created %s\n"
msgstr "\t# profilo gawk, creato %s\n"
-#: profile.c:1600
+#: profile.c:1735
#, c-format
msgid ""
"\n"
@@ -3489,86 +3407,178 @@ msgstr ""
"\n"
"\t# Funzioni, in ordine alfabetico\n"
-#: profile.c:1638
+#: profile.c:1791
#, c-format
msgid "redir2str: unknown redirection type %d"
msgstr "redir2str: tipo di ri-direzione non noto %d"
-#: re.c:610
+#: re.c:602
#, c-format
msgid "regexp component `%.*s' should probably be `[%.*s]'"
msgstr ""
"componente di espressione `%.*s' dovrebbe probabilmente essere `[%.*s]'"
-#: regcomp.c:143
+#: support/dfa.c:997
+msgid "unbalanced ["
+msgstr "[ non chiusa"
+
+#: support/dfa.c:1118
+msgid "invalid character class"
+msgstr "character class non valida"
+
+#: support/dfa.c:1244
+msgid "character class syntax is [[:space:]], not [:space:]"
+msgstr "sintassi character class è [[:spazio:]], non [:spazio:]"
+
+#: support/dfa.c:1311
+msgid "unfinished \\ escape"
+msgstr "sequenza escape \\ non completa"
+
+#: support/dfa.c:1472
+msgid "invalid content of \\{\\}"
+msgstr "contenuto di \\{\\} non valido"
+
+#: support/dfa.c:1475
+msgid "regular expression too big"
+msgstr "espressione regolare troppo complessa"
+
+#: support/dfa.c:1889
+msgid "unbalanced ("
+msgstr "( non chiusa"
+
+#: support/dfa.c:2007
+msgid "no syntax specified"
+msgstr "nessuna sintassi specificata"
+
+#: support/dfa.c:2015
+msgid "unbalanced )"
+msgstr ") non aperta"
+
+#: support/getopt.c:604 support/getopt.c:633
+#, c-format
+msgid "%s: option '%s' is ambiguous; possibilities:"
+msgstr "%s: opzione '%s' ambigua; possibilità:"
+
+#: support/getopt.c:679 support/getopt.c:683
+#, c-format
+msgid "%s: option '--%s' doesn't allow an argument\n"
+msgstr "%s: l'opzione '--%s' non ammette un argomento\n"
+
+#: support/getopt.c:692 support/getopt.c:697
+#, c-format
+msgid "%s: option '%c%s' doesn't allow an argument\n"
+msgstr "%s: l'opzione '%c%s' non ammette un argomento\n"
+
+#: support/getopt.c:740 support/getopt.c:759
+#, c-format
+msgid "%s: option '--%s' requires an argument\n"
+msgstr "%s: l'opzione '--%s' richiede un argomento\n"
+
+#: support/getopt.c:797 support/getopt.c:800
+#, c-format
+msgid "%s: unrecognized option '--%s'\n"
+msgstr "%s: opzione sconosciuta '--%s'\n"
+
+#: support/getopt.c:808 support/getopt.c:811
+#, c-format
+msgid "%s: unrecognized option '%c%s'\n"
+msgstr "%s: opzione sconosciuta '%c%s'\n"
+
+#: support/getopt.c:860 support/getopt.c:863
+#, c-format
+msgid "%s: invalid option -- '%c'\n"
+msgstr "%s: opzione non valida -- '%c'\n"
+
+#: support/getopt.c:916 support/getopt.c:933 support/getopt.c:1143
+#: support/getopt.c:1161
+#, c-format
+msgid "%s: option requires an argument -- '%c'\n"
+msgstr "%s: l'opzione richiede un argomento -- '%c'\n"
+
+#: support/getopt.c:989 support/getopt.c:1005
+#, c-format
+msgid "%s: option '-W %s' is ambiguous\n"
+msgstr "%s: l'opzione '-W %s' è ambigua\n"
+
+#: support/getopt.c:1029 support/getopt.c:1047
+#, c-format
+msgid "%s: option '-W %s' doesn't allow an argument\n"
+msgstr "%s: l'opzione '-W %s' non ammette un argomento\n"
+
+#: support/getopt.c:1068 support/getopt.c:1086
+#, c-format
+msgid "%s: option '-W %s' requires an argument\n"
+msgstr "%s: l'opzione '-W %s' richiede un argomento\n"
+
+#: support/regcomp.c:143
msgid "Success"
msgstr "Successo"
-#: regcomp.c:146
+#: support/regcomp.c:146
msgid "No match"
msgstr "Nessuna corrispondenza"
-#: regcomp.c:149
+#: support/regcomp.c:149
msgid "Invalid regular expression"
msgstr "Espressione regolare invalida"
-#: regcomp.c:152
+#: support/regcomp.c:152
msgid "Invalid collation character"
msgstr "Carattere di ordinamento non valido"
-#: regcomp.c:155
+#: support/regcomp.c:155
msgid "Invalid character class name"
msgstr "Nome di 'classe di caratteri' non valido"
-#: regcomp.c:158
+#: support/regcomp.c:158
msgid "Trailing backslash"
msgstr "'\\' finale"
-#: regcomp.c:161
+#: support/regcomp.c:161
msgid "Invalid back reference"
msgstr "Riferimento indietro non valido"
-#: regcomp.c:164
+#: support/regcomp.c:164
msgid "Unmatched [, [^, [:, [., or [="
msgstr "[, [^, [:, [. o [= non chiusa"
-#: regcomp.c:167
+#: support/regcomp.c:167
msgid "Unmatched ( or \\("
msgstr "( o \\( non chiusa"
-#: regcomp.c:170
+#: support/regcomp.c:170
msgid "Unmatched \\{"
msgstr "\\{ non chiusa"
-#: regcomp.c:173
+#: support/regcomp.c:173
msgid "Invalid content of \\{\\}"
msgstr "Contenuto di \\{\\} non valido"
-#: regcomp.c:176
+#: support/regcomp.c:176
msgid "Invalid range end"
msgstr "Fine di intervallo non valido"
-#: regcomp.c:179
+#: support/regcomp.c:179
msgid "Memory exhausted"
msgstr "Memoria esaurita"
-#: regcomp.c:182
+#: support/regcomp.c:182
msgid "Invalid preceding regular expression"
msgstr "Espressione regolare precedente invalida"
-#: regcomp.c:185
+#: support/regcomp.c:185
msgid "Premature end of regular expression"
msgstr "Fine di espressione regolare inaspettata"
-#: regcomp.c:188
+#: support/regcomp.c:188
msgid "Regular expression too big"
msgstr "Espressione regolare troppo complessa"
-#: regcomp.c:191
+#: support/regcomp.c:191
msgid "Unmatched ) or \\)"
msgstr ") o \\) non aperta"
-#: regcomp.c:701
+#: support/regcomp.c:701
msgid "No previous regular expression"
msgstr "Nessuna espressione regolare precedente"
@@ -3578,49 +3588,6 @@ msgid "function `%s': can't use function `%s' as a parameter name"
msgstr ""
"funzione `%s': non è possibile come nome parametro quello della funzione `%s'"
-#: symbol.c:816
+#: symbol.c:815
msgid "can not pop main context"
msgstr "non posso salire più in alto nello stack"
-
-#~ msgid "`isarray' is deprecated. Use `typeof' instead"
-#~ msgstr "`isarray' è una funzione deprecata. Usare `typeof' al suo posto"
-
-#~ msgid "intdiv: third argument is not an array"
-#~ msgstr "intdiv: il terzo argomento non è un vettore"
-
-#~ msgid "intdiv: received non-numeric first argument"
-#~ msgstr "intdiv: il primo argomento ricevuto non è numerico"
-
-#~ msgid "intdiv: received non-numeric second argument"
-#~ msgstr "intdiv: il secondo argomento ricevuto non è numerico"
-
-#~ msgid "intdiv: division by zero attempted"
-#~ msgstr "intdiv: tentativo di dividere per zero"
-
-#~ msgid "typeof: unknown argument type `%s'"
-#~ msgstr "typeof: tipo di argomento sconosciuto `%s'"
-
-#~ msgid "function `%s' defined to take no more than %d argument(s)"
-#~ msgstr "funzione `%s' definita per avere al massimo %d argomenti(o)"
-
-#~ msgid "function `%s': missing argument #%d"
-#~ msgstr "funzione `%s': manca argomento #%d"
-
-#~ msgid "cannot find end of BEGINFILE rule"
-#~ msgstr "non riesco a trovare la fine di una regola BEGINFILE"
-
-#~ msgid "cannot open unrecognized file type `%s' for `%s'"
-#~ msgstr "non riesco ad aprire file di tipo non riconosciuto `%s' per `%s'"
-
-#~ msgid "get_file cannot create pipe `%s' with fd %d"
-#~ msgstr "get_file non riesce a creare una `pipe' `%s' con fd %d"
-
-#~ msgid ""
-#~ "get_file socket creation not supported on this platform for `%s' with fd "
-#~ "%d"
-#~ msgstr ""
-#~ "creazione di socket get_file non disponibile su questa piattaforma per `"
-#~ "%s' con fd %d"
-
-#~ msgid "\t-s\t\t\t--no-optimize\n"
-#~ msgstr "\t-s\t\t\t--no-optimize\n"
diff --git a/po/pt_BR.gmo b/po/pt_BR.gmo
new file mode 100644
index 00000000..0524a5d4
--- /dev/null
+++ b/po/pt_BR.gmo
Binary files differ
diff --git a/posix/ChangeLog b/posix/ChangeLog
index c5ce0340..ec37e1fb 100644
--- a/posix/ChangeLog
+++ b/posix/ChangeLog
@@ -1,3 +1,12 @@
+2017-02-20 Corinna Vinschen <vinschen@redhat.com>
+
+ * gawkmisc.c (cygwin_premain0, cygwin_premain2): Remove.
+ No longer needed.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
+
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.4: Release tar ball made.
diff --git a/posix/gawkmisc.c b/posix/gawkmisc.c
index d422bd0f..ecf5aff9 100644
--- a/posix/gawkmisc.c
+++ b/posix/gawkmisc.c
@@ -1,5 +1,5 @@
/* gawkmisc.c --- miscellaneous gawk routines that are OS specific.
-
+
Copyright (C) 1986, 1988, 1989, 1991 - 1998, 2001 - 2004, 2011
the Free Software Foundation, Inc.
@@ -40,7 +40,7 @@ char *
gawk_name(const char *filespec)
{
char *p;
-
+
/* "path/name" -> "name" */
p = strrchr(filespec, '/');
return (p == NULL ? (char *) filespec : p + 1);
@@ -272,7 +272,7 @@ os_isatty(int fd)
{
return isatty(fd);
}
-
+
/* files_are_same --- return true if files are identical */
int
@@ -289,22 +289,3 @@ void
init_sockets(void)
{
}
-
-#ifdef __CYGWIN__
-void
-cygwin_premain0(int argc, char **argv, struct per_process *myself)
-{
- static struct __cygwin_perfile pf[] = {
- { "", O_RDONLY | O_TEXT },
- /*{ "", O_WRONLY | O_BINARY },*/
- { NULL, 0 }
- };
- cygwin_internal(CW_PERFILE, pf);
-}
-
-void
-cygwin_premain2(int argc, char **argv, struct per_process *myself)
-{
- setmode(fileno (stdin), O_TEXT);
-}
-#endif
diff --git a/profile.c b/profile.c
index 39c4f03d..6cdb5baa 100644
--- a/profile.c
+++ b/profile.c
@@ -2,22 +2,22 @@
* profile.c - gawk bytecode pretty-printer with counts
*/
-/*
+/*
* Copyright (C) 1999-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -26,17 +26,20 @@
#include "awk.h"
static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags);
+static INSTRUCTION *end_line(INSTRUCTION *ip);
static void pp_parenthesize(NODE *n);
static void parenthesize(int type, NODE *left, NODE *right);
static char *pp_list(int nargs, const char *paren, const char *delim);
static char *pp_group3(const char *s1, const char *s2, const char *s3);
static char *pp_concat(int nargs);
+static char *pp_string_or_typed_regex(const char *in_str, size_t len, int delim, bool typed_regex);
+static char *pp_typed_regex(const char *in_str, size_t len, int delim);
static bool is_binary(int type);
static bool is_scalar(int type);
static int prec_level(int type);
static void pp_push(int type, char *s, int flag);
static NODE *pp_pop(void);
-static void pp_free(NODE *n);
+static void print_comment(INSTRUCTION *pc, long in);
const char *redir2str(int redirtype);
#define pp_str vname
@@ -46,8 +49,8 @@ const char *redir2str(int redirtype);
#define DONT_FREE 1
#define CAN_FREE 2
-static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN;
-static RETSIGTYPE just_dump(int signum);
+static void dump_and_exit(int signum) ATTRIBUTE_NORETURN;
+static void just_dump(int signum);
/* pretty printing related functions and variables */
@@ -123,10 +126,12 @@ indent(long count)
{
int i;
- if (count == 0)
- fprintf(prof_fp, "\t");
- else
- fprintf(prof_fp, "%6ld ", count);
+ if (do_profile) {
+ if (count == 0)
+ fprintf(prof_fp, "\t");
+ else
+ fprintf(prof_fp, "%6ld ", count);
+ }
assert(indent_level >= 0);
for (i = 0; i < indent_level; i++)
@@ -196,52 +201,94 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags)
NODE *t1;
char *str;
NODE *t2;
- INSTRUCTION *ip;
+ INSTRUCTION *ip1;
+ INSTRUCTION *ip2;
NODE *m;
char *tmp;
int rule;
static int rule_count[MAXRULE];
+ static bool skip_comment = false;
for (pc = startp; pc != endp; pc = pc->nexti) {
if (pc->source_line > 0)
sourceline = pc->source_line;
+ /* skip leading EOL comment as it has already been printed */
+ if (pc->opcode == Op_comment
+ && pc->memory->comment_type == EOL_COMMENT
+ && skip_comment) {
+ skip_comment = false;
+ continue;
+ }
+ skip_comment = false;
+
switch (pc->opcode) {
case Op_rule:
+ /*
+ * Rules are three instructions long.
+ * See append_rule in awkgram.y.
+ * The first has the Rule Op Code, nexti etc.
+ * The second, (pc + 1) has firsti and lasti:
+ * the first/last ACTION instructions for this rule.
+ * The third has first_line and last_line:
+ * the first and last source line numbers.
+ */
source = pc->source_file;
rule = pc->in_rule;
if (rule != Rule) {
- if (! rule_count[rule]++)
- fprintf(prof_fp, _("\t# %s rule(s)\n\n"), ruletab[rule]);
- fprintf(prof_fp, "\t%s {\n", ruletab[rule]);
- ip = (pc + 1)->firsti;
+ /* Allow for pre-non-rule-block comment */
+ if (pc->nexti != (pc +1)->firsti
+ && pc->nexti->opcode == Op_comment
+ && pc->nexti->memory->comment_type == FULL_COMMENT)
+ print_comment(pc->nexti, -1);
+ ip1 = (pc + 1)->firsti;
+ ip2 = (pc + 1)->lasti;
+
+ if (do_profile) {
+ if (! rule_count[rule]++)
+ fprintf(prof_fp, _("\t# %s rule(s)\n\n"), ruletab[rule]);
+ indent(0);
+ }
+ fprintf(prof_fp, "%s {", ruletab[rule]);
+ end_line(pc);
+ skip_comment = true;
} else {
- if (! rule_count[rule]++)
+ if (do_profile && ! rule_count[rule]++)
fprintf(prof_fp, _("\t# Rule(s)\n\n"));
- ip = pc->nexti;
- indent(ip->exec_count);
- if (ip != (pc + 1)->firsti) { /* non-empty pattern */
- pprint(ip->nexti, (pc + 1)->firsti, NO_PPRINT_FLAGS);
- t1 = pp_pop();
- fprintf(prof_fp, "%s {", t1->pp_str);
- pp_free(t1);
- ip = (pc + 1)->firsti;
-
- if (do_profile && ip->exec_count > 0)
- fprintf(prof_fp, " # %ld", ip->exec_count);
-
- fprintf(prof_fp, "\n");
+ ip1 = pc->nexti;
+ indent(ip1->exec_count);
+ if (ip1 != (pc + 1)->firsti) { /* non-empty pattern */
+ pprint(ip1->nexti, (pc + 1)->firsti, NO_PPRINT_FLAGS);
+ /* Allow for case where the "pattern" is just a comment */
+ if (ip1->nexti->nexti->nexti != (pc +1)->firsti
+ || ip1->nexti->opcode != Op_comment) {
+ t1 = pp_pop();
+ fprintf(prof_fp, "%s {", t1->pp_str);
+ pp_free(t1);
+ } else
+ fprintf(prof_fp, "{");
+ ip1 = (pc + 1)->firsti;
+ ip2 = (pc + 1)->lasti;
+
+ if (do_profile && ip1->exec_count > 0)
+ fprintf(prof_fp, " # %ld", ip1->exec_count);
+
+ end_line(ip1);
+ skip_comment = true;
} else {
fprintf(prof_fp, "{\n");
- ip = (pc + 1)->firsti;
+ ip1 = (pc + 1)->firsti;
+ ip2 = (pc + 1)->lasti;
}
- ip = ip->nexti;
+ ip1 = ip1->nexti;
}
indent_in();
- pprint(ip, (pc + 1)->lasti, NO_PPRINT_FLAGS);
+ pprint(ip1, ip2, NO_PPRINT_FLAGS);
indent_out();
- fprintf(prof_fp, "\t}\n\n");
+ if (do_profile)
+ indent(0);
+ fprintf(prof_fp, "}\n\n");
pc = (pc + 1)->lasti;
break;
@@ -280,6 +327,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags)
case Op_push_array:
case Op_push:
case Op_push_arg:
+ case Op_push_arg_untyped:
m = pc->memory;
switch (m->type) {
case Node_param_list:
@@ -300,7 +348,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags)
cant_happen();
}
- switch (pc->opcode) {
+ switch (pc->opcode) {
case Op_store_var:
t2 = pp_pop(); /* l.h.s. */
t1 = pp_pop(); /* r.h.s. */
@@ -326,7 +374,7 @@ cleanup:
pp_free(t2);
pp_free(t1);
if ((flags & IN_FOR_HEADER) == 0)
- fprintf(prof_fp, "\n");
+ pc = end_line(pc);
break;
default:
@@ -343,7 +391,7 @@ cleanup:
efree(tmp);
pp_free(t1);
pp_push(pc->opcode, str, CAN_FREE);
- break;
+ break;
case Op_and:
case Op_or:
@@ -379,6 +427,13 @@ cleanup:
pp_push(pc->opcode, str, CAN_FREE);
break;
+ case Op_parens:
+ t1 = pp_pop();
+ str = pp_group3("(", t1->pp_str, ")");
+ pp_free(t1);
+ pp_push(pc->opcode, str, CAN_FREE);
+ break;
+
case Op_plus:
case Op_minus:
case Op_times:
@@ -416,10 +471,13 @@ cleanup:
case Op_field_spec:
case Op_field_spec_lhs:
case Op_unary_minus:
+ case Op_unary_plus:
case Op_not:
t1 = pp_pop();
if (is_binary(t1->type)
- || (((OPCODE) t1->type) == pc->opcode && pc->opcode == Op_unary_minus))
+ || (((OPCODE) t1->type) == pc->opcode
+ && (pc->opcode == Op_unary_minus
+ || pc->opcode == Op_unary_plus)))
pp_parenthesize(t1);
/* optypes table (eval.c) includes space after ! */
@@ -452,8 +510,8 @@ cleanup:
pp_free(t2);
pp_free(t1);
if ((flags & IN_FOR_HEADER) == 0)
- fprintf(prof_fp, "\n");
- break;
+ pc = end_line(pc);
+ break;
case Op_concat:
str = pp_concat(pc->expr_count);
@@ -470,10 +528,10 @@ cleanup:
sub = pp_list(pc->expr_count, NULL, pc->expr_count > 1 ? "][" : ", ");
fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
efree(sub);
- } else
+ } else
fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
if ((flags & IN_FOR_HEADER) == 0)
- fprintf(prof_fp, "\n");
+ pc = end_line(pc);
pp_free(t1);
}
break;
@@ -482,7 +540,7 @@ cleanup:
/* Efficency hack not in effect because of exec_count instruction */
cant_happen();
break;
-
+
case Op_in_array:
{
char *array, *sub;
@@ -495,7 +553,7 @@ cleanup:
} else {
t2 = pp_pop();
if (prec_level(t2->type) < prec_level(Op_in_array)) {
- pp_parenthesize(t2);
+ pp_parenthesize(t2);
}
sub = t2->pp_str;
str = pp_group3(sub, op2str(Op_in_array), array);
@@ -511,7 +569,7 @@ cleanup:
case Op_field_assign:
case Op_subscript_assign:
case Op_arrayfor_init:
- case Op_arrayfor_incr:
+ case Op_arrayfor_incr:
case Op_arrayfor_final:
case Op_newfile:
case Op_get_record:
@@ -572,7 +630,7 @@ cleanup:
else {
tmp = pp_list(pc->expr_count, " ", ", ");
tmp[strlen(tmp) - 1] = '\0'; /* remove trailing space */
- }
+ }
if (pc->redir_type != 0) {
t1 = pp_pop();
@@ -585,18 +643,23 @@ cleanup:
fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
efree(tmp);
if ((flags & IN_FOR_HEADER) == 0)
- fprintf(prof_fp, "\n");
+ pc = end_line(pc);
break;
case Op_push_re:
- if (pc->memory->type != Node_regex)
+ if (pc->memory->type != Node_regex && (pc->memory->flags & REGEX) == 0)
break;
- /* else
+ /* else
fall through */
case Op_match_rec:
{
- NODE *re = pc->memory->re_exp;
- str = pp_string(re->stptr, re->stlen, '/');
+ if (pc->memory->type == Node_regex) {
+ NODE *re = pc->memory->re_exp;
+ str = pp_string(re->stptr, re->stlen, '/');
+ } else {
+ assert((pc->memory->flags & REGEX) != 0);
+ str = pp_typed_regex(pc->memory->stptr, pc->memory->stlen, '/');
+ }
pp_push(pc->opcode, str, CAN_FREE);
}
break;
@@ -618,6 +681,10 @@ cleanup:
txt = t2->pp_str;
str = pp_group3(txt, op2str(pc->opcode), restr);
pp_free(t2);
+ } else if (m->type == Node_val && (m->flags & REGEX) != 0) {
+ restr = pp_typed_regex(m->stptr, m->stlen, '/');
+ str = pp_group3(txt, op2str(pc->opcode), restr);
+ efree(restr);
} else {
NODE *re = m->re_exp;
restr = pp_string(re->stptr, re->stlen, '/');
@@ -666,7 +733,7 @@ cleanup:
if (pc->opcode == Op_indirect_func_call)
pre = "@";
else
- pre = "";
+ pre = "";
pcount = (pc + 1)->expr_count;
if (pcount > 0) {
tmp = pp_list(pcount, "()", ", ");
@@ -686,7 +753,8 @@ cleanup:
case Op_K_break:
case Op_K_nextfile:
case Op_K_next:
- fprintf(prof_fp, "%s\n", op2str(pc->opcode));
+ fprintf(prof_fp, "%s", op2str(pc->opcode));
+ pc = end_line(pc);
break;
case Op_K_return:
@@ -694,8 +762,10 @@ cleanup:
t1 = pp_pop();
if (is_binary(t1->type))
pp_parenthesize(t1);
- if (pc->source_line > 0) /* don't print implicit 'return' at end of function */
- fprintf(prof_fp, "%s %s\n", op2str(pc->opcode), t1->pp_str);
+ if (pc->source_line > 0) { /* don't print implicit 'return' at end of function */
+ fprintf(prof_fp, "%s %s", op2str(pc->opcode), t1->pp_str);
+ pc = end_line(pc);
+ }
pp_free(t1);
break;
@@ -703,73 +773,78 @@ cleanup:
t1 = pp_pop();
fprintf(prof_fp, "%s", t1->pp_str);
if ((flags & IN_FOR_HEADER) == 0)
- fprintf(prof_fp, "\n");
+ pc = end_line(pc);
pp_free(t1);
break;
case Op_line_range:
- ip = pc + 1;
- pprint(pc->nexti, ip->condpair_left, NO_PPRINT_FLAGS);
- pprint(ip->condpair_left->nexti, ip->condpair_right, NO_PPRINT_FLAGS);
+ ip1 = pc + 1;
+ pprint(pc->nexti, ip1->condpair_left, NO_PPRINT_FLAGS);
+ pprint(ip1->condpair_left->nexti, ip1->condpair_right, NO_PPRINT_FLAGS);
t2 = pp_pop();
t1 = pp_pop();
str = pp_group3(t1->pp_str, ", ", t2->pp_str);
pp_free(t1);
pp_free(t2);
pp_push(Op_line_range, str, CAN_FREE);
- pc = ip->condpair_right;
+ pc = ip1->condpair_right;
break;
case Op_K_while:
- ip = pc + 1;
- indent(ip->while_body->exec_count);
+ ip1 = pc + 1;
+ indent(ip1->while_body->exec_count);
fprintf(prof_fp, "%s (", op2str(pc->opcode));
- pprint(pc->nexti, ip->while_body, NO_PPRINT_FLAGS);
+ pprint(pc->nexti, ip1->while_body, NO_PPRINT_FLAGS);
t1 = pp_pop();
- fprintf(prof_fp, "%s) {\n", t1->pp_str);
+ fprintf(prof_fp, "%s) {", t1->pp_str);
pp_free(t1);
+ ip1->while_body = end_line(ip1->while_body);
indent_in();
- pprint(ip->while_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
+ pprint(ip1->while_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
indent_out();
indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
- pc = pc->target_break;
+ fprintf(prof_fp, "}");
+ pc = end_line(pc->target_break);
break;
case Op_K_do:
- ip = pc + 1;
+ ip1 = pc + 1;
indent(pc->nexti->exec_count);
- fprintf(prof_fp, "%s {\n", op2str(pc->opcode));
+ fprintf(prof_fp, "%s {", op2str(pc->opcode));
+ end_line(pc->nexti);
+ skip_comment = true;
indent_in();
- pprint(pc->nexti->nexti, ip->doloop_cond, NO_PPRINT_FLAGS);
+ pprint(pc->nexti->nexti, ip1->doloop_cond, NO_PPRINT_FLAGS);
indent_out();
- pprint(ip->doloop_cond, pc->target_break, NO_PPRINT_FLAGS);
+ pprint(ip1->doloop_cond, pc->target_break, NO_PPRINT_FLAGS);
indent(SPACEOVER);
t1 = pp_pop();
- fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str);
+ fprintf(prof_fp, "} %s (%s)", op2str(Op_K_while), t1->pp_str);
pp_free(t1);
+ end_line(pc->target_break);
+ skip_comment = true;
pc = pc->target_break;
break;
case Op_K_for:
- ip = pc + 1;
- indent(ip->forloop_body->exec_count);
- fprintf(prof_fp, "%s (", op2str(pc->opcode));
+ ip1 = pc + 1;
+ indent(ip1->forloop_body->exec_count);
+ fprintf(prof_fp, "%s (", op2str(pc->opcode));
/* If empty for looop header, print it a little more nicely. */
if ( pc->nexti->opcode == Op_no_op
- && ip->forloop_cond == pc->nexti
+ && ip1->forloop_cond == pc->nexti
&& pc->target_continue->opcode == Op_jmp) {
fprintf(prof_fp, ";;");
} else {
- pprint(pc->nexti, ip->forloop_cond, IN_FOR_HEADER);
+ pprint(pc->nexti, ip1->forloop_cond, IN_FOR_HEADER);
fprintf(prof_fp, "; ");
- if (ip->forloop_cond->opcode == Op_no_op &&
- ip->forloop_cond->nexti == ip->forloop_body)
+ if (ip1->forloop_cond->opcode == Op_no_op &&
+ ip1->forloop_cond->nexti == ip1->forloop_body)
fprintf(prof_fp, "; ");
else {
- pprint(ip->forloop_cond, ip->forloop_body, IN_FOR_HEADER);
+ pprint(ip1->forloop_cond, ip1->forloop_body, IN_FOR_HEADER);
t1 = pp_pop();
fprintf(prof_fp, "%s; ", t1->pp_str);
pp_free(t1);
@@ -777,12 +852,16 @@ cleanup:
pprint(pc->target_continue, pc->target_break, IN_FOR_HEADER);
}
- fprintf(prof_fp, ") {\n");
+ fprintf(prof_fp, ") {");
+ end_line(ip1->forloop_body);
+ skip_comment = true;
indent_in();
- pprint(ip->forloop_body->nexti, pc->target_continue, NO_PPRINT_FLAGS);
+ pprint(ip1->forloop_body->nexti, pc->target_continue, NO_PPRINT_FLAGS);
indent_out();
indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
+ fprintf(prof_fp, "}");
+ end_line(pc->target_break);
+ skip_comment = true;
pc = pc->target_break;
break;
@@ -791,35 +870,39 @@ cleanup:
char *array;
const char *item;
- ip = pc + 1;
+ ip1 = pc + 1;
t1 = pp_pop();
array = t1->pp_str;
- m = ip->forloop_cond->array_var;
+ m = ip1->forloop_cond->array_var;
if (m->type == Node_param_list)
item = func_params[m->param_cnt].param;
else
item = m->vname;
- indent(ip->forloop_body->exec_count);
- fprintf(prof_fp, "%s (%s%s%s) {\n", op2str(Op_K_arrayfor),
+ indent(ip1->forloop_body->exec_count);
+ fprintf(prof_fp, "%s (%s%s%s) {", op2str(Op_K_arrayfor),
item, op2str(Op_in_array), array);
+ end_line(ip1->forloop_body);
+ skip_comment = true;
indent_in();
pp_free(t1);
- pprint(ip->forloop_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
+ pprint(ip1->forloop_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
indent_out();
indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
+ fprintf(prof_fp, "}");
+ end_line(pc->target_break);
+ skip_comment = true;
pc = pc->target_break;
}
break;
case Op_K_switch:
- ip = pc + 1;
+ ip1 = pc + 1;
fprintf(prof_fp, "%s (", op2str(pc->opcode));
- pprint(pc->nexti, ip->switch_start, NO_PPRINT_FLAGS);
+ pprint(pc->nexti, ip1->switch_start, NO_PPRINT_FLAGS);
t1 = pp_pop();
fprintf(prof_fp, "%s) {\n", t1->pp_str);
pp_free(t1);
- pprint(ip->switch_start, ip->switch_end, NO_PPRINT_FLAGS);
+ pprint(ip1->switch_start, ip1->switch_end, NO_PPRINT_FLAGS);
indent(SPACEOVER);
fprintf(prof_fp, "}\n");
pc = pc->target_break;
@@ -830,10 +913,13 @@ cleanup:
indent(pc->stmt_start->exec_count);
if (pc->opcode == Op_K_case) {
t1 = pp_pop();
- fprintf(prof_fp, "%s %s:\n", op2str(pc->opcode), t1->pp_str);
+ fprintf(prof_fp, "%s %s:", op2str(pc->opcode), t1->pp_str);
+ pc = end_line(pc);
pp_free(t1);
- } else
- fprintf(prof_fp, "%s:\n", op2str(pc->opcode));
+ } else {
+ fprintf(prof_fp, "%s:", op2str(pc->opcode));
+ pc = end_line(pc);
+ }
indent_in();
pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, NO_PPRINT_FLAGS);
indent_out();
@@ -846,17 +932,22 @@ cleanup:
fprintf(prof_fp, "%s) {", t1->pp_str);
pp_free(t1);
- ip = pc->branch_if;
- if (ip->exec_count > 0)
- fprintf(prof_fp, " # %ld", ip->exec_count);
- fprintf(prof_fp, "\n");
+ ip1 = pc->branch_if;
+ if (ip1->exec_count > 0)
+ fprintf(prof_fp, " # %ld", ip1->exec_count);
+ ip1 = end_line(ip1);
indent_in();
- pprint(ip->nexti, pc->branch_else, NO_PPRINT_FLAGS);
+ pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS);
indent_out();
pc = pc->branch_else;
if (pc->nexti->opcode == Op_no_op) { /* no following else */
indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
+ fprintf(prof_fp, "}");
+ if (pc->nexti->nexti->opcode != Op_comment
+ || pc->nexti->nexti->memory->comment_type == FULL_COMMENT)
+ fprintf(prof_fp, "\n");
+ /* else
+ It will be printed at the top. */
}
/*
* See next case; turn off the flag so that the
@@ -885,13 +976,22 @@ cleanup:
&& pc->branch_end == pc->nexti->nexti->branch_else->lasti) {
pprint(pc->nexti, pc->branch_end, IN_ELSE_IF);
} else {
- fprintf(prof_fp, "{\n");
+ fprintf(prof_fp, "{");
+ end_line(pc);
+ skip_comment = true;
indent_in();
pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
indent_out();
indent(SPACEOVER);
- fprintf(prof_fp, "}\n");
+ fprintf(prof_fp, "}");
+ end_line(pc->branch_end);
+ skip_comment = true;
}
+ /*
+ * Don't do end_line() here, we get multiple blank lines after
+ * the final else in a chain of else-ifs since they all point
+ * to the same branch_end.
+ */
pc = pc->branch_end;
break;
@@ -901,13 +1001,13 @@ cleanup:
size_t len;
pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS);
- ip = pc->branch_if;
- pprint(ip->nexti, pc->branch_else, NO_PPRINT_FLAGS);
- ip = pc->branch_else->nexti;
+ ip1 = pc->branch_if;
+ pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS);
+ ip1 = pc->branch_else->nexti;
- pc = ip->nexti;
+ pc = ip1->nexti;
assert(pc->opcode == Op_cond_exp);
- pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
+ pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
f = pp_pop();
t = pp_pop();
@@ -915,7 +1015,7 @@ cleanup:
len = f->pp_len + t->pp_len + cond->pp_len + 12;
emalloc(str, char *, len, "pprint");
- sprintf(str, "(%s ? %s : %s)", cond->pp_str, t->pp_str, f->pp_str);
+ sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str);
pp_free(cond);
pp_free(t);
@@ -923,13 +1023,20 @@ cleanup:
pp_push(Op_cond_exp, str, CAN_FREE);
pc = pc->branch_end;
}
- break;
+ break;
case Op_exec_count:
if (flags == NO_PPRINT_FLAGS)
indent(pc->exec_count);
break;
+ case Op_comment:
+ print_comment(pc, 0);
+ break;
+
+ case Op_list:
+ break;
+
default:
cant_happen();
}
@@ -939,6 +1046,25 @@ cleanup:
}
}
+/* end_line --- end pretty print line with new line or on-line comment */
+
+INSTRUCTION *
+end_line(INSTRUCTION *ip)
+{
+ INSTRUCTION *ret = ip;
+
+ if (ip->nexti->opcode == Op_comment
+ && ip->nexti->memory->comment_type == EOL_COMMENT) {
+ fprintf(prof_fp, "\t");
+ print_comment(ip->nexti, -1);
+ ret = ip->nexti;
+ }
+ else
+ fprintf(prof_fp, "\n");
+
+ return ret;
+}
+
/* pp_string_fp --- printy print a string to the fp */
/*
@@ -970,7 +1096,7 @@ pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
/* just_dump --- dump the profile and function stack and keep going */
-static RETSIGTYPE
+static void
just_dump(int signum)
{
extern INSTRUCTION *code_block;
@@ -984,7 +1110,7 @@ just_dump(int signum)
/* dump_and_exit --- dump the profile, the function stack, and exit */
-static RETSIGTYPE
+static void
dump_and_exit(int signum)
{
just_dump(signum);
@@ -1012,6 +1138,31 @@ print_lib_list(FILE *prof_fp)
fprintf(prof_fp, "\n");
}
+/* print_comment --- print comment text with proper indentation */
+
+static void
+print_comment(INSTRUCTION* pc, long in)
+{
+ char *text;
+ size_t count;
+ bool after_newline = false;
+
+ count = pc->memory->stlen;
+ text = pc->memory->stptr;
+
+ if (in >= 0)
+ indent(in); /* is this correct? Where should comments go? */
+ for (; count > 0; count--, text++) {
+ if (after_newline) {
+ indent(in);
+ after_newline = false;
+ }
+ putc(*text, prof_fp);
+ if (*text == '\n')
+ after_newline = true;
+ }
+}
+
/* dump_prog --- dump the program */
/*
@@ -1026,7 +1177,8 @@ dump_prog(INSTRUCTION *code)
(void) time(& now);
/* \n on purpose, with \n in ctime() output */
- fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
+ if (do_profile)
+ fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
print_lib_list(prof_fp);
pprint(code, NULL, NO_PPRINT_FLAGS);
}
@@ -1066,6 +1218,7 @@ prec_level(int type)
return 13;
case Op_unary_minus:
+ case Op_unary_plus:
case Op_not:
return 12;
@@ -1152,6 +1305,7 @@ is_scalar(int type)
case Op_postincrement:
case Op_postdecrement:
case Op_unary_minus:
+ case Op_unary_plus:
case Op_not:
return true;
@@ -1216,6 +1370,9 @@ pp_parenthesize(NODE *sp)
char *p = sp->pp_str;
size_t len = sp->pp_len;
+ if (p[0] == '(') // already parenthesized
+ return;
+
emalloc(p, char *, len + 3, "pp_parenthesize");
*p = '(';
memcpy(p + 1, sp->pp_str, len);
@@ -1228,26 +1385,6 @@ pp_parenthesize(NODE *sp)
sp->flags |= CAN_FREE;
}
-/* div_on_left_mul_on_right --- have / or % on left and * on right */
-
-static bool
-div_on_left_mul_on_right(int o1, int o2)
-{
- OPCODE op1 = (OPCODE) o1;
- OPCODE op2 = (OPCODE) o2;
-
- switch (op1) {
- case Op_quotient:
- case Op_quotient_i:
- case Op_mod:
- case Op_mod_i:
- return (op2 == Op_times || op2 == Op_times_i);
-
- default:
- return false;
- }
-}
-
/* parenthesize --- parenthesize two nodes relative to parent node type */
static void
@@ -1257,19 +1394,33 @@ parenthesize(int type, NODE *left, NODE *right)
int lprec = prec_level(left->type);
int prec = prec_level(type);
- if (lprec < prec
- || (lprec == prec && div_on_left_mul_on_right(left->type, type)))
+ if (lprec < prec)
pp_parenthesize(left);
- if (rprec < prec
- || (rprec == prec && div_on_left_mul_on_right(type, right->type)))
+ if (rprec < prec)
pp_parenthesize(right);
}
-/* pp_string --- pretty format a string or regex constant */
+/* pp_string --- pretty format a string or regular regex constant */
char *
pp_string(const char *in_str, size_t len, int delim)
{
+ return pp_string_or_typed_regex(in_str, len, delim, false);
+}
+
+/* pp_typed_regex --- pretty format a hard regex constant */
+
+static char *
+pp_typed_regex(const char *in_str, size_t len, int delim)
+{
+ return pp_string_or_typed_regex(in_str, len, delim, true);
+}
+
+/* pp_string_or_typed_regex --- pretty format a string, regex, or typed regex constant */
+
+char *
+pp_string_or_typed_regex(const char *in_str, size_t len, int delim, bool typed_regex)
+{
static char str_escapes[] = "\a\b\f\n\r\t\v\\";
static char str_printables[] = "abfnrtv\\";
static char re_escapes[] = "\a\b\f\n\r\t\v";
@@ -1301,11 +1452,15 @@ pp_string(const char *in_str, size_t len, int delim)
osiz *= 2; \
} ofre -= (l)
- osiz = len + 3 + 2; /* initial size; 3 for delim + terminating null */
+ /* initial size; 3 for delim + terminating null, 1 for @ */
+ osiz = len + 3 + 1 + (typed_regex == true);
emalloc(obuf, char *, osiz, "pp_string");
obufout = obuf;
ofre = osiz - 1;
+ if (typed_regex)
+ *obufout++ = '@';
+
*obufout++ = delim;
for (; len > 0; len--, str++) {
chksize(2); /* make space for 2 chars */
@@ -1313,10 +1468,9 @@ pp_string(const char *in_str, size_t len, int delim)
*obufout++ = '\\';
*obufout++ = delim;
} else if (*str == '\0') {
- chksize(4);
-
*obufout++ = '\\';
*obufout++ = '0';
+ chksize(2); /* need 2 more chars for this case */
*obufout++ = '0';
*obufout++ = '0';
} else if ((cp = strchr(escapes, *str)) != NULL) {
@@ -1326,7 +1480,7 @@ pp_string(const char *in_str, size_t len, int delim)
/* NB: Deliberate use of lower-case versions. */
} else if (isascii(*str) && isprint(*str)) {
*obufout++ = *str;
- ofre += 1;
+ ofre += 1; /* used 1 less than expected */
} else {
size_t len;
@@ -1350,45 +1504,12 @@ pp_string(const char *in_str, size_t len, int delim)
char *
pp_number(NODE *n)
{
-#define PP_PRECISION 6
char *str;
-#ifdef HAVE_MPFR
- size_t count;
-
- if (is_mpg_float(n)) {
- count = mpfr_get_prec(n->mpg_numbr) / 3; /* ~ 3.22 binary digits per decimal digit */
- emalloc(str, char *, count, "pp_number");
- /*
- * 3/2015: Format string used to be "%0.*R*g". That padded
- * with leading zeros. But it doesn't do that for regular
- * numbers in the non-MPFR case.
- */
- mpfr_sprintf(str, "%.*R*g", PP_PRECISION, ROUND_MODE, n->mpg_numbr);
- } else if (is_mpg_integer(n)) {
- count = mpz_sizeinbase(n->mpg_i, 10) + 2; /* +1 for sign, +1 for NUL at end */
- emalloc(str, char *, count, "pp_number");
- mpfr_sprintf(str, "%Zd", n->mpg_i);
- } else
-#endif
- {
- /* Use format_val() to get integral values printed as integers */
- NODE *s;
-
- getnode(s);
- *s = *n;
- s->flags &= ~STRCUR;
-
- s = r_format_val("%.6g", 0, s);
-
- s->stptr[s->stlen] = '\0';
- str = s->stptr;
-
- freenode(s);
- }
-
+ assert((n->flags & NUMCONSTSTR) != 0);
+ emalloc(str, char *, n->stlen + 1, "pp_number");
+ strcpy(str, n->stptr);
return str;
-#undef PP_PRECISION
}
/* pp_node --- pretty format a node */
@@ -1441,7 +1562,7 @@ pp_list(int nargs, const char *paren, const char *delim)
emalloc(str, char *, len + 1, "pp_list");
s = str;
if (paren != NULL)
- *s++ = paren[0];
+ *s++ = paren[0];
if (nargs > 0) {
r = pp_args[nargs];
memcpy(s, r->pp_str, r->pp_len);
@@ -1461,7 +1582,7 @@ pp_list(int nargs, const char *paren, const char *delim)
if (paren != NULL)
*s++ = paren[1];
*s = '\0';
- return str;
+ return str;
}
/* is_unary_minus --- return true if string starts with unary minus */
@@ -1510,22 +1631,27 @@ pp_concat(int nargs)
for (i = 1; i < nargs; i++) {
r = pp_args[i];
- pl_l = prec_level(pp_args[i]->type);
- pl_r = prec_level(pp_args[i+1]->type);
-
- if (i >= 2 && is_unary_minus(r->pp_str)) {
- *s++ = '(';
- memcpy(s, r->pp_str, r->pp_len);
- s += r->pp_len;
- *s++ = ')';
- } else if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) {
- memcpy(s, r->pp_str, r->pp_len);
- s += r->pp_len;
- } else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) {
- *s++ = '(';
- memcpy(s, r->pp_str, r->pp_len);
- s += r->pp_len;
- *s++ = ')';
+ if (r->pp_str[0] != '(') {
+ pl_l = prec_level(pp_args[i]->type);
+ pl_r = prec_level(pp_args[i+1]->type);
+
+ if (i >= 2 && is_unary_minus(r->pp_str)) {
+ *s++ = '(';
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ *s++ = ')';
+ } else if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) {
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ } else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) {
+ *s++ = '(';
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ *s++ = ')';
+ } else {
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ }
} else {
memcpy(s, r->pp_str, r->pp_len);
s += r->pp_len;
@@ -1536,11 +1662,14 @@ pp_concat(int nargs)
*s++ = ' ';
}
}
-
+
pl_l = prec_level(pp_args[nargs-1]->type);
pl_r = prec_level(pp_args[nargs]->type);
r = pp_args[nargs];
- if (is_unary_minus(r->pp_str) || ((pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)))) {
+ if (r->pp_str[0] == '(') {
+ memcpy(s, r->pp_str, r->pp_len);
+ s += r->pp_len;
+ } else if (is_unary_minus(r->pp_str) || ((pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)))) {
*s++ = '(';
memcpy(s, r->pp_str, r->pp_len);
s += r->pp_len;
@@ -1552,7 +1681,7 @@ pp_concat(int nargs)
pp_free(r);
*s = '\0';
- return str;
+ return str;
}
/* pp_group3 --- string together up to 3 strings */
@@ -1566,7 +1695,7 @@ pp_group3(const char *s1, const char *s2, const char *s3)
len1 = strlen(s1);
len2 = strlen(s2);
len3 = strlen(s3);
- l = len1 + len2 + len3 + 2;
+ l = len1 + len2 + len3 + 1;
emalloc(str, char *, l, "pp_group3");
s = str;
if (len1 > 0) {
@@ -1594,14 +1723,24 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
static bool first = true;
NODE *func;
int pcount;
+ INSTRUCTION *fp;
if (first) {
first = false;
- fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
+ if (do_profile)
+ fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
}
+ fp = pc->nexti->nexti;
func = pc->func_body;
fprintf(prof_fp, "\n");
+
+ /* print any function comment */
+ if (fp->opcode == Op_comment && fp->source_line == 0) {
+ print_comment(fp, -1); /* -1 ==> don't indent */
+ fp = fp->nexti;
+ }
+
indent(pc->nexti->exec_count);
fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname);
pcount = func->param_cnt;
@@ -1611,11 +1750,21 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
if (j < pcount - 1)
fprintf(prof_fp, ", ");
}
- fprintf(prof_fp, ")\n\t{\n");
+ if (fp->opcode == Op_comment
+ && fp->memory->comment_type == EOL_COMMENT) {
+ fprintf(prof_fp, ")");
+ fp = end_line(fp);
+ } else
+ fprintf(prof_fp, ")\n");
+ if (do_profile)
+ indent(0);
+ fprintf(prof_fp, "{\n");
indent_in();
- pprint(pc->nexti->nexti, NULL, NO_PPRINT_FLAGS); /* function body */
+ pprint(fp, NULL, NO_PPRINT_FLAGS); /* function body */
indent_out();
- fprintf(prof_fp, "\t}\n");
+ if (do_profile)
+ indent(0);
+ fprintf(prof_fp, "}\n");
return 0;
}
diff --git a/protos.h b/protos.h
index 7bef8b84..5693a43b 100644
--- a/protos.h
+++ b/protos.h
@@ -2,22 +2,22 @@
* protos.h -- function prototypes for when the headers don't have them.
*/
-/*
+/*
* Copyright (C) 1991 - 2002, 2011 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -64,7 +64,7 @@ extern size_t strftime(char *, size_t, const char *, const struct tm *);
extern time_t time(time_t *);
extern FILE *fdopen(int, const char *);
-extern int fprintf(FILE *, const char *, ...);
+extern int fprintf(FILE *, const char *, ...);
#if ! defined(__GNU_LIBRARY__)
extern size_t fwrite(const aptr_t, size_t, size_t, FILE *);
#endif
@@ -124,7 +124,7 @@ extern unsigned long int strtoul(const char *, char **endptr, int base);
#ifndef HAVE_TZSET
extern void tzset();
#endif
-
+
#ifndef HAVE_MKTIME
extern time_t mktime(struct tm *tp);
#endif
diff --git a/re.c b/re.c
index 878c884e..cf369a97 100644
--- a/re.c
+++ b/re.c
@@ -2,22 +2,22 @@
* re.c - compile regular expressions.
*/
-/*
+/*
* Copyright (C) 1991-2016 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -25,10 +25,14 @@
#include "awk.h"
+#include "localeinfo.h"
+
static reg_syntax_t syn;
static void check_bracket_exp(char *s, size_t len);
const char *regexflags2str(int flags);
+static struct localeinfo localeinfo;
+
/* make_regexp --- generate compiled regular expressions */
Regexp *
@@ -45,9 +49,8 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
int c, c2;
static bool first = true;
static bool no_dfa = false;
- bool has_anchor = false;
- reg_syntax_t dfa_syn;
int i;
+ static struct dfa* dfaregs[2] = { NULL, NULL };
/*
* The number of bytes in the current multibyte character.
@@ -59,9 +62,9 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
memset(&mbs, 0, sizeof(mbstate_t)); /* Initialize. */
if (first) {
- first = false;
/* for debugging and testing */
no_dfa = (getenv("GAWK_NO_DFA") != NULL);
+ /* don't set first to false here, we do it below */
}
/* always check */
@@ -72,13 +75,13 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
/*
* Build a copy of the string (in buf) with the
* escaped characters translated, and generate the regex
- * from that.
+ * from that.
*/
if (buf == NULL) {
- emalloc(buf, char *, len + 2, "make_regexp");
+ emalloc(buf, char *, len + 1, "make_regexp");
buflen = len;
} else if (len > buflen) {
- erealloc(buf, char *, len + 2, "make_regexp");
+ erealloc(buf, char *, len + 1, "make_regexp");
buflen = len;
}
dest = buf;
@@ -156,9 +159,6 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
} /* switch */
} else {
c = *src;
- if (c == '^' || c == '$')
- has_anchor = true;
-
*dest++ = *src++; /* not '\\' */
}
if (gawk_mb_cur_max > 1 && is_multibyte)
@@ -168,9 +168,7 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
*dest = '\0';
len = dest - buf;
- emalloc(rp, Regexp *, sizeof(*rp), "make_regexp");
- memset((char *) rp, 0, sizeof(*rp));
- rp->dfareg = NULL;
+ ezalloc(rp, Regexp *, sizeof(*rp), "make_regexp");
rp->pat.allocated = 0; /* regex will allocate the buffer */
emalloc(rp->pat.fastmap, char *, 256, "make_regexp");
@@ -203,10 +201,14 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
syn &= ~RE_ICASE;
}
- dfa_syn = syn;
- /* FIXME: dfa doesn't pay attention RE_ICASE */
- if (ignorecase)
- dfa_syn |= RE_ICASE;
+ /* initialize dfas to hold syntax */
+ if (first) {
+ first = false;
+ dfaregs[0] = dfaalloc();
+ dfaregs[1] = dfaalloc();
+ dfasyntax(dfaregs[0], & localeinfo, syn, DFA_ANCHOR);
+ dfasyntax(dfaregs[1], & localeinfo, syn | RE_ICASE, DFA_ANCHOR);
+ }
re_set_syntax(syn);
@@ -223,13 +225,11 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
/* gack. this must be done *after* re_compile_pattern */
rp->pat.newline_anchor = false; /* don't get \n in middle of string */
if (dfa && ! no_dfa) {
- rp->dfa = true;
rp->dfareg = dfaalloc();
- dfasyntax(rp->dfareg, dfa_syn, ignorecase, '\n');
+ dfacopysyntax(rp->dfareg, dfaregs[ignorecase]);
dfacomp(buf, len, rp->dfareg, true);
} else
- rp->dfa = false;
- rp->has_anchor = has_anchor;
+ rp->dfareg = NULL;
/* Additional flags that help with RS as regexp. */
for (i = 0; i < len; i++) {
@@ -245,7 +245,7 @@ make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal)
break;
}
}
-
+
return rp;
}
@@ -278,26 +278,24 @@ research(Regexp *rp, char *str, int start,
* starts in the middle of a string, so don't bother trying it
* in that case.
*/
- if (rp->dfa && ! no_bol && start == 0) {
- char save;
- size_t count = 0;
+ if (rp->dfareg != NULL && ! no_bol && start == 0) {
struct dfa *superset = dfasuperset(rp->dfareg);
- /*
- * dfa likes to stick a '\n' right after the matched
- * text. So we just save and restore the character.
- */
- save = str[start+len];
if (superset)
ret = dfaexec(superset, str+start, str+start+len,
true, NULL, NULL);
- if (ret)
+
+ if (ret && (! need_start
+ || (! superset && dfaisfast(rp->dfareg))))
ret = dfaexec(rp->dfareg, str+start, str+start+len,
- true, &count, &try_backref);
- str[start+len] = save;
+ true, NULL, &try_backref);
}
if (ret) {
- if (need_start || rp->dfa == false || try_backref) {
+ if ( rp->dfareg == NULL
+ || start != 0
+ || no_bol
+ || need_start
+ || try_backref) {
/*
* Passing NULL as last arg speeds up search for cases
* where we don't need the start/end info.
@@ -319,14 +317,14 @@ void
refree(Regexp *rp)
{
if (rp == NULL)
- return;
+ return;
rp->pat.translate = NULL;
regfree(& rp->pat);
if (rp->regs.start)
free(rp->regs.start);
if (rp->regs.end)
free(rp->regs.end);
- if (rp->dfa) {
+ if (rp->dfareg != NULL) {
dfafree(rp->dfareg);
free(rp->dfareg);
}
@@ -349,48 +347,49 @@ re_update(NODE *t)
{
NODE *t1;
- if ((t->re_flags & CASE) == IGNORECASE) {
- /* regex was compiled with settings matching IGNORECASE */
- if ((t->re_flags & CONSTANT) != 0) {
- /* it's a constant, so just return it as is */
- assert(t->type == Node_regex);
- return t->re_reg;
- }
- t1 = t->re_exp;
- if (t->re_text != NULL) {
- /* if contents haven't changed, just return it */
- if (cmp_nodes(t->re_text, t1) == 0)
- return t->re_reg;
- /* things changed, fall through to recompile */
- unref(t->re_text);
- }
- /* get fresh copy of the text of the regexp */
- t->re_text = dupnode(t1);
+ if (t->type == Node_val && (t->flags & REGEX) != 0)
+ return t->typed_re->re_reg[IGNORECASE];
+
+ if ((t->re_flags & CONSTANT) != 0) {
+ /* it's a constant, so just return it as is */
+ assert(t->type == Node_regex);
+ return t->re_reg[IGNORECASE];
}
- /* was compiled with different IGNORECASE or text changed */
+ t1 = t->re_exp;
+ if (t->re_text != NULL) {
+ /* if contents haven't changed, just return it */
+ if (cmp_nodes(t->re_text, t1, true) == 0)
+ return t->re_reg[IGNORECASE];
+ /* things changed, fall through to recompile */
+ unref(t->re_text);
+ }
+ /* get fresh copy of the text of the regexp */
+ t->re_text = dupnode(t1);
+
+ /* text changed */
/* free old */
- if (t->re_reg != NULL)
- refree(t->re_reg);
+ if (t->re_reg[0] != NULL)
+ refree(t->re_reg[0]);
+ if (t->re_reg[1] != NULL)
+ refree(t->re_reg[1]);
if (t->re_cnt > 0)
t->re_cnt++;
if (t->re_cnt > 10)
t->re_cnt = 0;
- if (t->re_text == NULL || (t->re_flags & CASE) != IGNORECASE) {
+ if (t->re_text == NULL) {
/* reset regexp text if needed */
t1 = t->re_exp;
unref(t->re_text);
t->re_text = dupnode(t1);
}
/* compile it */
- t->re_reg = make_regexp(t->re_text->stptr, t->re_text->stlen,
- IGNORECASE, t->re_cnt, true);
-
- /* clear case flag */
- t->re_flags &= ~CASE;
- /* set current value of case flag */
- t->re_flags |= IGNORECASE;
- return t->re_reg;
+ t->re_reg[0] = make_regexp(t->re_text->stptr, t->re_text->stlen,
+ false, t->re_cnt, true);
+ t->re_reg[1] = make_regexp(t->re_text->stptr, t->re_text->stlen,
+ true, t->re_cnt, true);
+
+ return t->re_reg[IGNORECASE];
}
/* resetup --- choose what kind of regexps we match */
@@ -398,6 +397,9 @@ re_update(NODE *t)
void
resetup()
{
+ // init localeinfo for dfa
+ init_localeinfo(& localeinfo);
+
/*
* Syntax bits: _that_ is yet another mind trip. Recreational drugs
* are helpful for recovering from the experience.
@@ -421,25 +423,14 @@ resetup()
syn |= RE_INTERVALS | RE_INVALID_INTERVAL_ORD | RE_NO_BK_BRACES;
(void) re_set_syntax(syn);
-
- dfa_init();
}
-/* avoid_dfa --- return true if we should not use the DFA matcher */
+/* using_utf8 --- are we using utf8 */
-int
-avoid_dfa(NODE *re, char *str, size_t len)
+bool
+using_utf8(void)
{
- char *end;
-
- if (! re->re_reg->has_anchor)
- return false;
-
- for (end = str + len; str < end; str++)
- if (*str == '\n')
- return true;
-
- return false;
+ return localeinfo.using_utf8;
}
/* reisstring --- return true if the RE match is a simple string match */
diff --git a/replace.c b/replace.c
index 6d345f52..db7f0893 100644
--- a/replace.c
+++ b/replace.c
@@ -2,22 +2,22 @@
* replace.c -- Get replacement versions of functions.
*/
-/*
+/*
* Copyright (C) 1989, 1991-2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -84,7 +84,7 @@
#ifndef HAVE_TZSET
#include "missing_d/tzset.c"
#endif /* HAVE_TZSET */
-
+
#ifndef HAVE_MKTIME
/* mktime.c defines main() if DEBUG is set */
#undef DEBUG
diff --git a/str_array.c b/str_array.c
index 460e2f1d..0f75b300 100644
--- a/str_array.c
+++ b/str_array.c
@@ -2,23 +2,23 @@
* str_array.c - routines for associative arrays of string indices.
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2013, 2016,
* the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -70,6 +70,25 @@ afunc_t str_array_func[] = {
(afunc_t) 0,
};
+static NODE **env_remove(NODE *symbol, NODE *subs);
+static NODE **env_store(NODE *symbol, NODE *subs);
+static NODE **env_clear(NODE *symbol, NODE *subs);
+
+/* special case for ENVIRON */
+afunc_t env_array_func[] = {
+ str_array_init,
+ (afunc_t) 0,
+ null_length,
+ str_lookup,
+ str_exists,
+ env_clear,
+ env_remove,
+ str_list,
+ str_copy,
+ str_dump,
+ env_store,
+};
+
static inline NODE **str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1);
static void grow_table(NODE *symbol);
@@ -107,7 +126,7 @@ str_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
* isn't there. Returns a pointer ala get_lhs to where its value is stored.
*
* SYMBOL is the address of the node (or other pointer) being dereferenced.
- * SUBS is a number or string used as the subscript.
+ * SUBS is a number or string used as the subscript.
*/
static NODE **
@@ -145,11 +164,9 @@ str_lookup(NODE *symbol, NODE *subs)
* "Array indices are always strings."
* "Array indices are always strings."
* ....
- * If subs is a STRNUM, copy it; don't clear the MAYBE_NUM
- * flag on it since other variables could be using the same
- * reference-counted value.
*/
- if (subs->stfmt != -1 || (subs->flags & MAYBE_NUM) != 0) {
+ if (subs->stfmt != STFMT_UNUSED) {
+ /* The string was generated using CONVFMT. */
NODE *tmp;
/*
@@ -175,13 +192,11 @@ str_lookup(NODE *symbol, NODE *subs)
}
subs = tmp;
} else {
- /* string value already "frozen" */
+ /* string value already "frozen" */
subs = dupnode(subs);
}
- assert((subs->flags & MAYBE_NUM) == 0);
-
getbucket(b);
b->ahnext = symbol->buckets[hash1];
symbol->buckets[hash1] = b;
@@ -226,7 +241,7 @@ str_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
r = b->ahvalue;
if (r->type == Node_var_array) {
assoc_clear(r); /* recursively clear all sub-arrays */
- efree(r->vname);
+ efree(r->vname);
freenode(r);
} else
unref(r);
@@ -303,15 +318,14 @@ str_copy(NODE *symbol, NODE *newsymb)
BUCKET **old, **new, **pnew;
BUCKET *chain, *newchain;
unsigned long cursize, i;
-
+
assert(symbol->table_size > 0);
/* find the current hash size */
cursize = symbol->array_size;
/* allocate new table */
- emalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "str_copy");
- memset(new, '\0', cursize * sizeof(BUCKET *));
+ ezalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "str_copy");
old = symbol->buckets;
@@ -349,7 +363,7 @@ str_copy(NODE *symbol, NODE *newsymb)
newchain->ahnext = NULL;
pnew = & newchain->ahnext;
}
- }
+ }
newsymb->table_size = symbol->table_size;
newsymb->buckets = new;
@@ -383,9 +397,9 @@ str_list(NODE *symbol, NODE *t)
if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
num_elems = 1;
list_size = elem_size * num_elems;
-
+
emalloc(list, NODE **, list_size * sizeof(NODE *), "str_list");
-
+
/* populate it */
for (i = 0; i < symbol->array_size; i++) {
@@ -409,7 +423,7 @@ str_list(NODE *symbol, NODE *t)
}
if (k >= list_size)
return list;
- }
+ }
}
return list;
}
@@ -426,7 +440,7 @@ str_kilobytes(NODE *symbol)
bucket_cnt = symbol->table_size;
/* This does not include extra memory for indices with stfmt != -1 */
- kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
+ kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
return kb;
}
@@ -514,7 +528,7 @@ str_dump(NODE *symbol, NODE *ndump)
return NULL;
#undef HCNT
-}
+}
/* awk_hash --- calculate the hash function of the string in subs */
@@ -627,11 +641,11 @@ grow_table(NODE *symbol)
* very large (> 8K), we just double more or less, instead of
* just jumping from 8K to 64K.
*/
-
+
static const unsigned long sizes[] = {
13, 127, 1021, 8191, 16381, 32749, 65497,
131101, 262147, 524309, 1048583, 2097169,
- 4194319, 8388617, 16777259, 33554467,
+ 4194319, 8388617, 16777259, 33554467,
67108879, 134217757, 268435459, 536870923,
1073741827
};
@@ -651,8 +665,7 @@ grow_table(NODE *symbol)
}
/* allocate new table */
- emalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_table");
- memset(new, '\0', newsize * sizeof(BUCKET *));
+ ezalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_table");
old = symbol->buckets;
symbol->buckets = new;
@@ -751,3 +764,67 @@ scramble(unsigned long x)
return x;
}
+
+/* env_remove --- for ENVIRON, remove value from real environment */
+
+static NODE **
+env_remove(NODE *symbol, NODE *subs)
+{
+ NODE **val = str_remove(symbol, subs);
+ char save;
+
+ if (val != NULL) {
+ str_terminate(subs, save);
+ (void) unsetenv(subs->stptr);
+ str_restore(subs, save);
+ }
+
+ return val;
+}
+
+/* env_clear --- clear out the environment when ENVIRON is deleted */
+
+static NODE **
+env_clear(NODE *symbol, NODE *subs)
+{
+ extern char **environ;
+ NODE **val = str_clear(symbol, subs);
+
+ environ = NULL; /* ZAP! */
+
+ /* str_clear zaps the vtable, reset it */
+ symbol->array_funcs = env_array_func;
+
+ return val;
+}
+
+/* env_store --- post assign function for ENVIRON, put new value into env */
+
+static NODE **
+env_store(NODE *symbol, NODE *subs)
+{
+ NODE **val = str_exists(symbol, subs);
+ const char *newval;
+
+ assert(val != NULL);
+
+ newval = (*val)->stptr;
+ if (newval == NULL)
+ newval = "";
+
+ (void) setenv(subs->stptr, newval, 1);
+
+ return val;
+}
+
+/* init_env_array --- set up the pointers for ENVIRON. A bit hacky. */
+
+void
+init_env_array(NODE *env_node)
+{
+ /* If POSIX simply don't reset the vtable and things work as before */
+ if (do_posix)
+ return;
+
+ env_node->array_funcs = env_array_func;
+}
diff --git a/support/CMakeLists.txt b/support/CMakeLists.txt
new file mode 100644
index 00000000..5e7fd3ad
--- /dev/null
+++ b/support/CMakeLists.txt
@@ -0,0 +1,34 @@
+#
+# CMakeLists.txt --- CMake input file for gawk's support library
+#
+# Copyright (C) 2016
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+add_definitions(-DGAWK)
+add_definitions(-DHAVE_CONFIG_H)
+add_definitions(-D_GNU_SOURCE)
+add_library (support STATIC
+ dfa.c
+ getopt1.c
+ getopt.c
+ localeinfo.c
+ random.c
+ regex.c
+)
diff --git a/support/ChangeLog b/support/ChangeLog
new file mode 100644
index 00000000..bc535ea8
--- /dev/null
+++ b/support/ChangeLog
@@ -0,0 +1,59 @@
+2017-06-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * dfa.c (dfaalloc): Replace xmalloc+memset with xzalloc.
+ * xalloc.h (xmalloc): New function moved here from gawkmisc.c.
+ (xcalloc): Replace xmalloc+memset with calloc.
+ (xzalloc): Replace xmalloc+memset with xcalloc.
+
+2017-06-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h,
+ regexec.c: Sync with GLIBC.
+
+2017-06-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * intprops.h: Sync with GNULIB.
+
+2017-05-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c, dfa.h, intprops.h, verify.h: Sync with GNULIB.
+
+2017-03-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+
+2017-01-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * localeinfo.h: Sync with GNULIB.
+ * localeinfo.c: Ditto.
+ * dfa.c: Ditto, to fix a memory leak.
+
+2017-01-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+
+2017-01-10 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+ Twice in one day! Sigh.
+
+2017-01-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ * dfa.c: Sync with GNULIB.
+
+2016-12-27 Juergen Kahrs <Juergen.Kahrs@googlemail.com>
+
+ * CMakeLists.txt: New file.
+
+2016-12-22 John E. Malmberg <wb8tyw@qsl.net>
+
+ * dfa.c fixes for OpenVMS
+
+2016-12-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * ChangeLog: Created.
+ * Makefile.am: New file.
+ * dfa.c, dfa.h, getopt.c, getopt.h, getopt1.c, getopt_int.h,
+ intprops.h, localeinfo.c, localeinfo.h, random.c, random.h,
+ regcomp.c, regex.c, regex.h, regex_internal.c, regex_internal.h,
+ regexec.c, verify.h, xalloc.h: Moved here from parent directory.
diff --git a/support/Makefile.am b/support/Makefile.am
new file mode 100644
index 00000000..0e198766
--- /dev/null
+++ b/support/Makefile.am
@@ -0,0 +1,61 @@
+#
+# Makefile.am --- automake input file for gawk
+#
+# Copyright (C) 2000-2016 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with automake to produce Makefile.in
+
+# This insures that make flags get passed down to child makes.
+AM_MAKEFLAGS = 'CFLAGS=$(CFLAGS)' 'LDFLAGS=$(LDFLAGS)'
+
+# Stuff to include in the dist that doesn't need it's own
+# Makefile.am files
+EXTRA_DIST = \
+ Makefile.am \
+ Makefile.in \
+ regcomp.c \
+ regex_internal.c \
+ regex_internal.h \
+ regexec.c
+
+# what to make and install
+noinst_LIBRARIES = libsupport.a
+libsupport_a_SOURCES = \
+ dfa.c \
+ dfa.h \
+ getopt.c \
+ getopt.h \
+ getopt_int.h \
+ getopt1.c \
+ intprops.h \
+ localeinfo.c \
+ localeinfo.h \
+ random.c \
+ random.h \
+ regex.c \
+ regex.h \
+ verify.h \
+ xalloc.h
+
+# For some make's, e.g. OpenBSD, that don't define this
+RM = rm -f
+
+DEFS = -DGAWK -DHAVE_CONFIG_H -I"$(srcdir)/.."
diff --git a/support/Makefile.in b/support/Makefile.in
new file mode 100644
index 00000000..13913f68
--- /dev/null
+++ b/support/Makefile.in
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Makefile.am --- automake input file for gawk
+#
+# Copyright (C) 2000-2016 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = support
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libsigsegv.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libsupport_a_AR = $(AR) $(ARFLAGS)
+libsupport_a_LIBADD =
+am_libsupport_a_OBJECTS = dfa.$(OBJEXT) getopt.$(OBJEXT) \
+ getopt1.$(OBJEXT) localeinfo.$(OBJEXT) random.$(OBJEXT) \
+ regex.$(OBJEXT)
+libsupport_a_OBJECTS = $(am_libsupport_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsupport_a_SOURCES)
+DIST_SOURCES = $(libsupport_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/mkinstalldirs ChangeLog
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = -DGAWK -DHAVE_CONFIG_H -I"$(srcdir)/.."
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GAWKLIBEXT = @GAWKLIBEXT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_LIBSIGSEGV = @HAVE_LIBSIGSEGV@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMPFR = @LIBMPFR@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBSIGSEGV = @LIBSIGSEGV@
+LIBSIGSEGV_PREFIX = @LIBSIGSEGV_PREFIX@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBSIGSEGV = @LTLIBSIGSEGV@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+acl_shlibext = @acl_shlibext@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgextensiondir = @pkgextensiondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# This insures that make flags get passed down to child makes.
+AM_MAKEFLAGS = 'CFLAGS=$(CFLAGS)' 'LDFLAGS=$(LDFLAGS)'
+
+# Stuff to include in the dist that doesn't need it's own
+# Makefile.am files
+EXTRA_DIST = \
+ Makefile.am \
+ Makefile.in \
+ regcomp.c \
+ regex_internal.c \
+ regex_internal.h \
+ regexec.c
+
+
+# what to make and install
+noinst_LIBRARIES = libsupport.a
+libsupport_a_SOURCES = \
+ dfa.c \
+ dfa.h \
+ getopt.c \
+ getopt.h \
+ getopt_int.h \
+ getopt1.c \
+ intprops.h \
+ localeinfo.c \
+ localeinfo.h \
+ random.c \
+ random.h \
+ regex.c \
+ regex.h \
+ verify.h \
+ xalloc.h
+
+
+# For some make's, e.g. OpenBSD, that don't define this
+RM = rm -f
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu support/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libsupport.a: $(libsupport_a_OBJECTS) $(libsupport_a_DEPENDENCIES) $(EXTRA_libsupport_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libsupport.a
+ $(AM_V_AR)$(libsupport_a_AR) libsupport.a $(libsupport_a_OBJECTS) $(libsupport_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libsupport.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localeinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/dfa.c b/support/dfa.c
index 4d1e1ab0..3a675f5d 100644
--- a/dfa.c
+++ b/support/dfa.c
@@ -1,5 +1,5 @@
/* dfa.c - deterministic extended regexp routines for GNU
- Copyright (C) 1988, 1998, 2000, 2002, 2004-2005, 2007-2016 Free Software
+ Copyright (C) 1988, 1998, 2000, 2002, 2004-2005, 2007-2017 Free Software
Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,12 @@
#include <assert.h>
#include <ctype.h>
+#ifndef VMS
+#include <stdint.h>
+#else
+#define SIZE_MAX __INT32_MAX
+#define PTRDIFF_MAX __INT32_MAX
+#endif
#include <stdio.h>
#ifndef VMS
@@ -38,37 +44,50 @@
#include <locale.h>
#endif
+#include "dfa.h" // gets stdbool.h for us
+
+static bool
+streq (char const *a, char const *b)
+{
+ return strcmp (a, b) == 0;
+}
+
+static bool
+isasciidigit (char c)
+{
+ return '0' <= c && c <= '9';
+}
+
/* Gawk doesn't use Gnulib, so don't assume that setlocale is present. */
#ifndef LC_ALL
# define setlocale(category, locale) NULL
#endif
-#define STREQ(a, b) (strcmp (a, b) == 0)
-
-/* ISASCIIDIGIT differs from isdigit, as follows:
- - Its arg may be any int or unsigned int; it need not be an unsigned char.
- - It's guaranteed to evaluate its argument exactly once.
- - It's typically faster.
- Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
- only '0' through '9' are digits. Prefer ISASCIIDIGIT to isdigit unless
- it's important to use the locale's definition of "digit" even when the
- host does not conform to Posix. */
-#define ISASCIIDIGIT(c) ((unsigned) (c) - '0' <= 9)
-
#include "gettext.h"
#define _(str) gettext (str)
#include <wchar.h>
-#include <wctype.h>
+#include "intprops.h"
#include "xalloc.h"
+#include "localeinfo.h"
+
+#ifndef FALLTHROUGH
+# if __GNUC__ < 7
+# define FALLTHROUGH ((void) 0)
+# else
+# define FALLTHROUGH __attribute__ ((__fallthrough__))
+# endif
+#endif
+
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
#if defined(__DJGPP__)
#include "mbsupport.h"
#endif
-#include "dfa.h"
-
#ifdef GAWK
static int
is_blank (int c)
@@ -77,14 +96,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
@@ -114,10 +125,10 @@ enum { CHARCLASS_WORD_BITS = 64 };
/* An initializer for a charclass whose 32-bit words are A through H. */
#define CHARCLASS_INIT(a, b, c, d, e, f, g, h) \
- { \
+ {{ \
CHARCLASS_PAIR (a, b), CHARCLASS_PAIR (c, d), \
CHARCLASS_PAIR (e, f), CHARCLASS_PAIR (g, h) \
- }
+ }}
/* The maximum useful value of a charclass_word; all used bits are 1. */
static charclass_word const CHARCLASS_WORD_MASK
@@ -130,7 +141,7 @@ enum
};
/* Sets of unsigned characters are stored as bit vectors in arrays of ints. */
-typedef charclass_word charclass[CHARCLASS_WORDS];
+typedef struct { charclass_word w[CHARCLASS_WORDS]; } charclass;
/* Convert a possibly-signed character to an unsigned character. This is
a bit safer than casting to unsigned char, since it catches some type
@@ -153,63 +164,87 @@ to_uchar (char ch)
character is a word constituent. A state whose context is CTX_ANY
might have transitions from any character. */
-#define CTX_NONE 1
-#define CTX_LETTER 2
-#define CTX_NEWLINE 4
-#define CTX_ANY 7
+enum
+ {
+ CTX_NONE = 1,
+ CTX_LETTER = 2,
+ CTX_NEWLINE = 4,
+ CTX_ANY = 7
+ };
/* Sometimes characters can only be matched depending on the surrounding
context. Such context decisions depend on what the previous character
was, and the value of the current (lookahead) character. Context
- dependent constraints are encoded as 12-bit integers. Each bit that
+ dependent constraints are encoded as 9-bit integers. Each bit that
is set indicates that the constraint succeeds in the corresponding
context.
- bit 8-11 - valid contexts when next character is CTX_NEWLINE
- bit 4-7 - valid contexts when next character is CTX_LETTER
- bit 0-3 - valid contexts when next character is CTX_NONE
+ bit 6-8 - valid contexts when next character is CTX_NEWLINE
+ bit 3-5 - valid contexts when next character is CTX_LETTER
+ bit 0-2 - valid contexts when next character is CTX_NONE
- The macro SUCCEEDS_IN_CONTEXT determines whether a given constraint
+ succeeds_in_context determines whether a given constraint
succeeds in a particular context. Prev is a bitmask of possible
context values for the previous character, curr is the (single-bit)
context value for the lookahead character. */
-#define NEWLINE_CONSTRAINT(constraint) (((constraint) >> 8) & 0xf)
-#define LETTER_CONSTRAINT(constraint) (((constraint) >> 4) & 0xf)
-#define OTHER_CONSTRAINT(constraint) ((constraint) & 0xf)
-
-#define SUCCEEDS_IN_CONTEXT(constraint, prev, curr) \
- ((((curr) & CTX_NONE ? OTHER_CONSTRAINT (constraint) : 0) \
- | ((curr) & CTX_LETTER ? LETTER_CONSTRAINT (constraint) : 0) \
- | ((curr) & CTX_NEWLINE ? NEWLINE_CONSTRAINT (constraint) : 0)) \
- & (prev))
-
-/* The following macros describe what a constraint depends on. */
-#define PREV_NEWLINE_CONSTRAINT(constraint) (((constraint) >> 2) & 0x111)
-#define PREV_LETTER_CONSTRAINT(constraint) (((constraint) >> 1) & 0x111)
-#define PREV_OTHER_CONSTRAINT(constraint) ((constraint) & 0x111)
-
-#define PREV_NEWLINE_DEPENDENT(constraint) \
- (PREV_NEWLINE_CONSTRAINT (constraint) != PREV_OTHER_CONSTRAINT (constraint))
-#define PREV_LETTER_DEPENDENT(constraint) \
- (PREV_LETTER_CONSTRAINT (constraint) != PREV_OTHER_CONSTRAINT (constraint))
+static int
+newline_constraint (int constraint)
+{
+ return (constraint >> 6) & 7;
+}
+static int
+letter_constraint (int constraint)
+{
+ return (constraint >> 3) & 7;
+}
+static int
+other_constraint (int constraint)
+{
+ return constraint & 7;
+}
+
+static bool
+succeeds_in_context (int constraint, int prev, int curr)
+{
+ return !! (((curr & CTX_NONE ? other_constraint (constraint) : 0) \
+ | (curr & CTX_LETTER ? letter_constraint (constraint) : 0) \
+ | (curr & CTX_NEWLINE ? newline_constraint (constraint) : 0)) \
+ & prev);
+}
+
+/* The following describe what a constraint depends on. */
+static bool
+prev_newline_dependent (int constraint)
+{
+ return ((constraint ^ constraint >> 2) & 0111) != 0;
+}
+static bool
+prev_letter_dependent (int constraint)
+{
+ return ((constraint ^ constraint >> 1) & 0111) != 0;
+}
/* Tokens that match the empty string subject to some constraint actually
work by applying that constraint to determine what may follow them,
taking into account what has gone before. The following values are
the constraints corresponding to the special tokens previously defined. */
-#define NO_CONSTRAINT 0x777
-#define BEGLINE_CONSTRAINT 0x444
-#define ENDLINE_CONSTRAINT 0x700
-#define BEGWORD_CONSTRAINT 0x050
-#define ENDWORD_CONSTRAINT 0x202
-#define LIMWORD_CONSTRAINT 0x252
-#define NOTLIMWORD_CONSTRAINT 0x525
+enum
+ {
+ NO_CONSTRAINT = 0777,
+ BEGLINE_CONSTRAINT = 0444,
+ ENDLINE_CONSTRAINT = 0700,
+ BEGWORD_CONSTRAINT = 0050,
+ ENDWORD_CONSTRAINT = 0202,
+ LIMWORD_CONSTRAINT = 0252,
+ NOTLIMWORD_CONSTRAINT = 0525
+ };
/* The regexp is parsed into an array of tokens in postfix form. Some tokens
are operators and others are terminal symbols. Most (but not all) of these
codes are returned by the lexical analyzer. */
typedef ptrdiff_t token;
+static ptrdiff_t const TOKEN_MAX = PTRDIFF_MAX;
/* States are indexed by state_num values. These are normally
nonnegative but -1 is used as a special value. */
@@ -318,8 +353,8 @@ typedef struct
typedef struct
{
position *elems; /* Elements of this position set. */
- size_t nelem; /* Number of elements in this set. */
- size_t alloc; /* Number of elements allocated in ELEMS. */
+ ptrdiff_t nelem; /* Number of elements in this set. */
+ ptrdiff_t alloc; /* Number of elements allocated in ELEMS. */
} position_set;
/* Sets of leaves are also stored as arrays. */
@@ -337,9 +372,6 @@ typedef struct
size_t hash; /* Hash of the positions of this state. */
position_set elems; /* Positions this state could match. */
unsigned char context; /* Context from previous state. */
- bool curr_dependent; /* True if the follows of any positions with
- ANYCHAR depends on the next character's
- context. */
unsigned short constraint; /* Constraint for this state to accept. */
token first_end; /* Token value of the first END in elems. */
position_set mbps; /* Positions which can match multibyte
@@ -350,7 +382,8 @@ typedef struct
ANYCHAR. */
} dfa_state;
-/* Maximum for any transition table count that exceeds min_trcount. */
+/* Maximum for any transition table count. This should be at least 3,
+ for the initial state setup. */
enum { MAX_TRCOUNT = 1024 };
/* A bracket operator.
@@ -360,7 +393,8 @@ struct mb_char_classes
ptrdiff_t cset;
bool invert;
wchar_t *chars; /* Normal characters. */
- size_t nchars;
+ ptrdiff_t nchars;
+ ptrdiff_t nchars_alloc;
};
struct regex_syntax
@@ -372,11 +406,15 @@ struct regex_syntax
/* Flag for case-folding letters into sets. */
bool case_fold;
+ /* True if ^ and $ match only the start and end of data, and do not match
+ end-of-line within data. */
+ bool anchor;
+
/* End-of-line byte in data. */
unsigned char eolbyte;
/* Cache of char-context values. */
- int sbit[NOTCHAR];
+ char sbit[NOTCHAR];
/* If never_trail[B], the byte B cannot be a non-initial byte in a
multibyte character. */
@@ -395,8 +433,8 @@ struct regex_syntax
meaning of the @#%!@#%^!@ syntax bits. */
struct lexer_state
{
- char const *lexptr; /* Pointer to next input character. */
- size_t lexleft; /* Number of characters remaining. */
+ char const *ptr; /* Pointer to next input character. */
+ size_t left; /* Number of characters remaining. */
token lasttok; /* Previous token returned; initially END. */
size_t parens; /* Count of outstanding left parens. */
int minrep, maxrep; /* Repeat counts for {m,n}. */
@@ -409,6 +447,9 @@ struct lexer_state
/* Length of the multibyte representation of wctok. */
int cur_mb_len;
+ /* The most recently analyzed multibyte bracket expression. */
+ struct mb_char_classes brack;
+
/* We're separated from beginning or (, | only by zero-width characters. */
bool laststart;
};
@@ -433,14 +474,15 @@ struct dfa
/* Fields filled by the scanner. */
charclass *charclasses; /* Array of character sets for CSET tokens. */
- size_t cindex; /* Index for adding new charclasses. */
- size_t calloc; /* Number of charclasses allocated. */
+ ptrdiff_t cindex; /* Index for adding new charclasses. */
+ ptrdiff_t calloc; /* Number of charclasses allocated. */
+ size_t canychar; /* Index of anychar class, or (size_t) -1. */
/* Scanner state */
- struct lexer_state lexstate;
+ struct lexer_state lex;
/* Parser state */
- struct parser_state parsestate;
+ struct parser_state parse;
/* Fields filled by the parser. */
token *tokens; /* Postfix parse array. */
@@ -453,14 +495,9 @@ struct dfa
size_t nregexps; /* Count of parallel regexps being built
with dfaparse. */
bool fast; /* The DFA is fast. */
- bool multibyte; /* MB_CUR_MAX > 1. */
token utf8_anychar_classes[5]; /* To lower ANYCHAR in UTF-8 locales. */
mbstate_t mbs; /* Multibyte conversion state. */
- /* dfaexec implementation. */
- char *(*dfaexec) (struct dfa *, char const *, char *,
- bool, size_t *, bool *);
-
/* The following are valid only if MB_CUR_MAX > 1. */
/* The value of multibyte_prop[i] is defined by following rule.
@@ -470,9 +507,6 @@ struct dfa
bit 1 : tokens[i] is the last byte of a character, including
single-byte characters.
- if tokens[i] = MBCSET
- ("the index of mbcsets corresponding to this operator" << 2) + 3
-
e.g.
tokens
= 'single_byte_a', 'multi_byte_A', single_byte_b'
@@ -480,12 +514,7 @@ struct dfa
multibyte_prop
= 3 , 1 , 0 , 2 , 3
*/
- int *multibyte_prop;
-
- /* Array of the bracket expression in the DFA. */
- struct mb_char_classes *mbcsets;
- size_t nmbcsets;
- size_t mbcsets_alloc;
+ char *multibyte_prop;
/* Fields filled by the superset. */
struct dfa *superset; /* Hint of the dfa. */
@@ -493,7 +522,7 @@ struct dfa
/* Fields filled by the state builder. */
dfa_state *states; /* States of the dfa. */
state_num sindex; /* Index for adding new states. */
- size_t salloc; /* Number of states currently allocated. */
+ ptrdiff_t salloc; /* Number of states currently allocated. */
/* Fields filled by the parse tree->NFA conversion. */
position_set *follows; /* Array of follow sets, indexed by position
@@ -513,23 +542,27 @@ struct dfa
/* Fields filled by dfaexec. */
state_num tralloc; /* Number of transition tables that have
- slots so far, not counting trans[-1]. */
+ slots so far, not counting trans[-1] and
+ trans[-2]. */
int trcount; /* Number of transition tables that have
- actually been built. */
- int min_trcount; /* Minimum of number of transition tables.
- Always keep the number, even after freeing
- the transition tables. It is also the
- number of initial states. */
+ been built, other than for initial
+ states. */
+ int min_trcount; /* Number of initial states. Equivalently,
+ the minimum state number for which trcount
+ counts transitions. */
state_num **trans; /* Transition tables for states that can
never accept. If the transitions for a
state have not yet been computed, or the
state could possibly accept, its entry in
- this table is NULL. This points to one
+ this table is NULL. This points to two
past the start of the allocated array,
- and trans[-1] is always NULL. */
+ and trans[-1] and trans[-2] are always
+ NULL. */
state_num **fails; /* Transition tables after failing to accept
- on a state that potentially could do so. */
- int *success; /* Table of acceptance conditions used in
+ on a state that potentially could do so.
+ If trans[i] is non-null, fails[i] must
+ be null. */
+ char *success; /* Table of acceptance conditions used in
dfaexec and computed in build_state. */
state_num *newlines; /* Transitions on newlines. The entry for a
newline in any transition table is always
@@ -543,29 +576,48 @@ struct dfa
do not distinguish between their contexts,
as not supported word. */
position_set mb_follows; /* Follow set added by ANYCHAR on demand. */
- state_num **mb_trans; /* Transition tables for states with ANYCHAR. */
+ state_num **mb_trans; /* Transition tables for states with
+ ANYCHAR. */
state_num mb_trcount; /* Number of transition tables for states with
ANYCHAR that have actually been built. */
+
+ /* Information derived from the locale. This is at the end so that
+ a quick memset need not clear it specially. */
+
+ /* dfaexec implementation. */
+ char *(*dfaexec) (struct dfa *, char const *, char *,
+ bool, size_t *, bool *);
+
+ /* The locale is simple, like the C locale. These locales can be
+ processed more efficiently, as they are single-byte, their native
+ character set is in collating-sequence order, and they do not
+ have multi-character collating elements. */
+ bool simple_locale;
+
+ /* Other cached information derived from the locale. */
+ struct localeinfo localeinfo;
};
-/* Some macros for user access to dfa internals. */
+/* User access to dfa internals. */
/* S could possibly be an accepting state of R. */
-#define ACCEPTING(s, r) ((r).states[s].constraint)
+static bool
+accepting (state_num s, struct dfa const *r)
+{
+ return r->states[s].constraint != 0;
+}
/* STATE accepts in the specified context. */
-#define ACCEPTS_IN_CONTEXT(prev, curr, state, dfa) \
- SUCCEEDS_IN_CONTEXT ((dfa).states[state].constraint, prev, curr)
+static bool
+accepts_in_context (int prev, int curr, state_num state, struct dfa const *dfa)
+{
+ return succeeds_in_context (dfa->states[state].constraint, prev, curr);
+}
static void regexp (struct dfa *dfa);
-/* A table indexed by byte values that contains the corresponding wide
- character (if any) for that byte. WEOF means the byte is not a
- valid single-byte character. */
-static wint_t mbrtowc_cache[NOTCHAR];
-
/* Store into *PWC the result of converting the leading bytes of the
- multibyte buffer S of length N bytes, using the mbrtowc_cache in *D
+ multibyte buffer S of length N bytes, using D->localeinfo.sbctowc
and updating the conversion state in *D. On conversion error,
convert just a single byte, to WEOF. Return the number of bytes
converted.
@@ -574,7 +626,7 @@ static wint_t mbrtowc_cache[NOTCHAR];
* PWC points to wint_t, not to wchar_t.
* The last arg is a dfa *D instead of merely a multibyte conversion
- state D->mbs. D also contains an mbrtowc_cache for speed.
+ state D->mbs.
* N must be at least 1.
* S[N - 1] must be a sentinel byte.
* Shift encodings are not supported.
@@ -585,7 +637,7 @@ static size_t
mbs_to_wchar (wint_t *pwc, char const *s, size_t n, struct dfa *d)
{
unsigned char uc = s[0];
- wint_t wc = mbrtowc_cache[uc];
+ wint_t wc = d->localeinfo.sbctowc[uc];
if (wc == WEOF)
{
@@ -608,8 +660,6 @@ mbs_to_wchar (wint_t *pwc, char const *s, size_t n, struct dfa *d)
static void
prtok (token t)
{
- char const *s;
-
if (t < 0)
fprintf (stderr, "END");
else if (t < NOTCHAR)
@@ -619,6 +669,7 @@ prtok (token t)
}
else
{
+ char const *s;
switch (t)
{
case EMPTY:
@@ -684,169 +735,188 @@ prtok (token t)
/* Stuff pertaining to charclasses. */
static bool
-tstbit (unsigned int b, charclass const c)
+tstbit (unsigned int b, charclass const *c)
{
- return c[b / CHARCLASS_WORD_BITS] >> b % CHARCLASS_WORD_BITS & 1;
+ return c->w[b / CHARCLASS_WORD_BITS] >> b % CHARCLASS_WORD_BITS & 1;
}
static void
-setbit (unsigned int b, charclass c)
+setbit (unsigned int b, charclass *c)
{
- c[b / CHARCLASS_WORD_BITS] |= (charclass_word) 1 << b % CHARCLASS_WORD_BITS;
+ charclass_word one = 1;
+ c->w[b / CHARCLASS_WORD_BITS] |= one << b % CHARCLASS_WORD_BITS;
}
static void
-clrbit (unsigned int b, charclass c)
+clrbit (unsigned int b, charclass *c)
{
- c[b / CHARCLASS_WORD_BITS] &= ~((charclass_word) 1
- << b % CHARCLASS_WORD_BITS);
+ charclass_word one = 1;
+ c->w[b / CHARCLASS_WORD_BITS] &= ~(one << b % CHARCLASS_WORD_BITS);
}
static void
-copyset (charclass const src, charclass dst)
+zeroset (charclass *s)
{
- memcpy (dst, src, sizeof (charclass));
+ memset (s, 0, sizeof *s);
}
static void
-zeroset (charclass s)
+fillset (charclass *s)
{
- memset (s, 0, sizeof (charclass));
+ for (int i = 0; i < CHARCLASS_WORDS; i++)
+ s->w[i] = CHARCLASS_WORD_MASK;
}
static void
-notset (charclass s)
+notset (charclass *s)
{
- int i;
-
- for (i = 0; i < CHARCLASS_WORDS; ++i)
- s[i] = CHARCLASS_WORD_MASK & ~s[i];
+ for (int i = 0; i < CHARCLASS_WORDS; ++i)
+ s->w[i] = CHARCLASS_WORD_MASK & ~s->w[i];
}
static bool
-equal (charclass const s1, charclass const s2)
+equal (charclass const *s1, charclass const *s2)
{
charclass_word w = 0;
- int i;
- for (i = 0; i < CHARCLASS_WORDS; i++)
- w |= s1[i] ^ s2[i];
+ for (int i = 0; i < CHARCLASS_WORDS; i++)
+ w |= s1->w[i] ^ s2->w[i];
return w == 0;
}
static bool
-emptyset (charclass const s)
+emptyset (charclass const *s)
{
charclass_word w = 0;
- int i;
- for (i = 0; i < CHARCLASS_WORDS; i++)
- w |= s[i];
+ for (int i = 0; i < CHARCLASS_WORDS; i++)
+ w |= s->w[i];
return w == 0;
}
-/* Ensure that the array addressed by PTR holds at least NITEMS +
- (PTR || !NITEMS) items. Either return PTR, or reallocate the array
- and return its new address. Although PTR may be null, the returned
- value is never null.
+/* Grow PA, which points to an array of *NITEMS items, and return the
+ location of the reallocated array, updating *NITEMS to reflect its
+ new size. The new array will contain at least NITEMS_INCR_MIN more
+ items, but will not contain more than NITEMS_MAX items total.
+ ITEM_SIZE is the size of each item, in bytes.
+
+ ITEM_SIZE and NITEMS_INCR_MIN must be positive. *NITEMS must be
+ nonnegative. If NITEMS_MAX is -1, it is treated as if it were
+ infinity.
+
+ If PA is null, then allocate a new array instead of reallocating
+ the old one.
+
+ Thus, to grow an array A without saving its old contents, do
+ { free (A); A = xpalloc (NULL, &AITEMS, ...); }. */
- The array holds *NALLOC items; *NALLOC is updated on reallocation.
- ITEMSIZE is the size of one item. Avoid O(N**2) behavior on arrays
- growing linearly. */
static void *
-maybe_realloc (void *ptr, size_t nitems, size_t *nalloc, size_t itemsize)
+xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
+ ptrdiff_t nitems_max, ptrdiff_t item_size)
{
- if (nitems < *nalloc)
- return ptr;
- *nalloc = nitems;
- return x2nrealloc (ptr, nalloc, itemsize);
+ ptrdiff_t n0 = *nitems;
+
+ /* The approximate size to use for initial small allocation
+ requests. This is the largest "small" request for the GNU C
+ library malloc. */
+ enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
+
+ /* If the array is tiny, grow it to about (but no greater than)
+ DEFAULT_MXFAST bytes. Otherwise, grow it by about 50%.
+ Adjust the growth according to three constraints: NITEMS_INCR_MIN,
+ NITEMS_MAX, and what the C language can represent safely. */
+
+ ptrdiff_t n, nbytes;
+ if (INT_ADD_WRAPV (n0, n0 >> 1, &n))
+ n = PTRDIFF_MAX;
+ if (0 <= nitems_max && nitems_max < n)
+ n = nitems_max;
+
+ ptrdiff_t adjusted_nbytes
+ = ((INT_MULTIPLY_WRAPV (n, item_size, &nbytes) || SIZE_MAX < nbytes)
+ ? MIN (PTRDIFF_MAX, SIZE_MAX)
+ : nbytes < DEFAULT_MXFAST ? DEFAULT_MXFAST : 0);
+ if (adjusted_nbytes)
+ {
+ n = adjusted_nbytes / item_size;
+ nbytes = adjusted_nbytes - adjusted_nbytes % item_size;
+ }
+
+ if (! pa)
+ *nitems = 0;
+ if (n - n0 < nitems_incr_min
+ && (INT_ADD_WRAPV (n0, nitems_incr_min, &n)
+ || (0 <= nitems_max && nitems_max < n)
+ || INT_MULTIPLY_WRAPV (n, item_size, &nbytes)))
+ xalloc_die ();
+ pa = xrealloc (pa, nbytes);
+ *nitems = n;
+ return pa;
+}
+
+/* Ensure that the array addressed by PA holds at least I + 1 items.
+ Either return PA, or reallocate the array and return its new address.
+ Although PA may be null, the returned value is never null.
+
+ The array holds *NITEMS items, where 0 <= I <= *NITEMS; *NITEMS
+ is updated on reallocation. If PA is null, *NITEMS must be zero.
+ Do not allocate more than NITEMS_MAX items total; -1 means no limit.
+ ITEM_SIZE is the size of one item; it must be positive.
+ Avoid O(N**2) behavior on arrays growing linearly. */
+static void *
+maybe_realloc (void *pa, ptrdiff_t i, ptrdiff_t *nitems,
+ ptrdiff_t nitems_max, ptrdiff_t item_size)
+{
+ if (i < *nitems)
+ return pa;
+ return xpalloc (pa, nitems, 1, nitems_max, item_size);
}
/* In DFA D, find the index of charclass S, or allocate a new one. */
-static size_t
-dfa_charclass_index (struct dfa *d, charclass const s)
+static ptrdiff_t
+charclass_index (struct dfa *d, charclass *s)
{
- size_t i;
+ ptrdiff_t i;
for (i = 0; i < d->cindex; ++i)
- if (equal (s, d->charclasses[i]))
+ if (equal (s, &d->charclasses[i]))
return i;
d->charclasses = maybe_realloc (d->charclasses, d->cindex, &d->calloc,
- sizeof *d->charclasses);
+ TOKEN_MAX - CSET, sizeof *d->charclasses);
++d->cindex;
- copyset (s, d->charclasses[i]);
+ d->charclasses[i] = *s;
return i;
}
static bool
-unibyte_word_constituent (unsigned char c)
+unibyte_word_constituent (struct dfa const *dfa, unsigned char c)
{
- return mbrtowc_cache[c] != WEOF && (isalnum (c) || (c) == '_');
+ return dfa->localeinfo.sbctowc[c] != WEOF && (isalnum (c) || (c) == '_');
}
static int
char_context (struct dfa const *dfa, unsigned char c)
{
- if (c == dfa->syntax.eolbyte)
+ if (c == dfa->syntax.eolbyte && !dfa->syntax.anchor)
return CTX_NEWLINE;
- if (unibyte_word_constituent (c))
+ if (unibyte_word_constituent (dfa, c))
return CTX_LETTER;
return CTX_NONE;
}
-/* UTF-8 encoding allows some optimizations that we can't otherwise
- assume in a multibyte encoding. */
-static bool using_utf8;
-
-bool
-dfa_using_utf8 (void)
-{
- return using_utf8;
-}
-
-static void
-init_mbrtowc_cache (void)
-{
- int i;
- for (i = CHAR_MIN; i <= CHAR_MAX; ++i)
- {
- char c = i;
- unsigned char uc = i;
- mbstate_t s = { 0 };
- wchar_t wc;
- mbrtowc_cache[uc] = mbrtowc (&wc, &c, 1, &s) <= 1 ? wc : WEOF;
- }
-}
-
-/* Entry point to set syntax options. */
+/* Copy the syntax settings from one dfa instance to another.
+ Saves considerable computation time if compiling many regular expressions
+ based on the same setting. */
void
-dfasyntax (struct dfa *dfa, reg_syntax_t bits, bool fold, unsigned char eol)
+dfacopysyntax (struct dfa *to, const struct dfa *from)
{
- int i;
- dfa->syntax.syntax_bits_set = true;
- dfa->syntax.syntax_bits = bits;
- dfa->syntax.case_fold = fold;
- dfa->syntax.eolbyte = eol;
+ to->dfaexec = from->dfaexec;
+ to->simple_locale = from->simple_locale;
+ to->localeinfo = from->localeinfo;
- for (i = CHAR_MIN; i <= CHAR_MAX; ++i)
- {
- unsigned char uc = i;
+ to->fast = from->fast;
- /* Use mbrtowc_cache to calculate sbit. */
- dfa->syntax.sbit[uc] = char_context (dfa, uc);
- switch (dfa->syntax.sbit[uc])
- {
- case CTX_LETTER:
- setbit (uc, dfa->syntax.letters);
- break;
- case CTX_NEWLINE:
- setbit (uc, dfa->syntax.newline);
- break;
- }
-
- /* POSIX requires that the five bytes in "\n\r./" (including the
- terminating NUL) cannot occur inside a multibyte character. */
- dfa->syntax.never_trail[uc] = (using_utf8 ? (uc & 0xc0) != 0x80
- : strchr ("\n\r./", uc) != NULL);
- }
+ to->canychar = from->canychar;
+ to->lex.cur_mb_len = from->lex.cur_mb_len;
+ to->syntax = from->syntax;
}
/* Set a bit in the charclass for the given wchar_t. Do nothing if WC
@@ -855,10 +925,10 @@ dfasyntax (struct dfa *dfa, reg_syntax_t bits, bool fold, unsigned char eol)
dotless i/dotted I are not included in the chosen character set.
Return whether a bit was set in the charclass. */
static bool
-setbit_wc (wint_t wc, charclass c)
+setbit_wc (wint_t wc, charclass *c)
{
int b = wctob (wc);
- if (b == EOF)
+ if (b < 0)
return false;
setbit (b, c);
@@ -868,39 +938,18 @@ setbit_wc (wint_t wc, charclass c)
/* Set a bit for B and its case variants in the charclass C.
MB_CUR_MAX must be 1. */
static void
-setbit_case_fold_c (int b, charclass c)
+setbit_case_fold_c (int b, charclass *c)
{
int ub = toupper (b);
- int i;
- for (i = 0; i < NOTCHAR; i++)
+ for (int i = 0; i < NOTCHAR; i++)
if (toupper (i) == ub)
setbit (i, c);
}
-static void check_utf8 (void)
-{
- wchar_t wc;
- mbstate_t mbs = { 0 };
- using_utf8 = mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100;
-}
-
-static bool unibyte_c;
-
-static void check_unibyte_c (void)
-{
- char const *locale = setlocale (LC_ALL, NULL);
- unibyte_c = (!locale
- || STREQ (locale, "C")
- || STREQ (locale, "POSIX"));
-}
-
-/* The current locale is known to be a unibyte locale
- without multicharacter collating sequences and where range
- comparisons simply use the native encoding. These locales can be
- processed more efficiently. */
+/* Return true if the locale compatible with the C locale. */
static bool
-using_simple_locale (struct dfa const *dfa)
+using_simple_locale (bool multibyte)
{
/* The native character set is known to be compatible with
the C locale. The following test isn't perfect, but it's good
@@ -918,87 +967,43 @@ using_simple_locale (struct dfa const *dfa)
&& '}' == 125 && '~' == 126)
};
- return (!native_c_charset || dfa->multibyte) ? false : unibyte_c;
+ if (!native_c_charset || multibyte)
+ return false;
+ else
+ {
+ /* Treat C and POSIX locales as being compatible. Also, treat
+ errors as compatible, as these are invariably from stubs. */
+ char const *loc = setlocale (LC_ALL, NULL);
+ return !loc || streq (loc, "C") || streq (loc, "POSIX");
+ }
}
-/* Fetch the next lexical input character. Set C (of type int) to the
- next input byte, except set C to EOF if the input is a multibyte
- character of length greater than 1. Set WC (of type wint_t) to the
- value of the input if it is a valid multibyte character (possibly
- of length 1); otherwise set WC to WEOF. If there is no more input,
- report EOFERR if EOFERR is not null, and return lasttok = END
- otherwise. */
-# define FETCH_WC(dfa, c, wc, eoferr) \
- do { \
- if (! dfa->lexstate.lexleft) \
- { \
- if ((eoferr) != 0) \
- dfaerror (eoferr); \
- else \
- return dfa->lexstate.lasttok = END; \
- } \
- else \
- { \
- wint_t _wc; \
- size_t nbytes = mbs_to_wchar (&_wc, dfa->lexstate.lexptr, \
- dfa->lexstate.lexleft, dfa); \
- dfa->lexstate.cur_mb_len = nbytes; \
- (wc) = _wc; \
- (c) = nbytes == 1 ? to_uchar (*dfa->lexstate.lexptr) : EOF; \
- dfa->lexstate.lexptr += nbytes; \
- dfa->lexstate.lexleft -= nbytes; \
- } \
- } while (false)
-
-#ifndef MIN
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-/* The set of wchar_t values C such that there's a useful locale
- somewhere where C != towupper (C) && C != towlower (towupper (C)).
- For example, 0x00B5 (U+00B5 MICRO SIGN) is in this table, because
- towupper (0x00B5) == 0x039C (U+039C GREEK CAPITAL LETTER MU), and
- towlower (0x039C) == 0x03BC (U+03BC GREEK SMALL LETTER MU). */
-static short const lonesome_lower[] =
- {
- 0x00B5, 0x0131, 0x017F, 0x01C5, 0x01C8, 0x01CB, 0x01F2, 0x0345,
- 0x03C2, 0x03D0, 0x03D1, 0x03D5, 0x03D6, 0x03F0, 0x03F1,
-
- /* U+03F2 GREEK LUNATE SIGMA SYMBOL lacks a specific uppercase
- counterpart in locales predating Unicode 4.0.0 (April 2003). */
- 0x03F2,
-
- 0x03F5, 0x1E9B, 0x1FBE,
- };
-
-/* Maximum number of characters that can be the case-folded
- counterparts of a single character, not counting the character
- itself. This is 1 for towupper, 1 for towlower, and 1 for each
- entry in LONESOME_LOWER. */
-enum
-{ CASE_FOLDED_BUFSIZE = 2 + sizeof lonesome_lower / sizeof *lonesome_lower };
+/* Fetch the next lexical input character from the pattern. There
+ must at least one byte of pattern input. Set DFA->lex.wctok to the
+ value of the character or to WEOF depending on whether the input is
+ a valid multibyte character (possibly of length 1). Then return
+ the next input byte value, except return EOF if the input is a
+ multibyte character of length greater than 1. */
+static int
+fetch_wc (struct dfa *dfa)
+{
+ size_t nbytes = mbs_to_wchar (&dfa->lex.wctok, dfa->lex.ptr, dfa->lex.left,
+ dfa);
+ dfa->lex.cur_mb_len = nbytes;
+ int c = nbytes == 1 ? to_uchar (dfa->lex.ptr[0]) : EOF;
+ dfa->lex.ptr += nbytes;
+ dfa->lex.left -= nbytes;
+ return c;
+}
-/* Find the characters equal to C after case-folding, other than C
- itself, and store them into FOLDED. Return the number of characters
- stored. */
-static unsigned int
-case_folded_counterparts (wchar_t c, wchar_t folded[CASE_FOLDED_BUFSIZE])
+/* If there is no more input, report an error about unbalanced brackets.
+ Otherwise, behave as with fetch_wc (DFA). */
+static int
+bracket_fetch_wc (struct dfa *dfa)
{
- unsigned int i;
- unsigned int n = 0;
- wint_t uc = towupper (c);
- wint_t lc = towlower (uc);
- if (uc != c)
- folded[n++] = uc;
- if (lc != uc && lc != c && towupper (lc) == uc)
- folded[n++] = lc;
- for (i = 0; i < sizeof lonesome_lower / sizeof *lonesome_lower; i++)
- {
- wint_t li = lonesome_lower[i];
- if (li != lc && li != uc && li != c && towupper (li) == uc)
- folded[n++] = li;
- }
- return n;
+ if (! dfa->lex.left)
+ dfaerror (_("unbalanced ["));
+ return fetch_wc (dfa);
}
typedef int predicate (int);
@@ -1033,22 +1038,17 @@ static const struct dfa_ctype prednames[] = {
static const struct dfa_ctype *_GL_ATTRIBUTE_PURE
find_pred (const char *str)
{
- unsigned int i;
- for (i = 0; prednames[i].name; ++i)
- if (STREQ (str, prednames[i].name))
+ for (unsigned int i = 0; prednames[i].name; ++i)
+ if (streq (str, prednames[i].name))
return &prednames[i];
return NULL;
}
-/* Multibyte character handling sub-routine for lex.
- Parse a bracket expression and build a struct mb_char_classes. */
+/* Parse a bracket expression, which possibly includes multibyte
+ characters. */
static token
parse_bracket_exp (struct dfa *dfa)
{
- bool invert;
- int c, c1, c2;
- charclass ccl;
-
/* This is a bracket expression that dfaexec is known to
process correctly. */
bool known_bracket_exp = true;
@@ -1060,43 +1060,19 @@ parse_bracket_exp (struct dfa *dfa)
Bit 3 = includes ranges, char/equiv classes or collation elements. */
int colon_warning_state;
- wint_t wc;
- wint_t wc2;
- wint_t wc1 = 0;
-
- /* Work area to build a mb_char_classes. */
- struct mb_char_classes *work_mbc;
- size_t chars_al;
-
- chars_al = 0;
- if (dfa->multibyte)
- {
- dfa->mbcsets = maybe_realloc (dfa->mbcsets, dfa->nmbcsets,
- &dfa->mbcsets_alloc,
- sizeof *dfa->mbcsets);
-
- /* dfa->multibyte_prop[] hold the index of dfa->mbcsets.
- We will update dfa->multibyte_prop[] in addtok, because we can't
- decide the index in dfa->tokens[]. */
-
- /* Initialize work area. */
- work_mbc = &dfa->mbcsets[dfa->nmbcsets++];
- memset (work_mbc, 0, sizeof *work_mbc);
- }
- else
- work_mbc = NULL;
-
- memset (ccl, 0, sizeof ccl);
- FETCH_WC (dfa, c, wc, _("unbalanced ["));
- if (c == '^')
+ dfa->lex.brack.nchars = 0;
+ charclass ccl;
+ zeroset (&ccl);
+ int c = bracket_fetch_wc (dfa);
+ bool invert = c == '^';
+ if (invert)
{
- FETCH_WC (dfa, c, wc, _("unbalanced ["));
- invert = true;
- known_bracket_exp = using_simple_locale (dfa);
+ c = bracket_fetch_wc (dfa);
+ known_bracket_exp = dfa->simple_locale;
}
- else
- invert = false;
-
+ wint_t wc = dfa->lex.wctok;
+ int c1;
+ wint_t wc1;
colon_warning_state = (c == ':');
do
{
@@ -1109,7 +1085,8 @@ parse_bracket_exp (struct dfa *dfa)
dfa is ever called. */
if (c == '[')
{
- FETCH_WC (dfa, c1, wc1, _("unbalanced ["));
+ c1 = bracket_fetch_wc (dfa);
+ wc1 = dfa->lex.wctok;
if ((c1 == ':' && (dfa->syntax.syntax_bits & RE_CHAR_CLASSES))
|| c1 == '.' || c1 == '=')
@@ -1119,9 +1096,9 @@ parse_bracket_exp (struct dfa *dfa)
size_t len = 0;
for (;;)
{
- FETCH_WC (dfa, c, wc, _("unbalanced ["));
- if ((c == c1 && *dfa->lexstate.lexptr == ']')
- || dfa->lexstate.lexleft == 0)
+ c = bracket_fetch_wc (dfa);
+ if (dfa->lex.left == 0
+ || (c == c1 && dfa->lex.ptr[0] == ']'))
break;
if (len < MAX_BRACKET_STRING_LEN)
str[len++] = c;
@@ -1132,7 +1109,8 @@ parse_bracket_exp (struct dfa *dfa)
str[len] = '\0';
/* Fetch bracket. */
- FETCH_WC (dfa, c, wc, _("unbalanced ["));
+ c = bracket_fetch_wc (dfa);
+ wc = dfa->lex.wctok;
if (c1 == ':')
/* Build character class. POSIX allows character
classes to match multicharacter collating elements,
@@ -1140,19 +1118,19 @@ parse_bracket_exp (struct dfa *dfa)
worry about that possibility. */
{
char const *class
- = (dfa->syntax.case_fold && (STREQ (str, "upper")
- || STREQ (str, "lower")) ?
- "alpha" : str);
+ = (dfa->syntax.case_fold && (streq (str, "upper")
+ || streq (str, "lower"))
+ ? "alpha" : str);
const struct dfa_ctype *pred = find_pred (class);
if (!pred)
dfaerror (_("invalid character class"));
- if (dfa->multibyte && !pred->single_byte_only)
+ if (dfa->localeinfo.multibyte && !pred->single_byte_only)
known_bracket_exp = false;
else
- for (c2 = 0; c2 < NOTCHAR; ++c2)
+ for (int c2 = 0; c2 < NOTCHAR; ++c2)
if (pred->func (c2))
- setbit (c2, ccl);
+ setbit (c2, &ccl);
}
else
known_bracket_exp = false;
@@ -1160,7 +1138,8 @@ parse_bracket_exp (struct dfa *dfa)
colon_warning_state |= 8;
/* Fetch new lookahead character. */
- FETCH_WC (dfa, c1, wc1, _("unbalanced ["));
+ c1 = bracket_fetch_wc (dfa);
+ wc1 = dfa->lex.wctok;
continue;
}
@@ -1168,21 +1147,29 @@ parse_bracket_exp (struct dfa *dfa)
are already set up. */
}
- if (c == '\\' && (dfa->syntax.syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
- FETCH_WC (dfa, c, wc, _("unbalanced ["));
+ if (c == '\\'
+ && (dfa->syntax.syntax_bits & RE_BACKSLASH_ESCAPE_IN_LISTS))
+ {
+ c = bracket_fetch_wc (dfa);
+ wc = dfa->lex.wctok;
+ }
if (c1 == NOTCHAR)
- FETCH_WC (dfa, c1, wc1, _("unbalanced ["));
+ {
+ c1 = bracket_fetch_wc (dfa);
+ wc1 = dfa->lex.wctok;
+ }
if (c1 == '-')
/* build range characters. */
{
- FETCH_WC (dfa, c2, wc2, _("unbalanced ["));
+ int c2 = bracket_fetch_wc (dfa);
+ wint_t wc2 = dfa->lex.wctok;
/* A bracket expression like [a-[.aa.]] matches an unknown set.
Treat it like [-a[.aa.]] while parsing it, and
remember that the set is unknown. */
- if (c2 == '[' && *dfa->lexstate.lexptr == '.')
+ if (c2 == '[' && dfa->lex.ptr[0] == '.')
{
known_bracket_exp = false;
c2 = ']';
@@ -1192,39 +1179,33 @@ parse_bracket_exp (struct dfa *dfa)
{
/* In the case [x-], the - is an ordinary hyphen,
which is left in c1, the lookahead character. */
- dfa->lexstate.lexptr -= dfa->lexstate.cur_mb_len;
- dfa->lexstate.lexleft += dfa->lexstate.cur_mb_len;
+ dfa->lex.ptr -= dfa->lex.cur_mb_len;
+ dfa->lex.left += dfa->lex.cur_mb_len;
}
else
{
if (c2 == '\\' && (dfa->syntax.syntax_bits
& RE_BACKSLASH_ESCAPE_IN_LISTS))
- FETCH_WC (dfa, c2, wc2, _("unbalanced ["));
+ {
+ c2 = bracket_fetch_wc (dfa);
+ wc2 = dfa->lex.wctok;
+ }
colon_warning_state |= 8;
- FETCH_WC (dfa, c1, wc1, _("unbalanced ["));
+ c1 = bracket_fetch_wc (dfa);
+ wc1 = dfa->lex.wctok;
/* Treat [x-y] as a range if x != y. */
if (wc != wc2 || wc == WEOF)
{
- if (dfa->multibyte)
- known_bracket_exp = false;
- else if (using_simple_locale (dfa))
+ if (dfa->simple_locale
+ || (isasciidigit (c) & isasciidigit (c2)))
{
- int ci;
- for (ci = c; ci <= c2; ci++)
- setbit (ci, ccl);
- if (dfa->syntax.case_fold)
- {
- int uc = toupper (c);
- int uc2 = toupper (c2);
- for (ci = 0; ci < NOTCHAR; ci++)
- {
- int uci = toupper (ci);
- if (uc <= uci && uci <= uc2)
- setbit (ci, ccl);
- }
- }
+ for (int ci = c; ci <= c2; ci++)
+ if (dfa->syntax.case_fold && isalpha (ci))
+ setbit_case_fold_c (ci, &ccl);
+ else
+ setbit (ci, &ccl);
}
else
known_bracket_exp = false;
@@ -1236,12 +1217,12 @@ parse_bracket_exp (struct dfa *dfa)
colon_warning_state |= (c == ':') ? 2 : 4;
- if (!dfa->multibyte)
+ if (!dfa->localeinfo.multibyte)
{
- if (dfa->syntax.case_fold)
- setbit_case_fold_c (c, ccl);
+ if (dfa->syntax.case_fold && isalpha (c))
+ setbit_case_fold_c (c, &ccl);
else
- setbit (c, ccl);
+ setbit (c, &ccl);
continue;
}
@@ -1250,18 +1231,18 @@ parse_bracket_exp (struct dfa *dfa)
else
{
wchar_t folded[CASE_FOLDED_BUFSIZE + 1];
- unsigned int i;
unsigned int n = (dfa->syntax.case_fold
? case_folded_counterparts (wc, folded + 1) + 1
: 1);
folded[0] = wc;
- for (i = 0; i < n; i++)
- if (!setbit_wc (folded[i], ccl))
+ for (unsigned int i = 0; i < n; i++)
+ if (!setbit_wc (folded[i], &ccl))
{
- work_mbc->chars
- = maybe_realloc (work_mbc->chars, work_mbc->nchars,
- &chars_al, sizeof *work_mbc->chars);
- work_mbc->chars[work_mbc->nchars++] = folded[i];
+ dfa->lex.brack.chars
+ = maybe_realloc (dfa->lex.brack.chars, dfa->lex.brack.nchars,
+ &dfa->lex.brack.nchars_alloc, -1,
+ sizeof *dfa->lex.brack.chars);
+ dfa->lex.brack.chars[dfa->lex.brack.nchars++] = folded[i];
}
}
}
@@ -1273,45 +1254,49 @@ parse_bracket_exp (struct dfa *dfa)
if (! known_bracket_exp)
return BACKREF;
- if (dfa->multibyte)
+ if (dfa->localeinfo.multibyte && (invert || dfa->lex.brack.nchars != 0))
{
- work_mbc->invert = invert;
- work_mbc->cset = emptyset (ccl) ? -1 : dfa_charclass_index (dfa, ccl);
+ dfa->lex.brack.invert = invert;
+ dfa->lex.brack.cset = emptyset (&ccl) ? -1 : charclass_index (dfa, &ccl);
return MBCSET;
}
if (invert)
{
- assert (!dfa->multibyte);
- notset (ccl);
+ notset (&ccl);
if (dfa->syntax.syntax_bits & RE_HAT_LISTS_NOT_NEWLINE)
- clrbit ('\n', ccl);
+ clrbit ('\n', &ccl);
}
- return CSET + dfa_charclass_index (dfa, ccl);
+ return CSET + charclass_index (dfa, &ccl);
}
-#define PUSH_LEX_STATE(s) \
- do \
- { \
- char const *lexptr_saved = dfa->lexstate.lexptr; \
- size_t lexleft_saved = dfa->lexstate.lexleft; \
- dfa->lexstate.lexptr = (s); \
- dfa->lexstate.lexleft = strlen (dfa->lexstate.lexptr)
+struct lexptr
+{
+ char const *ptr;
+ size_t left;
+};
+
+static void
+push_lex_state (struct dfa *dfa, struct lexptr *ls, char const *s)
+{
+ ls->ptr = dfa->lex.ptr;
+ ls->left = dfa->lex.left;
+ dfa->lex.ptr = s;
+ dfa->lex.left = strlen (s);
+}
-#define POP_LEX_STATE() \
- dfa->lexstate.lexptr = lexptr_saved; \
- dfa->lexstate.lexleft = lexleft_saved; \
- } \
- while (false)
+static void
+pop_lex_state (struct dfa *dfa, struct lexptr const *ls)
+{
+ dfa->lex.ptr = ls->ptr;
+ dfa->lex.left = ls->left;
+}
static token
lex (struct dfa *dfa)
{
- int c, c2;
bool backslash = false;
- charclass ccl;
- int i;
/* Basic plan: We fetch a character. If it's a backslash,
we set the backslash flag and go through the loop again.
@@ -1319,16 +1304,18 @@ lex (struct dfa *dfa)
main switch inside the backslash case. On the minus side,
it means that just about every case begins with
"if (backslash) ...". */
- for (i = 0; i < 2; ++i)
+ for (int i = 0; i < 2; ++i)
{
- FETCH_WC (dfa, c, dfa->lexstate.wctok, NULL);
+ if (! dfa->lex.left)
+ return dfa->lex.lasttok = END;
+ int c = fetch_wc (dfa);
switch (c)
{
case '\\':
if (backslash)
goto normal_char;
- if (dfa->lexstate.lexleft == 0)
+ if (dfa->lex.left == 0)
dfaerror (_("unfinished \\ escape"));
backslash = true;
break;
@@ -1337,28 +1324,29 @@ lex (struct dfa *dfa)
if (backslash)
goto normal_char;
if (dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_ANCHORS
- || dfa->lexstate.lasttok == END || dfa->lexstate.lasttok == LPAREN
- || dfa->lexstate.lasttok == OR)
- return dfa->lexstate.lasttok = BEGLINE;
+ || dfa->lex.lasttok == END || dfa->lex.lasttok == LPAREN
+ || dfa->lex.lasttok == OR)
+ return dfa->lex.lasttok = BEGLINE;
goto normal_char;
case '$':
if (backslash)
goto normal_char;
if (dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_ANCHORS
- || dfa->lexstate.lexleft == 0
- || (dfa->syntax.syntax_bits & RE_NO_BK_PARENS
- ? dfa->lexstate.lexleft > 0 && *dfa->lexstate.lexptr == ')'
- : dfa->lexstate.lexleft > 1 && dfa->lexstate.lexptr[0] == '\\'
- && dfa->lexstate.lexptr[1] == ')')
- || (dfa->syntax.syntax_bits & RE_NO_BK_VBAR
- ? dfa->lexstate.lexleft > 0 && *dfa->lexstate.lexptr == '|'
- : dfa->lexstate.lexleft > 1 && dfa->lexstate.lexptr[0] == '\\'
- && dfa->lexstate.lexptr[1] == '|')
+ || dfa->lex.left == 0
+ || ((dfa->lex.left
+ > !(dfa->syntax.syntax_bits & RE_NO_BK_PARENS))
+ && (dfa->lex.ptr[!(dfa->syntax.syntax_bits & RE_NO_BK_PARENS)
+ & (dfa->lex.ptr[0] == '\\')]
+ == ')'))
+ || ((dfa->lex.left
+ > !(dfa->syntax.syntax_bits & RE_NO_BK_VBAR))
+ && (dfa->lex.ptr[!(dfa->syntax.syntax_bits & RE_NO_BK_VBAR)
+ & (dfa->lex.ptr[0] == '\\')]
+ == '|'))
|| ((dfa->syntax.syntax_bits & RE_NEWLINE_ALT)
- && dfa->lexstate.lexleft > 0
- && *dfa->lexstate.lexptr == '\n'))
- return dfa->lexstate.lasttok = ENDLINE;
+ && dfa->lex.left > 0 && dfa->lex.ptr[0] == '\n'))
+ return dfa->lex.lasttok = ENDLINE;
goto normal_char;
case '1':
@@ -1372,8 +1360,8 @@ lex (struct dfa *dfa)
case '9':
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_BK_REFS))
{
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = BACKREF;
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = BACKREF;
}
goto normal_char;
@@ -1381,7 +1369,7 @@ lex (struct dfa *dfa)
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
{
/* FIXME: should be beginning of string */
- return dfa->lexstate.lasttok = BEGLINE;
+ return dfa->lex.lasttok = BEGLINE;
}
goto normal_char;
@@ -1389,28 +1377,28 @@ lex (struct dfa *dfa)
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
{
/* FIXME: should be end of string */
- return dfa->lexstate.lasttok = ENDLINE;
+ return dfa->lex.lasttok = ENDLINE;
}
goto normal_char;
case '<':
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
- return dfa->lexstate.lasttok = BEGWORD;
+ return dfa->lex.lasttok = BEGWORD;
goto normal_char;
case '>':
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
- return dfa->lexstate.lasttok = ENDWORD;
+ return dfa->lex.lasttok = ENDWORD;
goto normal_char;
case 'b':
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
- return dfa->lexstate.lasttok = LIMWORD;
+ return dfa->lex.lasttok = LIMWORD;
goto normal_char;
case 'B':
if (backslash && !(dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
- return dfa->lexstate.lasttok = NOTLIMWORD;
+ return dfa->lex.lasttok = NOTLIMWORD;
goto normal_char;
case '?':
@@ -1419,17 +1407,17 @@ lex (struct dfa *dfa)
if (backslash != ((dfa->syntax.syntax_bits & RE_BK_PLUS_QM) != 0))
goto normal_char;
if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lexstate.laststart)
+ && dfa->lex.laststart)
goto normal_char;
- return dfa->lexstate.lasttok = QMARK;
+ return dfa->lex.lasttok = QMARK;
case '*':
if (backslash)
goto normal_char;
if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lexstate.laststart)
+ && dfa->lex.laststart)
goto normal_char;
- return dfa->lexstate.lasttok = STAR;
+ return dfa->lex.lasttok = STAR;
case '+':
if (dfa->syntax.syntax_bits & RE_LIMITED_OPS)
@@ -1437,9 +1425,9 @@ lex (struct dfa *dfa)
if (backslash != ((dfa->syntax.syntax_bits & RE_BK_PLUS_QM) != 0))
goto normal_char;
if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lexstate.laststart)
+ && dfa->lex.laststart)
goto normal_char;
- return dfa->lexstate.lasttok = PLUS;
+ return dfa->lex.lasttok = PLUS;
case '{':
if (!(dfa->syntax.syntax_bits & RE_INTERVALS))
@@ -1447,7 +1435,7 @@ lex (struct dfa *dfa)
if (backslash != ((dfa->syntax.syntax_bits & RE_NO_BK_BRACES) == 0))
goto normal_char;
if (!(dfa->syntax.syntax_bits & RE_CONTEXT_INDEP_OPS)
- && dfa->lexstate.laststart)
+ && dfa->lex.laststart)
goto normal_char;
/* Cases:
@@ -1457,121 +1445,117 @@ lex (struct dfa *dfa)
{,} - 0 to infinity (same as '*')
{M,N} - M through N */
{
- char const *p = dfa->lexstate.lexptr;
- char const *lim = p + dfa->lexstate.lexleft;
- dfa->lexstate.minrep = dfa->lexstate.maxrep = -1;
- for (; p != lim && ISASCIIDIGIT (*p); p++)
- {
- if (dfa->lexstate.minrep < 0)
- dfa->lexstate.minrep = *p - '0';
- else
- dfa->lexstate.minrep = MIN (RE_DUP_MAX + 1,
- (dfa->lexstate.minrep
- * 10 + *p - '0'));
- }
+ char const *p = dfa->lex.ptr;
+ char const *lim = p + dfa->lex.left;
+ dfa->lex.minrep = dfa->lex.maxrep = -1;
+ for (; p != lim && isasciidigit (*p); p++)
+ dfa->lex.minrep = (dfa->lex.minrep < 0
+ ? *p - '0'
+ : MIN (RE_DUP_MAX + 1,
+ dfa->lex.minrep * 10 + *p - '0'));
if (p != lim)
{
if (*p != ',')
- dfa->lexstate.maxrep = dfa->lexstate.minrep;
+ dfa->lex.maxrep = dfa->lex.minrep;
else
{
- if (dfa->lexstate.minrep < 0)
- dfa->lexstate.minrep = 0;
- while (++p != lim && ISASCIIDIGIT (*p))
- {
- if (dfa->lexstate.maxrep < 0)
- dfa->lexstate.maxrep = *p - '0';
- else
- dfa->lexstate.maxrep = MIN (RE_DUP_MAX + 1,
- (dfa->lexstate.maxrep
- * 10 + *p - '0'));
- }
+ if (dfa->lex.minrep < 0)
+ dfa->lex.minrep = 0;
+ while (++p != lim && isasciidigit (*p))
+ dfa->lex.maxrep
+ = (dfa->lex.maxrep < 0
+ ? *p - '0'
+ : MIN (RE_DUP_MAX + 1,
+ dfa->lex.maxrep * 10 + *p - '0'));
}
}
if (! ((! backslash || (p != lim && *p++ == '\\'))
&& p != lim && *p++ == '}'
- && 0 <= dfa->lexstate.minrep
- && (dfa->lexstate.maxrep < 0
- || dfa->lexstate.minrep <= dfa->lexstate.maxrep)))
+ && 0 <= dfa->lex.minrep
+ && (dfa->lex.maxrep < 0
+ || dfa->lex.minrep <= dfa->lex.maxrep)))
{
if (dfa->syntax.syntax_bits & RE_INVALID_INTERVAL_ORD)
goto normal_char;
dfaerror (_("invalid content of \\{\\}"));
}
- if (RE_DUP_MAX < dfa->lexstate.maxrep)
+ if (RE_DUP_MAX < dfa->lex.maxrep)
dfaerror (_("regular expression too big"));
- dfa->lexstate.lexptr = p;
- dfa->lexstate.lexleft = lim - p;
+ dfa->lex.ptr = p;
+ dfa->lex.left = lim - p;
}
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = REPMN;
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = REPMN;
case '|':
if (dfa->syntax.syntax_bits & RE_LIMITED_OPS)
goto normal_char;
if (backslash != ((dfa->syntax.syntax_bits & RE_NO_BK_VBAR) == 0))
goto normal_char;
- dfa->lexstate.laststart = true;
- return dfa->lexstate.lasttok = OR;
+ dfa->lex.laststart = true;
+ return dfa->lex.lasttok = OR;
case '\n':
if (dfa->syntax.syntax_bits & RE_LIMITED_OPS
|| backslash || !(dfa->syntax.syntax_bits & RE_NEWLINE_ALT))
goto normal_char;
- dfa->lexstate.laststart = true;
- return dfa->lexstate.lasttok = OR;
+ dfa->lex.laststart = true;
+ return dfa->lex.lasttok = OR;
case '(':
if (backslash != ((dfa->syntax.syntax_bits & RE_NO_BK_PARENS) == 0))
goto normal_char;
- ++dfa->lexstate.parens;
- dfa->lexstate.laststart = true;
- return dfa->lexstate.lasttok = LPAREN;
+ dfa->lex.parens++;
+ dfa->lex.laststart = true;
+ return dfa->lex.lasttok = LPAREN;
case ')':
if (backslash != ((dfa->syntax.syntax_bits & RE_NO_BK_PARENS) == 0))
goto normal_char;
- if (dfa->lexstate.parens == 0
+ if (dfa->lex.parens == 0
&& dfa->syntax.syntax_bits & RE_UNMATCHED_RIGHT_PAREN_ORD)
goto normal_char;
- --dfa->lexstate.parens;
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = RPAREN;
+ dfa->lex.parens--;
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = RPAREN;
case '.':
if (backslash)
goto normal_char;
- if (dfa->multibyte)
+ if (dfa->canychar == (size_t) -1)
{
- /* In multibyte environment period must match with a single
- character not a byte. So we use ANYCHAR. */
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = ANYCHAR;
+ charclass ccl;
+ fillset (&ccl);
+ if (!(dfa->syntax.syntax_bits & RE_DOT_NEWLINE))
+ clrbit ('\n', &ccl);
+ if (dfa->syntax.syntax_bits & RE_DOT_NOT_NULL)
+ clrbit ('\0', &ccl);
+ if (dfa->localeinfo.multibyte)
+ for (int c2 = 0; c2 < NOTCHAR; c2++)
+ if (dfa->localeinfo.sbctowc[c2] == WEOF)
+ clrbit (c2, &ccl);
+ dfa->canychar = charclass_index (dfa, &ccl);
}
- zeroset (ccl);
- notset (ccl);
- if (!(dfa->syntax.syntax_bits & RE_DOT_NEWLINE))
- clrbit ('\n', ccl);
- if (dfa->syntax.syntax_bits & RE_DOT_NOT_NULL)
- clrbit ('\0', ccl);
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = CSET + dfa_charclass_index (dfa, ccl);
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = (dfa->localeinfo.multibyte
+ ? ANYCHAR
+ : CSET + dfa->canychar);
case 's':
case 'S':
if (!backslash || (dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
goto normal_char;
- if (!dfa->multibyte)
+ if (!dfa->localeinfo.multibyte)
{
- zeroset (ccl);
- for (c2 = 0; c2 < NOTCHAR; ++c2)
+ charclass ccl;
+ zeroset (&ccl);
+ for (int c2 = 0; c2 < NOTCHAR; ++c2)
if (isspace (c2))
- setbit (c2, ccl);
+ setbit (c2, &ccl);
if (c == 'S')
- notset (ccl);
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = CSET + dfa_charclass_index (dfa,
- ccl);
+ notset (&ccl);
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = CSET + charclass_index (dfa, &ccl);
}
/* FIXME: see if optimizing this, as is done with ANYCHAR and
@@ -1580,31 +1564,32 @@ lex (struct dfa *dfa)
/* \s and \S are documented to be equivalent to [[:space:]] and
[^[:space:]] respectively, so tell the lexer to process those
strings, each minus its "already processed" '['. */
- PUSH_LEX_STATE (c == 's' ? "[:space:]]" : "^[:space:]]");
-
- dfa->lexstate.lasttok = parse_bracket_exp (dfa);
-
- POP_LEX_STATE ();
+ {
+ struct lexptr ls;
+ push_lex_state (dfa, &ls, &"^[:space:]]"[c == 's']);
+ dfa->lex.lasttok = parse_bracket_exp (dfa);
+ pop_lex_state (dfa, &ls);
+ }
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok;
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok;
case 'w':
case 'W':
if (!backslash || (dfa->syntax.syntax_bits & RE_NO_GNU_OPS))
goto normal_char;
- if (!dfa->multibyte)
+ if (!dfa->localeinfo.multibyte)
{
- zeroset (ccl);
- for (c2 = 0; c2 < NOTCHAR; ++c2)
- if (unibyte_word_constituent (c2))
- setbit (c2, ccl);
+ charclass ccl;
+ zeroset (&ccl);
+ for (int c2 = 0; c2 < NOTCHAR; ++c2)
+ if (dfa->syntax.sbit[c2] == CTX_LETTER)
+ setbit (c2, &ccl);
if (c == 'W')
- notset (ccl);
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = CSET + dfa_charclass_index (dfa,
- ccl);
+ notset (&ccl);
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = CSET + charclass_index (dfa, &ccl);
}
/* FIXME: see if optimizing this, as is done with ANYCHAR and
@@ -1613,38 +1598,39 @@ lex (struct dfa *dfa)
/* \w and \W are documented to be equivalent to [_[:alnum:]] and
[^_[:alnum:]] respectively, so tell the lexer to process those
strings, each minus its "already processed" '['. */
- PUSH_LEX_STATE (c == 'w' ? "_[:alnum:]]" : "^_[:alnum:]]");
-
- dfa->lexstate.lasttok = parse_bracket_exp (dfa);
-
- POP_LEX_STATE ();
+ {
+ struct lexptr ls;
+ push_lex_state (dfa, &ls, &"^_[:alnum:]]"[c == 'w']);
+ dfa->lex.lasttok = parse_bracket_exp (dfa);
+ pop_lex_state (dfa, &ls);
+ }
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok;
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok;
case '[':
if (backslash)
goto normal_char;
- dfa->lexstate.laststart = false;
- return dfa->lexstate.lasttok = parse_bracket_exp (dfa);
+ dfa->lex.laststart = false;
+ return dfa->lex.lasttok = parse_bracket_exp (dfa);
default:
normal_char:
- dfa->lexstate.laststart = false;
+ dfa->lex.laststart = false;
/* For multibyte character sets, folding is done in atom. Always
return WCHAR. */
- if (dfa->multibyte)
- return dfa->lexstate.lasttok = WCHAR;
+ if (dfa->localeinfo.multibyte)
+ return dfa->lex.lasttok = WCHAR;
if (dfa->syntax.case_fold && isalpha (c))
{
- zeroset (ccl);
- setbit_case_fold_c (c, ccl);
- return dfa->lexstate.lasttok = CSET + dfa_charclass_index (dfa,
- ccl);
+ charclass ccl;
+ zeroset (&ccl);
+ setbit_case_fold_c (c, &ccl);
+ return dfa->lex.lasttok = CSET + charclass_index (dfa, &ccl);
}
- return dfa->lexstate.lasttok = c;
+ return dfa->lex.lasttok = c;
}
}
@@ -1655,17 +1641,17 @@ lex (struct dfa *dfa)
}
static void
-addtok_mb (struct dfa *dfa, token t, int mbprop)
+addtok_mb (struct dfa *dfa, token t, char mbprop)
{
if (dfa->talloc == dfa->tindex)
{
dfa->tokens = x2nrealloc (dfa->tokens, &dfa->talloc,
sizeof *dfa->tokens);
- if (dfa->multibyte)
+ if (dfa->localeinfo.multibyte)
dfa->multibyte_prop = xnrealloc (dfa->multibyte_prop, dfa->talloc,
sizeof *dfa->multibyte_prop);
}
- if (dfa->multibyte)
+ if (dfa->localeinfo.multibyte)
dfa->multibyte_prop[dfa->tindex] = mbprop;
dfa->tokens[dfa->tindex++] = t;
@@ -1678,21 +1664,21 @@ addtok_mb (struct dfa *dfa, token t, int mbprop)
case CAT:
case OR:
- --dfa->parsestate.depth;
+ dfa->parse.depth--;
break;
case BACKREF:
dfa->fast = false;
- /* fallthrough */
+ FALLTHROUGH;
default:
- ++dfa->nleaves;
- /* fallthrough */
+ dfa->nleaves++;
+ FALLTHROUGH;
case EMPTY:
- ++dfa->parsestate.depth;
+ dfa->parse.depth++;
break;
}
- if (dfa->parsestate.depth > dfa->depth)
- dfa->depth = dfa->parsestate.depth;
+ if (dfa->parse.depth > dfa->depth)
+ dfa->depth = dfa->parse.depth;
}
static void addtok_wc (struct dfa *dfa, wint_t wc);
@@ -1702,28 +1688,26 @@ static void addtok_wc (struct dfa *dfa, wint_t wc);
static void
addtok (struct dfa *dfa, token t)
{
- if (dfa->multibyte && t == MBCSET)
+ if (dfa->localeinfo.multibyte && t == MBCSET)
{
bool need_or = false;
- struct mb_char_classes *work_mbc = &dfa->mbcsets[dfa->nmbcsets - 1];
- size_t i;
/* Extract wide characters into alternations for better performance.
This does not require UTF-8. */
- for (i = 0; i < work_mbc->nchars; i++)
+ for (ptrdiff_t i = 0; i < dfa->lex.brack.nchars; i++)
{
- addtok_wc (dfa, work_mbc->chars[i]);
+ addtok_wc (dfa, dfa->lex.brack.chars[i]);
if (need_or)
addtok (dfa, OR);
need_or = true;
}
- work_mbc->nchars = 0;
+ dfa->lex.brack.nchars = 0;
- /* Characters have been handled above, so it is possible
- that the mbcset is empty now. Do nothing in that case. */
- if (work_mbc->cset != -1)
+ /* Wide characters have been handled above, so it is possible
+ that the set is empty now. Do nothing in that case. */
+ if (dfa->lex.brack.cset != -1)
{
- addtok (dfa, CSET + work_mbc->cset);
+ addtok (dfa, CSET + dfa->lex.brack.cset);
if (need_or)
addtok (dfa, OR);
}
@@ -1745,23 +1729,22 @@ addtok_wc (struct dfa *dfa, wint_t wc)
{
unsigned char buf[MB_LEN_MAX];
mbstate_t s = { 0 };
- int i;
size_t stored_bytes = wcrtomb ((char *) buf, wc, &s);
if (stored_bytes != (size_t) -1)
- dfa->lexstate.cur_mb_len = stored_bytes;
+ dfa->lex.cur_mb_len = stored_bytes;
else
{
/* This is merely stop-gap. buf[0] is undefined, yet skipping
the addtok_mb call altogether can corrupt the heap. */
- dfa->lexstate.cur_mb_len = 1;
+ dfa->lex.cur_mb_len = 1;
buf[0] = 0;
}
- addtok_mb (dfa, buf[0], dfa->lexstate.cur_mb_len == 1 ? 3 : 1);
- for (i = 1; i < dfa->lexstate.cur_mb_len; i++)
+ addtok_mb (dfa, buf[0], dfa->lex.cur_mb_len == 1 ? 3 : 1);
+ for (int i = 1; i < dfa->lex.cur_mb_len; i++)
{
- addtok_mb (dfa, buf[i], i == dfa->lexstate.cur_mb_len - 1 ? 2 : 0);
+ addtok_mb (dfa, buf[i], i == dfa->lex.cur_mb_len - 1 ? 2 : 0);
addtok (dfa, CAT);
}
}
@@ -1786,22 +1769,20 @@ add_utf8_anychar (struct dfa *dfa)
CHARCLASS_INIT (0, 0, 0, 0, 0, 0, 0, 0xff0000)
};
const unsigned int n = sizeof (utf8_classes) / sizeof (utf8_classes[0]);
- unsigned int i;
/* Define the five character classes that are needed below. */
if (dfa->utf8_anychar_classes[0] == 0)
- for (i = 0; i < n; i++)
+ for (unsigned int i = 0; i < n; i++)
{
- charclass c;
- copyset (utf8_classes[i], c);
+ charclass c = utf8_classes[i];
if (i == 1)
{
if (!(dfa->syntax.syntax_bits & RE_DOT_NEWLINE))
- clrbit ('\n', c);
+ clrbit ('\n', &c);
if (dfa->syntax.syntax_bits & RE_DOT_NOT_NULL)
- clrbit ('\0', c);
+ clrbit ('\0', &c);
}
- dfa->utf8_anychar_classes[i] = CSET + dfa_charclass_index (dfa, c);
+ dfa->utf8_anychar_classes[i] = CSET + charclass_index (dfa, &c);
}
/* A valid UTF-8 character is
@@ -1814,6 +1795,7 @@ add_utf8_anychar (struct dfa *dfa)
which I'll write more concisely "B|CA|DAA|EAAA". Factor the [0x00-0x7f]
and you get "B|(C|(D|EA)A)A". And since the token buffer is in reverse
Polish notation, you get "B C D E A CAT OR A CAT OR A CAT OR". */
+ unsigned int i;
for (i = 1; i < n; i++)
addtok (dfa, dfa->utf8_anychar_classes[i]);
while (--i > 1)
@@ -1862,20 +1844,20 @@ add_utf8_anychar (struct dfa *dfa)
static void
atom (struct dfa *dfa)
{
- if (dfa->parsestate.tok == WCHAR)
+ if (dfa->parse.tok == WCHAR)
{
- if (dfa->lexstate.wctok == WEOF)
+ if (dfa->lex.wctok == WEOF)
addtok (dfa, BACKREF);
else
{
- addtok_wc (dfa, dfa->lexstate.wctok);
+ addtok_wc (dfa, dfa->lex.wctok);
if (dfa->syntax.case_fold)
{
wchar_t folded[CASE_FOLDED_BUFSIZE];
- unsigned int i, n = case_folded_counterparts (dfa->lexstate.wctok,
- folded);
- for (i = 0; i < n; i++)
+ unsigned int n = case_folded_counterparts (dfa->lex.wctok,
+ folded);
+ for (unsigned int i = 0; i < n; i++)
{
addtok_wc (dfa, folded[i]);
addtok (dfa, OR);
@@ -1883,9 +1865,9 @@ atom (struct dfa *dfa)
}
}
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
}
- else if (dfa->parsestate.tok == ANYCHAR && using_utf8)
+ else if (dfa->parse.tok == ANYCHAR && dfa->localeinfo.using_utf8)
{
/* For UTF-8 expand the period to a series of CSETs that define a valid
UTF-8 character. This avoids using the slow multibyte path. I'm
@@ -1895,26 +1877,25 @@ atom (struct dfa *dfa)
UTF-8: it is the most used, and the structure of the encoding
makes the correctness more obvious. */
add_utf8_anychar (dfa);
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
}
- else if ((dfa->parsestate.tok >= 0 && dfa->parsestate.tok < NOTCHAR)
- || dfa->parsestate.tok >= CSET || dfa->parsestate.tok == BACKREF
- || dfa->parsestate.tok == BEGLINE || dfa->parsestate.tok == ENDLINE
- || dfa->parsestate.tok == BEGWORD || dfa->parsestate.tok == ANYCHAR
- || dfa->parsestate.tok == MBCSET || dfa->parsestate.tok == ENDWORD
- || dfa->parsestate.tok == LIMWORD
- || dfa->parsestate.tok == NOTLIMWORD)
+ else if ((0 <= dfa->parse.tok && dfa->parse.tok < NOTCHAR)
+ || dfa->parse.tok >= CSET || dfa->parse.tok == BACKREF
+ || dfa->parse.tok == BEGLINE || dfa->parse.tok == ENDLINE
+ || dfa->parse.tok == BEGWORD || dfa->parse.tok == ANYCHAR
+ || dfa->parse.tok == MBCSET || dfa->parse.tok == ENDWORD
+ || dfa->parse.tok == LIMWORD || dfa->parse.tok == NOTLIMWORD)
{
- addtok (dfa, dfa->parsestate.tok);
- dfa->parsestate.tok = lex (dfa);
+ addtok (dfa, dfa->parse.tok);
+ dfa->parse.tok = lex (dfa);
}
- else if (dfa->parsestate.tok == LPAREN)
+ else if (dfa->parse.tok == LPAREN)
{
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
regexp (dfa);
- if (dfa->parsestate.tok != RPAREN)
+ if (dfa->parse.tok != RPAREN)
dfaerror (_("unbalanced ("));
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
}
else
addtok (dfa, EMPTY);
@@ -1924,8 +1905,6 @@ atom (struct dfa *dfa)
static size_t _GL_ATTRIBUTE_PURE
nsubtoks (struct dfa const *dfa, size_t tindex)
{
- size_t ntoks1;
-
switch (dfa->tokens[tindex - 1])
{
default:
@@ -1936,8 +1915,10 @@ nsubtoks (struct dfa const *dfa, size_t tindex)
return 1 + nsubtoks (dfa, tindex - 1);
case CAT:
case OR:
- ntoks1 = nsubtoks (dfa, tindex - 1);
- return 1 + ntoks1 + nsubtoks (dfa, tindex - 1 - ntoks1);
+ {
+ size_t ntoks1 = nsubtoks (dfa, tindex - 1);
+ return 1 + ntoks1 + nsubtoks (dfa, tindex - 1 - ntoks1);
+ }
}
}
@@ -1945,57 +1926,53 @@ nsubtoks (struct dfa const *dfa, size_t tindex)
static void
copytoks (struct dfa *dfa, size_t tindex, size_t ntokens)
{
- size_t i;
-
- if (dfa->multibyte)
- for (i = 0; i < ntokens; ++i)
- addtok_mb (dfa, dfa->tokens[tindex + i], dfa->multibyte_prop[tindex + i]);
+ if (dfa->localeinfo.multibyte)
+ for (size_t i = 0; i < ntokens; ++i)
+ addtok_mb (dfa, dfa->tokens[tindex + i],
+ dfa->multibyte_prop[tindex + i]);
else
- for (i = 0; i < ntokens; ++i)
+ for (size_t i = 0; i < ntokens; ++i)
addtok_mb (dfa, dfa->tokens[tindex + i], 3);
}
static void
closure (struct dfa *dfa)
{
- int i;
- size_t tindex, ntokens;
-
atom (dfa);
- while (dfa->parsestate.tok == QMARK || dfa->parsestate.tok == STAR
- || dfa->parsestate.tok == PLUS || dfa->parsestate.tok == REPMN)
- if (dfa->parsestate.tok == REPMN
- && (dfa->lexstate.minrep || dfa->lexstate.maxrep))
+ while (dfa->parse.tok == QMARK || dfa->parse.tok == STAR
+ || dfa->parse.tok == PLUS || dfa->parse.tok == REPMN)
+ if (dfa->parse.tok == REPMN && (dfa->lex.minrep || dfa->lex.maxrep))
{
- ntokens = nsubtoks (dfa, dfa->tindex);
- tindex = dfa->tindex - ntokens;
- if (dfa->lexstate.maxrep < 0)
+ size_t ntokens = nsubtoks (dfa, dfa->tindex);
+ size_t tindex = dfa->tindex - ntokens;
+ if (dfa->lex.maxrep < 0)
addtok (dfa, PLUS);
- if (dfa->lexstate.minrep == 0)
+ if (dfa->lex.minrep == 0)
addtok (dfa, QMARK);
- for (i = 1; i < dfa->lexstate.minrep; ++i)
+ int i;
+ for (i = 1; i < dfa->lex.minrep; i++)
{
copytoks (dfa, tindex, ntokens);
addtok (dfa, CAT);
}
- for (; i < dfa->lexstate.maxrep; ++i)
+ for (; i < dfa->lex.maxrep; i++)
{
copytoks (dfa, tindex, ntokens);
addtok (dfa, QMARK);
addtok (dfa, CAT);
}
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
}
- else if (dfa->parsestate.tok == REPMN)
+ else if (dfa->parse.tok == REPMN)
{
dfa->tindex -= nsubtoks (dfa, dfa->tindex);
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
closure (dfa);
}
else
{
- addtok (dfa, dfa->parsestate.tok);
- dfa->parsestate.tok = lex (dfa);
+ addtok (dfa, dfa->parse.tok);
+ dfa->parse.tok = lex (dfa);
}
}
@@ -2003,8 +1980,8 @@ static void
branch (struct dfa* dfa)
{
closure (dfa);
- while (dfa->parsestate.tok != RPAREN && dfa->parsestate.tok != OR
- && dfa->parsestate.tok >= 0)
+ while (dfa->parse.tok != RPAREN && dfa->parse.tok != OR
+ && dfa->parse.tok >= 0)
{
closure (dfa);
addtok (dfa, CAT);
@@ -2015,9 +1992,9 @@ static void
regexp (struct dfa *dfa)
{
branch (dfa);
- while (dfa->parsestate.tok == OR)
+ while (dfa->parse.tok == OR)
{
- dfa->parsestate.tok = lex (dfa);
+ dfa->parse.tok = lex (dfa);
branch (dfa);
addtok (dfa, OR);
}
@@ -2029,26 +2006,20 @@ regexp (struct dfa *dfa)
static void
dfaparse (char const *s, size_t len, struct dfa *d)
{
- d->lexstate.lexptr = s;
- d->lexstate.lexleft = len;
- d->lexstate.lasttok = END;
- d->lexstate.laststart = true;
- d->lexstate.parens = 0;
- if (d->multibyte)
- {
- d->lexstate.cur_mb_len = 0;
- memset (&d->mbs, 0, sizeof d->mbs);
- }
+ d->lex.ptr = s;
+ d->lex.left = len;
+ d->lex.lasttok = END;
+ d->lex.laststart = true;
if (!d->syntax.syntax_bits_set)
dfaerror (_("no syntax specified"));
- d->parsestate.tok = lex (d);
- d->parsestate.depth = d->depth;
+ d->parse.tok = lex (d);
+ d->parse.depth = d->depth;
regexp (d);
- if (d->parsestate.tok != END)
+ if (d->parse.tok != END)
dfaerror (_("unbalanced )"));
addtok (d, END - d->nregexps);
@@ -2069,11 +2040,12 @@ copy (position_set const *src, position_set *dst)
if (dst->alloc < src->nelem)
{
free (dst->elems);
- dst->alloc = src->nelem;
- dst->elems = x2nrealloc (NULL, &dst->alloc, sizeof *dst->elems);
+ dst->elems = xpalloc (NULL, &dst->alloc, src->nelem - dst->alloc, -1,
+ sizeof *dst->elems);
}
- memcpy (dst->elems, src->elems, src->nelem * sizeof *dst->elems);
dst->nelem = src->nelem;
+ if (src->nelem != 0)
+ memcpy (dst->elems, src->elems, src->nelem * sizeof *dst->elems);
}
static void
@@ -2091,73 +2063,114 @@ alloc_position_set (position_set *s, size_t size)
static void
insert (position p, position_set *s)
{
- size_t count = s->nelem;
- size_t lo = 0, hi = count;
- size_t i;
+ ptrdiff_t count = s->nelem;
+ ptrdiff_t lo = 0, hi = count;
while (lo < hi)
{
- size_t mid = (lo + hi) >> 1;
+ ptrdiff_t mid = (lo + hi) >> 1;
if (s->elems[mid].index > p.index)
lo = mid + 1;
+ else if (s->elems[mid].index == p.index)
+ {
+ s->elems[mid].constraint |= p.constraint;
+ return;
+ }
else
hi = mid;
}
- if (lo < count && p.index == s->elems[lo].index)
- {
- s->elems[lo].constraint |= p.constraint;
- return;
- }
-
- s->elems = maybe_realloc (s->elems, count, &s->alloc, sizeof *s->elems);
- for (i = count; i > lo; i--)
+ s->elems = maybe_realloc (s->elems, count, &s->alloc, -1, sizeof *s->elems);
+ for (ptrdiff_t i = count; i > lo; i--)
s->elems[i] = s->elems[i - 1];
s->elems[lo] = p;
++s->nelem;
}
-/* Merge two sets of positions into a third. The result is exactly as if
- the positions of both sets were inserted into an initially empty set. */
+/* Merge S1 and S2 (with the additional constraint C2) into M. The
+ result is as if the positions of S1, and of S2 with the additional
+ constraint C2, were inserted into an initially empty set. */
static void
-merge (position_set const *s1, position_set const *s2, position_set *m)
+merge_constrained (position_set const *s1, position_set const *s2,
+ unsigned int c2, position_set *m)
{
- size_t i = 0, j = 0;
+ ptrdiff_t i = 0, j = 0;
- if (m->alloc < s1->nelem + s2->nelem)
+ if (m->alloc - s1->nelem < s2->nelem)
{
free (m->elems);
- m->elems = maybe_realloc (NULL, s1->nelem + s2->nelem, &m->alloc,
- sizeof *m->elems);
+ m->alloc = s1->nelem;
+ m->elems = xpalloc (NULL, &m->alloc, s2->nelem, -1, sizeof *m->elems);
}
m->nelem = 0;
- while (i < s1->nelem && j < s2->nelem)
- if (s1->elems[i].index > s2->elems[j].index)
- m->elems[m->nelem++] = s1->elems[i++];
- else if (s1->elems[i].index < s2->elems[j].index)
- m->elems[m->nelem++] = s2->elems[j++];
+ while (i < s1->nelem || j < s2->nelem)
+ if (! (j < s2->nelem)
+ || (i < s1->nelem && s1->elems[i].index >= s2->elems[j].index))
+ {
+ unsigned int c = ((i < s1->nelem && j < s2->nelem
+ && s1->elems[i].index == s2->elems[j].index)
+ ? s2->elems[j++].constraint & c2
+ : 0);
+ m->elems[m->nelem].index = s1->elems[i].index;
+ m->elems[m->nelem++].constraint = s1->elems[i++].constraint | c;
+ }
else
{
- m->elems[m->nelem] = s1->elems[i++];
- m->elems[m->nelem++].constraint |= s2->elems[j++].constraint;
+ if (s2->elems[j].constraint & c2)
+ {
+ m->elems[m->nelem].index = s2->elems[j].index;
+ m->elems[m->nelem++].constraint = s2->elems[j].constraint & c2;
+ }
+ j++;
}
- while (i < s1->nelem)
- m->elems[m->nelem++] = s1->elems[i++];
- while (j < s2->nelem)
- m->elems[m->nelem++] = s2->elems[j++];
}
-/* Delete a position from a set. */
+/* Merge two sets of positions into a third. The result is exactly as if
+ the positions of both sets were inserted into an initially empty set. */
static void
-delete (position p, position_set *s)
+merge (position_set const *s1, position_set const *s2, position_set *m)
{
- size_t i;
+ merge_constrained (s1, s2, -1, m);
+}
- for (i = 0; i < s->nelem; ++i)
- if (p.index == s->elems[i].index)
- break;
- if (i < s->nelem)
- for (--s->nelem; i < s->nelem; ++i)
- s->elems[i] = s->elems[i + 1];
+/* Delete a position from a set. Return the nonzero constraint of the
+ deleted position, or zero if there was no such position. */
+static unsigned int
+delete (size_t del, position_set *s)
+{
+ size_t count = s->nelem;
+ size_t lo = 0, hi = count;
+ while (lo < hi)
+ {
+ size_t mid = (lo + hi) >> 1;
+ if (s->elems[mid].index > del)
+ lo = mid + 1;
+ else if (s->elems[mid].index == del)
+ {
+ unsigned int c = s->elems[mid].constraint;
+ size_t i;
+ for (i = mid; i + 1 < count; i++)
+ s->elems[i] = s->elems[i + 1];
+ s->nelem = i;
+ return c;
+ }
+ else
+ hi = mid;
+ }
+ return 0;
+}
+
+/* Replace a position with the followed set. */
+static void
+replace (position_set *dst, size_t del, position_set *add,
+ unsigned int constraint, position_set *tmp)
+{
+ unsigned int c = delete (del, dst) & constraint;
+
+ if (c)
+ {
+ copy (dst, tmp);
+ merge_constrained (tmp, add, c, dst);
+ }
}
/* Find the index of the state corresponding to the given position set with
@@ -2168,8 +2181,7 @@ state_index (struct dfa *d, position_set const *s, int context)
{
size_t hash = 0;
int constraint = 0;
- state_num i, j;
- bool curr_dependent = false;
+ state_num i;
token first_end = 0;
for (i = 0; i < s->nelem; ++i)
@@ -2181,6 +2193,7 @@ state_index (struct dfa *d, position_set const *s, int context)
if (hash != d->states[i].hash || s->nelem != d->states[i].elems.nelem
|| context != d->states[i].context)
continue;
+ state_num j;
for (j = 0; j < s->nelem; ++j)
if (s->elems[j].constraint != d->states[i].elems.elems[j].constraint
|| s->elems[j].index != d->states[i].elems.elems[j].index)
@@ -2191,7 +2204,7 @@ state_index (struct dfa *d, position_set const *s, int context)
#ifdef DEBUG
fprintf (stderr, "new state %zd\n nextpos:", i);
- for (j = 0; j < s->nelem; ++j)
+ for (state_num j = 0; j < s->nelem; j++)
{
fprintf (stderr, " %zu:", s->elems[j].index);
prtok (d->tokens[s->elems[j].index]);
@@ -2211,40 +2224,28 @@ state_index (struct dfa *d, position_set const *s, int context)
fprintf (stderr, "\n");
#endif
- for (j = 0; j < s->nelem; ++j)
+ for (state_num j = 0; j < s->nelem; j++)
{
int c = s->elems[j].constraint;
if (d->tokens[s->elems[j].index] < 0)
{
- if (SUCCEEDS_IN_CONTEXT (c, context, CTX_ANY))
+ if (succeeds_in_context (c, context, CTX_ANY))
constraint |= c;
if (!first_end)
first_end = d->tokens[s->elems[j].index];
}
else if (d->tokens[s->elems[j].index] == BACKREF)
constraint = NO_CONSTRAINT;
- if (d->multibyte && d->tokens[s->elems[j].index] == ANYCHAR)
- {
- int acceptable
- = ((SUCCEEDS_IN_CONTEXT (c, context, CTX_NEWLINE)
- ? CTX_NEWLINE : 0)
- | (SUCCEEDS_IN_CONTEXT (c, context, CTX_LETTER)
- ? CTX_LETTER : 0)
- | (SUCCEEDS_IN_CONTEXT (c, context, CTX_NONE)
- ? CTX_NONE : 0));
- curr_dependent |= acceptable && (context & ~acceptable);
- }
}
/* Create a new state. */
- d->states = maybe_realloc (d->states, d->sindex, &d->salloc,
+ d->states = maybe_realloc (d->states, d->sindex, &d->salloc, -1,
sizeof *d->states);
d->states[i].hash = hash;
alloc_position_set (&d->states[i].elems, s->nelem);
copy (s, &d->states[i].elems);
d->states[i].context = context;
- d->states[i].curr_dependent = curr_dependent;
d->states[i].constraint = constraint;
d->states[i].first_end = first_end;
d->states[i].mbps.nelem = 0;
@@ -2262,83 +2263,67 @@ state_index (struct dfa *d, position_set const *s, int context)
constraint. Repeat exhaustively until no funny positions are left.
S->elems must be large enough to hold the result. */
static void
-epsclosure (position_set *s, struct dfa const *d, char *visited)
+epsclosure (position_set *initial, struct dfa const *d)
{
- size_t i, j;
- position p, old;
- bool initialized = false;
-
- for (i = 0; i < s->nelem; ++i)
- if (d->tokens[s->elems[i].index] >= NOTCHAR
- && d->tokens[s->elems[i].index] != BACKREF
- && d->tokens[s->elems[i].index] != ANYCHAR
- && d->tokens[s->elems[i].index] != MBCSET
- && d->tokens[s->elems[i].index] < CSET)
+ position_set tmp;
+ alloc_position_set (&tmp, d->nleaves);
+ for (size_t i = 0; i < d->tindex; ++i)
+ if (d->follows[i].nelem > 0 && d->tokens[i] >= NOTCHAR
+ && d->tokens[i] != BACKREF && d->tokens[i] != ANYCHAR
+ && d->tokens[i] != MBCSET && d->tokens[i] < CSET)
{
- if (!initialized)
- {
- memset (visited, 0, d->tindex * sizeof (*visited));
- initialized = true;
- }
- old = s->elems[i];
- p.constraint = old.constraint;
- delete (s->elems[i], s);
- if (visited[old.index])
- {
- --i;
- continue;
- }
- visited[old.index] = 1;
- switch (d->tokens[old.index])
+ unsigned int constraint;
+ switch (d->tokens[i])
{
case BEGLINE:
- p.constraint &= BEGLINE_CONSTRAINT;
+ constraint = BEGLINE_CONSTRAINT;
break;
case ENDLINE:
- p.constraint &= ENDLINE_CONSTRAINT;
+ constraint = ENDLINE_CONSTRAINT;
break;
case BEGWORD:
- p.constraint &= BEGWORD_CONSTRAINT;
+ constraint = BEGWORD_CONSTRAINT;
break;
case ENDWORD:
- p.constraint &= ENDWORD_CONSTRAINT;
+ constraint = ENDWORD_CONSTRAINT;
break;
case LIMWORD:
- p.constraint &= LIMWORD_CONSTRAINT;
+ constraint = LIMWORD_CONSTRAINT;
break;
case NOTLIMWORD:
- p.constraint &= NOTLIMWORD_CONSTRAINT;
+ constraint = NOTLIMWORD_CONSTRAINT;
break;
default:
+ constraint = NO_CONSTRAINT;
break;
}
- for (j = 0; j < d->follows[old.index].nelem; ++j)
- {
- p.index = d->follows[old.index].elems[j].index;
- insert (p, s);
- }
- /* Force rescan to start at the beginning. */
- i = -1;
+
+ delete (i, &d->follows[i]);
+
+ for (size_t j = 0; j < d->tindex; j++)
+ if (i != j && d->follows[j].nelem > 0)
+ replace (&d->follows[j], i, &d->follows[i], constraint, &tmp);
+
+ replace (initial, i, &d->follows[i], constraint, &tmp);
}
+ free (tmp.elems);
}
/* Returns the set of contexts for which there is at least one
character included in C. */
static int
-charclass_context (struct dfa const *dfa, charclass c)
+charclass_context (struct dfa const *dfa, charclass const *c)
{
int context = 0;
- unsigned int j;
-
- if (tstbit (dfa->syntax.eolbyte, c))
- context |= CTX_NEWLINE;
- for (j = 0; j < CHARCLASS_WORDS; ++j)
+ for (unsigned int j = 0; j < CHARCLASS_WORDS; ++j)
{
- if (c[j] & dfa->syntax.letters[j])
+ if (c->w[j] & dfa->syntax.newline.w[j])
+ context |= CTX_NEWLINE;
+ if (c->w[j] & dfa->syntax.letters.w[j])
context |= CTX_LETTER;
- if (c[j] & ~(dfa->syntax.letters[j] | dfa->syntax.newline[j]))
+ if (c->w[j] & ~(dfa->syntax.letters.w[j] | dfa->syntax.newline.w[j]))
context |= CTX_NONE;
}
@@ -2355,13 +2340,12 @@ static int _GL_ATTRIBUTE_PURE
state_separate_contexts (position_set const *s)
{
int separate_contexts = 0;
- size_t j;
- for (j = 0; j < s->nelem; ++j)
+ for (size_t j = 0; j < s->nelem; j++)
{
- if (PREV_NEWLINE_DEPENDENT (s->elems[j].constraint))
+ if (prev_newline_dependent (s->elems[j].constraint))
separate_contexts |= CTX_NEWLINE;
- if (PREV_LETTER_DEPENDENT (s->elems[j].constraint))
+ if (prev_letter_dependent (s->elems[j].constraint))
separate_contexts |= CTX_LETTER;
}
@@ -2441,16 +2425,11 @@ dfaanalyze (struct dfa *d, bool searchflag)
size_t nlastpos;
} *stkalloc = xnmalloc (d->depth, sizeof *stkalloc), *stk = stkalloc;
- position_set tmp; /* Temporary set for merging sets. */
position_set merged; /* Result of merging sets. */
- int separate_contexts; /* Context wanted by some position. */
- size_t i, j;
- position *pos;
- char *visited = xnmalloc (d->tindex, sizeof *visited);
#ifdef DEBUG
fprintf (stderr, "dfaanalyze:\n");
- for (i = 0; i < d->tindex; ++i)
+ for (size_t i = 0; i < d->tindex; ++i)
{
fprintf (stderr, " %zu:", i);
prtok (d->tokens[i]);
@@ -2462,7 +2441,7 @@ dfaanalyze (struct dfa *d, bool searchflag)
alloc_position_set (&merged, d->nleaves);
d->follows = xcalloc (d->tindex, sizeof *d->follows);
- for (i = 0; i < d->tindex; ++i)
+ for (size_t i = 0; i < d->tindex; ++i)
{
switch (d->tokens[i])
{
@@ -2479,16 +2458,18 @@ dfaanalyze (struct dfa *d, bool searchflag)
case PLUS:
/* Every element in the firstpos of the argument is in the follow
of every element in the lastpos. */
- tmp.nelem = stk[-1].nfirstpos;
- tmp.elems = firstpos;
- pos = lastpos;
- for (j = 0; j < stk[-1].nlastpos; ++j)
- {
- merge (&tmp, &d->follows[pos[j].index], &merged);
- copy (&merged, &d->follows[pos[j].index]);
- }
- /* fallthrough */
-
+ {
+ position_set tmp;
+ tmp.nelem = stk[-1].nfirstpos;
+ tmp.elems = firstpos;
+ position *pos = lastpos;
+ for (size_t j = 0; j < stk[-1].nlastpos; j++)
+ {
+ merge (&tmp, &d->follows[pos[j].index], &merged);
+ copy (&merged, &d->follows[pos[j].index]);
+ }
+ }
+ FALLTHROUGH;
case QMARK:
/* A QMARK or STAR node is automatically nullable. */
if (d->tokens[i] != PLUS)
@@ -2498,14 +2479,17 @@ dfaanalyze (struct dfa *d, bool searchflag)
case CAT:
/* Every element in the firstpos of the second argument is in the
follow of every element in the lastpos of the first argument. */
- tmp.nelem = stk[-1].nfirstpos;
- tmp.elems = firstpos;
- pos = lastpos + stk[-1].nlastpos;
- for (j = 0; j < stk[-2].nlastpos; ++j)
- {
- merge (&tmp, &d->follows[pos[j].index], &merged);
- copy (&merged, &d->follows[pos[j].index]);
- }
+ {
+ position_set tmp;
+ tmp.nelem = stk[-1].nfirstpos;
+ tmp.elems = firstpos;
+ position *pos = lastpos + stk[-1].nlastpos;
+ for (size_t j = 0; j < stk[-2].nlastpos; j++)
+ {
+ merge (&tmp, &d->follows[pos[j].index], &merged);
+ copy (&merged, &d->follows[pos[j].index]);
+ }
+ }
/* The firstpos of a CAT node is the firstpos of the first argument,
union that of the second argument if the first is nullable. */
@@ -2520,8 +2504,8 @@ dfaanalyze (struct dfa *d, bool searchflag)
stk[-2].nlastpos += stk[-1].nlastpos;
else
{
- pos = lastpos + stk[-2].nlastpos;
- for (j = stk[-1].nlastpos; j-- > 0;)
+ position *pos = lastpos + stk[-2].nlastpos;
+ for (size_t j = stk[-1].nlastpos; j-- > 0;)
pos[j] = lastpos[j];
lastpos += stk[-2].nlastpos;
stk[-2].nlastpos = stk[-1].nlastpos;
@@ -2560,8 +2544,6 @@ dfaanalyze (struct dfa *d, bool searchflag)
firstpos->index = lastpos->index = i;
firstpos->constraint = lastpos->constraint = NO_CONSTRAINT;
- /* Allocate the follow set for this position. */
- alloc_position_set (&d->follows[i], 1);
break;
}
#ifdef DEBUG
@@ -2572,13 +2554,13 @@ dfaanalyze (struct dfa *d, bool searchflag)
fprintf (stderr,
stk[-1].nullable ? " nullable: yes\n" : " nullable: no\n");
fprintf (stderr, " firstpos:");
- for (j = stk[-1].nfirstpos; j-- > 0;)
+ for (size_t j = stk[-1].nfirstpos; j-- > 0;)
{
fprintf (stderr, " %zu:", firstpos[j].index);
prtok (d->tokens[firstpos[j].index]);
}
fprintf (stderr, "\n lastpos:");
- for (j = stk[-1].nlastpos; j-- > 0;)
+ for (size_t j = stk[-1].nlastpos; j-- > 0;)
{
fprintf (stderr, " %zu:", lastpos[j].index);
prtok (d->tokens[lastpos[j].index]);
@@ -2587,38 +2569,38 @@ dfaanalyze (struct dfa *d, bool searchflag)
#endif
}
- /* For each follow set that is the follow set of a real position, replace
- it with its epsilon closure. */
- for (i = 0; i < d->tindex; ++i)
+#ifdef DEBUG
+ for (size_t i = 0; i < d->tindex; ++i)
if (d->tokens[i] < NOTCHAR || d->tokens[i] == BACKREF
|| d->tokens[i] == ANYCHAR || d->tokens[i] == MBCSET
|| d->tokens[i] >= CSET)
{
-#ifdef DEBUG
fprintf (stderr, "follows(%zu:", i);
prtok (d->tokens[i]);
fprintf (stderr, "):");
- for (j = d->follows[i].nelem; j-- > 0;)
+ for (size_t j = d->follows[i].nelem; j-- > 0;)
{
fprintf (stderr, " %zu:", d->follows[i].elems[j].index);
prtok (d->tokens[d->follows[i].elems[j].index]);
}
putc ('\n', stderr);
-#endif
- copy (&d->follows[i], &merged);
- epsclosure (&merged, d, visited);
- copy (&merged, &d->follows[i]);
}
+#endif
/* Get the epsilon closure of the firstpos of the regexp. The result will
be the set of positions of state 0. */
merged.nelem = 0;
- for (i = 0; i < stk[-1].nfirstpos; ++i)
+ for (size_t i = 0; i < stk[-1].nfirstpos; ++i)
insert (firstpos[i], &merged);
- epsclosure (&merged, d, visited);
+
+ /* For each follow set that is the follow set of a real position, replace
+ it with its epsilon closure. */
+ epsclosure (&merged, d);
+
+ /* Context wanted by some position. */
+ int separate_contexts = state_separate_contexts (&merged);
/* Build the initial state. */
- separate_contexts = state_separate_contexts (&merged);
if (separate_contexts & CTX_NEWLINE)
state_index (d, &merged, CTX_NEWLINE);
d->initstate_notbol = d->min_trcount
@@ -2626,100 +2608,179 @@ dfaanalyze (struct dfa *d, bool searchflag)
if (separate_contexts & CTX_LETTER)
d->min_trcount = state_index (d, &merged, CTX_LETTER);
d->min_trcount++;
+ d->trcount = 0;
free (posalloc);
free (stkalloc);
free (merged.elems);
- free (visited);
}
+/* Make sure D's state arrays are large enough to hold NEW_STATE. */
+static void
+realloc_trans_if_necessary (struct dfa *d)
+{
+ state_num oldalloc = d->tralloc;
+ if (oldalloc < d->sindex)
+ {
+ state_num **realtrans = d->trans ? d->trans - 2 : NULL;
+ ptrdiff_t newalloc1 = realtrans ? d->tralloc + 2 : 0;
+ realtrans = xpalloc (realtrans, &newalloc1, d->sindex - oldalloc,
+ -1, sizeof *realtrans);
+ realtrans[0] = realtrans[1] = NULL;
+ d->trans = realtrans + 2;
+ ptrdiff_t newalloc = d->tralloc = newalloc1 - 2;
+ d->fails = xnrealloc (d->fails, newalloc, sizeof *d->fails);
+ d->success = xnrealloc (d->success, newalloc, sizeof *d->success);
+ d->newlines = xnrealloc (d->newlines, newalloc, sizeof *d->newlines);
+ if (d->localeinfo.multibyte)
+ {
+ realtrans = d->mb_trans ? d->mb_trans - 2 : NULL;
+ realtrans = xnrealloc (realtrans, newalloc1, sizeof *realtrans);
+ if (oldalloc == 0)
+ realtrans[0] = realtrans[1] = NULL;
+ d->mb_trans = realtrans + 2;
+ }
+ for (; oldalloc < newalloc; oldalloc++)
+ {
+ d->trans[oldalloc] = NULL;
+ d->fails[oldalloc] = NULL;
+ if (d->localeinfo.multibyte)
+ d->mb_trans[oldalloc] = NULL;
+ }
+ }
+}
-/* Find, for each character, the transition out of state s of d, and store
- it in the appropriate slot of trans.
+/*
+ Calculate the transition table for a new state derived from state s
+ for a compiled dfa d after input character uc, and return the new
+ state number.
- We divide the positions of s into groups (positions can appear in more
- than one group). Each group is labeled with a set of characters that
+ Do not worry about all possible input characters; calculate just the group
+ of positions that match uc. Label it with the set of characters that
every position in the group matches (taking into account, if necessary,
- preceding context information of s). For each group, find the union
- of the its elements' follows. This set is the set of positions of the
+ preceding context information of s). Then find the union
+ of these positions' follows, i.e., the set of positions of the
new state. For each character in the group's label, set the transition
on this character to be to a state corresponding to the set's positions,
and its associated backward context information, if necessary.
- If we are building a searching matcher, we include the positions of state
+ When building a searching matcher, include the positions of state
0 in every state.
- The collection of groups is constructed by building an equivalence-class
+ The group is constructed by building an equivalence-class
partition of the positions of s.
For each position, find the set of characters C that it matches. Eliminate
any characters from C that fail on grounds of backward context.
- Search through the groups, looking for a group whose label L has nonempty
+ Check whether the group's label L has nonempty
intersection with C. If L - C is nonempty, create a new group labeled
L - C and having the same positions as the current group, and set L to
- the intersection of L and C. Insert the position in this group, set
+ the intersection of L and C. Insert the position in the group, set
C = C - L, and resume scanning.
If after comparing with every group there are characters remaining in C,
create a new group labeled with the characters of C and insert this
position in that group. */
-static void
-dfastate (state_num s, struct dfa *d, state_num trans[])
+
+static state_num
+build_state (state_num s, struct dfa *d, unsigned char uc)
{
- leaf_set grps[NOTCHAR]; /* As many as will ever be needed. */
- charclass labels[NOTCHAR]; /* Labels corresponding to the groups. */
- size_t ngrps = 0; /* Number of groups actually used. */
- position pos; /* Current position being considered. */
- charclass matches; /* Set of matching characters. */
- charclass_word matchesf; /* Nonzero if matches is nonempty. */
- charclass intersect; /* Intersection with some label set. */
- charclass_word intersectf; /* Nonzero if intersect is nonempty. */
- charclass leftovers; /* Stuff in the label that didn't match. */
- charclass_word leftoversf; /* Nonzero if leftovers is nonempty. */
- position_set follows; /* Union of the follows of some group. */
+ position_set follows; /* Union of the follows of the group. */
position_set tmp; /* Temporary space for merging sets. */
- int possible_contexts; /* Contexts that this group can match. */
- int separate_contexts; /* Context that new state wants to know. */
state_num state; /* New state. */
state_num state_newline; /* New state on a newline transition. */
state_num state_letter; /* New state on a letter transition. */
- bool next_isnt_1st_byte = false; /* We can't add state0. */
- size_t i, j, k;
#ifdef DEBUG
fprintf (stderr, "build state %td\n", s);
#endif
- zeroset (matches);
+ /* A pointer to the new transition table, and the table itself. */
+ state_num **ptrans = (accepting (s, d) ? d->fails : d->trans) + s;
+ state_num *trans = *ptrans;
- for (i = 0; i < d->states[s].elems.nelem; ++i)
+ if (!trans)
{
- pos = d->states[s].elems.elems[i];
+ /* MAX_TRCOUNT is an arbitrary upper limit on the number of
+ transition tables that can exist at once, other than for
+ initial states. Often-used transition tables are quickly
+ rebuilt, whereas rarely-used ones are cleared away. */
+ if (MAX_TRCOUNT <= d->trcount)
+ {
+ for (state_num i = d->min_trcount; i < d->tralloc; i++)
+ {
+ free (d->trans[i]);
+ free (d->fails[i]);
+ d->trans[i] = d->fails[i] = NULL;
+ }
+ d->trcount = 0;
+ }
+
+ d->trcount++;
+ *ptrans = trans = xmalloc (NOTCHAR * sizeof *trans);
+
+ /* Fill transition table with a default value which means that the
+ transited state has not been calculated yet. */
+ for (int i = 0; i < NOTCHAR; i++)
+ trans[i] = -2;
+ }
+
+ /* Set up the success bits for this state. */
+ d->success[s] = 0;
+ if (accepts_in_context (d->states[s].context, CTX_NEWLINE, s, d))
+ d->success[s] |= CTX_NEWLINE;
+ if (accepts_in_context (d->states[s].context, CTX_LETTER, s, d))
+ d->success[s] |= CTX_LETTER;
+ if (accepts_in_context (d->states[s].context, CTX_NONE, s, d))
+ d->success[s] |= CTX_NONE;
+
+ /* Positions that match the input char. */
+ leaf_set group;
+ group.elems = xnmalloc (d->nleaves, sizeof *group.elems);
+ group.nelem = 0;
+
+ /* The group's label. */
+ charclass label;
+ fillset (&label);
+
+ for (size_t i = 0; i < d->states[s].elems.nelem; ++i)
+ {
+ charclass matches; /* Set of matching characters. */
+ position pos = d->states[s].elems.elems[i];
+ bool matched = false;
if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR)
- setbit (d->tokens[pos.index], matches);
+ {
+ zeroset (&matches);
+ setbit (d->tokens[pos.index], &matches);
+ if (d->tokens[pos.index] == uc)
+ matched = true;
+ }
else if (d->tokens[pos.index] >= CSET)
- copyset (d->charclasses[d->tokens[pos.index] - CSET], matches);
- else if (d->multibyte && d->tokens[pos.index] == ANYCHAR)
{
- /* ANYCHAR must match a single character, so put it to
- D->states[s].mbps which contains the positions which can
- match with a single character not a byte. If all
- positions with ANYCHAR do not depend on the context of
- the next character, put its follows instead to
+ matches = d->charclasses[d->tokens[pos.index] - CSET];
+ if (tstbit (uc, &matches))
+ matched = true;
+ }
+ else if (d->tokens[pos.index] == ANYCHAR)
+ {
+ matches = d->charclasses[d->canychar];
+ if (tstbit (uc, &matches))
+ matched = true;
+
+ /* ANYCHAR must match with a single character, so we must put
+ it to D->states[s].mbps which contains the positions which
+ can match with a single character not a byte. If all
+ positions which has ANYCHAR does not depend on context of
+ next character, we put the follows instead of it to
D->states[s].mbps to optimize. */
- if (d->states[s].curr_dependent)
- {
- if (d->states[s].mbps.nelem == 0)
- alloc_position_set (&d->states[s].mbps, 1);
- insert (pos, &d->states[s].mbps);
- }
- else if (SUCCEEDS_IN_CONTEXT (pos.constraint,
- d->states[s].context, CTX_ANY))
+ if (succeeds_in_context (pos.constraint, d->states[s].context,
+ CTX_NONE))
{
if (d->states[s].mbps.nelem == 0)
- alloc_position_set (&d->states[s].mbps, 1);
- for (j = 0; j < d->follows[pos.index].nelem; j++)
+ alloc_position_set (&d->states[s].mbps,
+ d->follows[pos.index].nelem);
+ for (size_t j = 0; j < d->follows[pos.index].nelem; j++)
insert (d->follows[pos.index].elems[j], &d->states[s].mbps);
}
}
@@ -2730,181 +2791,106 @@ dfastate (state_num s, struct dfa *d, state_num trans[])
they fail in the current context. */
if (pos.constraint != NO_CONSTRAINT)
{
- if (!SUCCEEDS_IN_CONTEXT (pos.constraint,
+ if (!succeeds_in_context (pos.constraint,
d->states[s].context, CTX_NEWLINE))
- for (j = 0; j < CHARCLASS_WORDS; ++j)
- matches[j] &= ~d->syntax.newline[j];
- if (!SUCCEEDS_IN_CONTEXT (pos.constraint,
+ for (size_t j = 0; j < CHARCLASS_WORDS; ++j)
+ matches.w[j] &= ~d->syntax.newline.w[j];
+ if (!succeeds_in_context (pos.constraint,
d->states[s].context, CTX_LETTER))
- for (j = 0; j < CHARCLASS_WORDS; ++j)
- matches[j] &= ~d->syntax.letters[j];
- if (!SUCCEEDS_IN_CONTEXT (pos.constraint,
+ for (size_t j = 0; j < CHARCLASS_WORDS; ++j)
+ matches.w[j] &= ~d->syntax.letters.w[j];
+ if (!succeeds_in_context (pos.constraint,
d->states[s].context, CTX_NONE))
- for (j = 0; j < CHARCLASS_WORDS; ++j)
- matches[j] &= d->syntax.letters[j] | d->syntax.newline[j];
+ for (size_t j = 0; j < CHARCLASS_WORDS; ++j)
+ matches.w[j] &= d->syntax.letters.w[j] | d->syntax.newline.w[j];
/* If there are no characters left, there's no point in going on. */
- for (j = 0; j < CHARCLASS_WORDS && !matches[j]; ++j)
- continue;
- if (j == CHARCLASS_WORDS)
+ if (emptyset (&matches))
continue;
+
+ /* If we have reset the bit that made us declare "matched", reset
+ that indicator, too. This is required to avoid an infinite loop
+ with this command: echo cx | LC_ALL=C grep -E 'c\b[x ]' */
+ if (!tstbit (uc, &matches))
+ matched = false;
}
#ifdef DEBUG
fprintf (stderr, " nextpos %zu:", pos.index);
prtok (d->tokens[pos.index]);
fprintf (stderr, " of");
- for (j = 0; j < NOTCHAR; j++)
- if (tstbit (j, matches))
+ for (size_t j = 0; j < NOTCHAR; j++)
+ if (tstbit (j, &matches))
fprintf (stderr, " 0x%02zx", j);
fprintf (stderr, "\n");
#endif
- for (j = 0; j < ngrps; ++j)
+ if (matched)
{
- /* If matches contains a single character only, and the current
- group's label doesn't contain that character, go on to the
- next group. */
- if (d->tokens[pos.index] >= 0 && d->tokens[pos.index] < NOTCHAR
- && !tstbit (d->tokens[pos.index], labels[j]))
- continue;
-
- /* Check if this group's label has a nonempty intersection with
- matches. */
- intersectf = 0;
- for (k = 0; k < CHARCLASS_WORDS; ++k)
- intersectf |= intersect[k] = matches[k] & labels[j][k];
- if (!intersectf)
- continue;
-
- /* It does; now find the set differences both ways. */
- leftoversf = matchesf = 0;
- for (k = 0; k < CHARCLASS_WORDS; ++k)
- {
- /* Even an optimizing compiler can't know this for sure. */
- charclass_word match = matches[k], label = labels[j][k];
-
- leftoversf |= leftovers[k] = label & ~match;
- matchesf |= matches[k] = match & ~label;
- }
-
- /* If there were leftovers, create a new group labeled with them. */
- if (leftoversf)
- {
- copyset (leftovers, labels[ngrps]);
- copyset (intersect, labels[j]);
- grps[ngrps].elems = xnmalloc (d->nleaves,
- sizeof *grps[ngrps].elems);
- memcpy (grps[ngrps].elems, grps[j].elems,
- sizeof (grps[j].elems[0]) * grps[j].nelem);
- grps[ngrps].nelem = grps[j].nelem;
- ++ngrps;
- }
-
- /* Put the position in the current group. The constraint is
- irrelevant here. */
- grps[j].elems[grps[j].nelem++] = pos.index;
-
- /* If every character matching the current position has been
- accounted for, we're done. */
- if (!matchesf)
- break;
+ for (size_t k = 0; k < CHARCLASS_WORDS; ++k)
+ label.w[k] &= matches.w[k];
+ group.elems[group.nelem++] = pos.index;
}
-
- /* If we've passed the last group, and there are still characters
- unaccounted for, then we'll have to create a new group. */
- if (j == ngrps)
+ else
{
- copyset (matches, labels[ngrps]);
- zeroset (matches);
- grps[ngrps].elems = xnmalloc (d->nleaves, sizeof *grps[ngrps].elems);
- grps[ngrps].nelem = 1;
- grps[ngrps].elems[0] = pos.index;
- ++ngrps;
+ for (size_t k = 0; k < CHARCLASS_WORDS; ++k)
+ label.w[k] &= ~matches.w[k];
}
}
alloc_position_set (&follows, d->nleaves);
alloc_position_set (&tmp, d->nleaves);
- /* If we are a searching matcher, the default transition is to a state
- containing the positions of state 0, otherwise the default transition
- is to fail miserably. */
- if (d->searchflag)
- {
- /* Find the state(s) corresponding to the positions of state 0. */
- copy (&d->states[0].elems, &follows);
- separate_contexts = state_separate_contexts (&follows);
- state = state_index (d, &follows, separate_contexts ^ CTX_ANY);
- if (separate_contexts & CTX_NEWLINE)
- state_newline = state_index (d, &follows, CTX_NEWLINE);
- else
- state_newline = state;
- if (separate_contexts & CTX_LETTER)
- state_letter = state_index (d, &follows, CTX_LETTER);
- else
- state_letter = state;
-
- for (i = 0; i < NOTCHAR; ++i)
- trans[i] = unibyte_word_constituent (i) ? state_letter : state;
- trans[d->syntax.eolbyte] = state_newline;
- }
- else
- for (i = 0; i < NOTCHAR; ++i)
- trans[i] = -1;
-
- for (i = 0; i < ngrps; ++i)
+ if (group.nelem > 0)
{
follows.nelem = 0;
/* Find the union of the follows of the positions of the group.
This is a hideously inefficient loop. Fix it someday. */
- for (j = 0; j < grps[i].nelem; ++j)
- for (k = 0; k < d->follows[grps[i].elems[j]].nelem; ++k)
- insert (d->follows[grps[i].elems[j]].elems[k], &follows);
+ for (size_t j = 0; j < group.nelem; ++j)
+ for (size_t k = 0; k < d->follows[group.elems[j]].nelem; ++k)
+ insert (d->follows[group.elems[j]].elems[k], &follows);
- if (d->multibyte)
+ /* If we are building a searching matcher, throw in the positions
+ of state 0 as well, if possible. */
+ if (d->searchflag)
{
/* If a token in follows.elems is not 1st byte of a multibyte
character, or the states of follows must accept the bytes
which are not 1st byte of the multibyte character.
- Then, if a state of follows encounter a byte, it must not be
- a 1st byte of a multibyte character nor single byte character.
- We cansel to add state[0].follows to next state, because
- state[0] must accept 1st-byte
-
- For example, we assume <sb a> is a certain single byte
- character, <mb A> is a certain multibyte character, and the
- codepoint of <sb a> equals the 2nd byte of the codepoint of
- <mb A>.
- When state[0] accepts <sb a>, state[i] transit to state[i+1]
- by accepting accepts 1st byte of <mb A>, and state[i+1]
- accepts 2nd byte of <mb A>, if state[i+1] encounter the
- codepoint of <sb a>, it must not be <sb a> but 2nd byte of
- <mb A>, so we cannot add state[0]. */
-
- next_isnt_1st_byte = false;
- for (j = 0; j < follows.nelem; ++j)
+ Then, if a state of follows encounters a byte, it must not be
+ a 1st byte of a multibyte character nor a single byte character.
+ In this case, do not add state[0].follows to next state, because
+ state[0] must accept 1st-byte.
+
+ For example, suppose <sb a> is a certain single byte character,
+ <mb A> is a certain multibyte character, and the codepoint of
+ <sb a> equals the 2nd byte of the codepoint of <mb A>. When
+ state[0] accepts <sb a>, state[i] transits to state[i+1] by
+ accepting the 1st byte of <mb A>, and state[i+1] accepts the
+ 2nd byte of <mb A>, if state[i+1] encounters the codepoint of
+ <sb a>, it must not be <sb a> but the 2nd byte of <mb A>, so do
+ not add state[0]. */
+
+ bool mergeit = !d->localeinfo.multibyte;
+ if (!mergeit)
{
- if (!(d->multibyte_prop[follows.elems[j].index] & 1))
- {
- next_isnt_1st_byte = true;
- break;
- }
+ mergeit = true;
+ for (size_t j = 0; mergeit && j < follows.nelem; j++)
+ mergeit &= d->multibyte_prop[follows.elems[j].index];
+ }
+ if (mergeit)
+ {
+ merge (&d->states[0].elems, &follows, &tmp);
+ copy (&tmp, &follows);
}
}
- /* If we are building a searching matcher, throw in the positions
- of state 0 as well. */
- if (d->searchflag && (!d->multibyte || !next_isnt_1st_byte))
- {
- merge (&d->states[0].elems, &follows, &tmp);
- copy (&tmp, &follows);
- }
-
- /* Find out if the new state will want any context information. */
- possible_contexts = charclass_context (d, labels[i]);
- separate_contexts = state_separate_contexts (&follows);
+ /* Find out if the new state will want any context information,
+ by calculating possible contexts that the group can match,
+ and separate contexts that the new state wants to know. */
+ int possible_contexts = charclass_context (d, &label);
+ int separate_contexts = state_separate_contexts (&follows);
/* Find the state(s) corresponding to the union of the follows. */
if (possible_contexts & ~separate_contexts)
@@ -2920,48 +2906,45 @@ dfastate (state_num s, struct dfa *d, state_num trans[])
else
state_letter = state;
-#ifdef DEBUG
- fprintf (stderr, "group %zu\n nextpos:", i);
- for (j = 0; j < grps[i].nelem; ++j)
- {
- fprintf (stderr, " %zu:", grps[i].elems[j]);
- prtok (d->tokens[grps[i].elems[j]]);
- }
- fprintf (stderr, "\n follows:");
- for (j = 0; j < follows.nelem; ++j)
- {
- fprintf (stderr, " %zu:", follows.elems[j].index);
- prtok (d->tokens[follows.elems[j].index]);
- }
- fprintf (stderr, "\n states:");
- if (possible_contexts & CTX_NEWLINE)
- fprintf (stderr, " CTX_NEWLINE:%td", state_newline);
- if (possible_contexts & CTX_LETTER)
- fprintf (stderr, " CTX_LETTER:%td", state_letter);
- if (possible_contexts & CTX_NONE)
- fprintf (stderr, " CTX_NONE:%td", state);
- fprintf (stderr, "\n");
-#endif
+ /* Reallocate now, to reallocate any newline transition properly. */
+ realloc_trans_if_necessary (d);
+ }
- /* Set the transitions for each character in the current label. */
- for (j = 0; j < CHARCLASS_WORDS; ++j)
- for (k = 0; k < CHARCLASS_WORD_BITS; ++k)
- if (labels[i][j] >> k & 1)
- {
- int c = j * CHARCLASS_WORD_BITS + k;
-
- if (c == d->syntax.eolbyte)
- trans[c] = state_newline;
- else if (unibyte_word_constituent (c))
- trans[c] = state_letter;
- else if (c < NOTCHAR)
- trans[c] = state;
- }
+ /* If we are a searching matcher, the default transition is to a state
+ containing the positions of state 0, otherwise the default transition
+ is to fail miserably. */
+ else if (d->searchflag)
+ {
+ state_newline = 0;
+ state_letter = d->min_trcount - 1;
+ state = d->initstate_notbol;
+ }
+ else
+ {
+ state_newline = -1;
+ state_letter = -1;
+ state = -1;
}
+ /* Set the transitions for each character in the label. */
+ for (size_t i = 0; i < NOTCHAR; i++)
+ if (tstbit (i, &label))
+ switch (d->syntax.sbit[i])
+ {
+ case CTX_NEWLINE:
+ trans[i] = state_newline;
+ break;
+ case CTX_LETTER:
+ trans[i] = state_letter;
+ break;
+ default:
+ trans[i] = state;
+ break;
+ }
+
#ifdef DEBUG
fprintf (stderr, "trans table %td", s);
- for (i = 0; i < NOTCHAR; ++i)
+ for (size_t i = 0; i < NOTCHAR; ++i)
{
if (!(i & 0xf))
fprintf (stderr, "\n");
@@ -2970,119 +2953,19 @@ dfastate (state_num s, struct dfa *d, state_num trans[])
fprintf (stderr, "\n");
#endif
- for (i = 0; i < ngrps; ++i)
- free (grps[i].elems);
+ free (group.elems);
free (follows.elems);
free (tmp.elems);
-}
-
-/* Make sure D's state arrays are large enough to hold NEW_STATE. */
-static void
-realloc_trans_if_necessary (struct dfa *d, state_num new_state)
-{
- state_num oldalloc = d->tralloc;
- if (oldalloc <= new_state)
- {
- state_num **realtrans = d->trans ? d->trans - 1 : NULL;
- size_t newalloc, newalloc1;
- newalloc1 = new_state + 1;
- realtrans = x2nrealloc (realtrans, &newalloc1, sizeof *realtrans);
- realtrans[0] = NULL;
- d->trans = realtrans + 1;
- d->tralloc = newalloc = newalloc1 - 1;
- d->fails = xnrealloc (d->fails, newalloc, sizeof *d->fails);
- d->success = xnrealloc (d->success, newalloc, sizeof *d->success);
- d->newlines = xnrealloc (d->newlines, newalloc, sizeof *d->newlines);
- if (d->multibyte)
- {
- realtrans = d->mb_trans ? d->mb_trans - 1 : NULL;
- realtrans = xnrealloc (realtrans, newalloc1, sizeof *realtrans);
- if (oldalloc == 0)
- realtrans[0] = NULL;
- d->mb_trans = realtrans + 1;
- }
- for (; oldalloc < newalloc; oldalloc++)
- {
- d->trans[oldalloc] = NULL;
- d->fails[oldalloc] = NULL;
- if (d->multibyte)
- d->mb_trans[oldalloc] = NULL;
- }
- }
-}
-
-/* Some routines for manipulating a compiled dfa's transition tables.
- Each state may or may not have a transition table; if it does, and it
- is a non-accepting state, then d->trans[state] points to its table.
- If it is an accepting state then d->fails[state] points to its table.
- If it has no table at all, then d->trans[state] is NULL.
- TODO: Improve this comment, get rid of the unnecessary redundancy. */
-
-static void
-build_state (state_num s, struct dfa *d)
-{
- state_num *trans; /* The new transition table. */
- state_num i, maxstate;
-
- /* Set an upper limit on the number of transition tables that will ever
- exist at once. MAX_TRCOUNT is arbitrary. The idea is that the frequently
- used transition tables will be quickly rebuilt, whereas the ones that
- were only needed once or twice will be cleared away. However, do not
- clear the initial D->min_trcount states, since they are always used. */
- if (MAX_TRCOUNT <= d->trcount)
- {
- for (i = d->min_trcount; i < d->tralloc; ++i)
- {
- free (d->trans[i]);
- free (d->fails[i]);
- d->trans[i] = d->fails[i] = NULL;
- }
- d->trcount = d->min_trcount;
-
- if (d->multibyte)
- {
- for (i = d->min_trcount; i < d->tralloc; i++)
- {
- free (d->mb_trans[i]);
- d->mb_trans[i] = NULL;
- }
- free (d->mb_trans[-1]);
- d->mb_trans[-1] = NULL;
- }
- }
-
- ++d->trcount;
-
- /* Set up the success bits for this state. */
- d->success[s] = 0;
- if (ACCEPTS_IN_CONTEXT (d->states[s].context, CTX_NEWLINE, s, *d))
- d->success[s] |= CTX_NEWLINE;
- if (ACCEPTS_IN_CONTEXT (d->states[s].context, CTX_LETTER, s, *d))
- d->success[s] |= CTX_LETTER;
- if (ACCEPTS_IN_CONTEXT (d->states[s].context, CTX_NONE, s, *d))
- d->success[s] |= CTX_NONE;
-
- trans = xmalloc (NOTCHAR * sizeof *trans);
- dfastate (s, d, trans);
-
- /* Now go through the new transition table, and make sure that the trans
- and fail arrays are allocated large enough to hold a pointer for the
- largest state mentioned in the table. */
- maxstate = -1;
- for (i = 0; i < NOTCHAR; ++i)
- if (maxstate < trans[i])
- maxstate = trans[i];
- realloc_trans_if_necessary (d, maxstate);
/* Keep the newline transition in a special place so we can use it as
a sentinel. */
- d->newlines[s] = trans[d->syntax.eolbyte];
- trans[d->syntax.eolbyte] = -1;
+ if (tstbit (d->syntax.eolbyte, &label))
+ {
+ d->newlines[s] = trans[d->syntax.eolbyte];
+ trans[d->syntax.eolbyte] = -1;
+ }
- if (ACCEPTING (s, *d))
- d->fails[s] = trans;
- else
- d->trans[s] = trans;
+ return trans[uc];
}
/* Multibyte character handling sub-routines for dfaexec. */
@@ -3096,23 +2979,13 @@ transit_state_singlebyte (struct dfa *d, state_num s, unsigned char const **pp)
{
state_num *t;
- if (**pp == d->syntax.eolbyte)
- {
- /* S is always an initial state in transit_state, so the
- transition table for the state must have been built already. */
- assert (d->trans[s] || d->fails[s]);
-
- ++*pp;
- return d->newlines[s];
- }
-
if (d->trans[s])
t = d->trans[s];
else if (d->fails[s])
t = d->fails[s];
else
{
- build_state (s, d);
+ build_state (s, d, **pp);
if (d->trans[s])
t = d->trans[s];
else
@@ -3122,6 +2995,9 @@ transit_state_singlebyte (struct dfa *d, state_num s, unsigned char const **pp)
}
}
+ if (t[**pp] == -2)
+ build_state (s, d, **pp);
+
return t[*(*pp)++];
}
@@ -3132,51 +3008,24 @@ static state_num
transit_state (struct dfa *d, state_num s, unsigned char const **pp,
unsigned char const *end)
{
- state_num s1;
wint_t wc;
- int separate_contexts;
- state_num state, state_newline, mb_index;
- size_t i, j;
int mbclen = mbs_to_wchar (&wc, (char const *) *pp, end - *pp, d);
- int context = wc == d->syntax.eolbyte ? CTX_NEWLINE : CTX_NONE;
- bool context_newline = context == CTX_NEWLINE;
/* This state has some operators which can match a multibyte character. */
d->mb_follows.nelem = 0;
/* Calculate the state which can be reached from the state 's' by
consuming 'mbclen' single bytes from the buffer. */
- s1 = s;
- for (i = 0; i < mbclen && 0 <= s; i++)
+ state_num s1 = s;
+ int mbci;
+ for (mbci = 0; mbci < mbclen && (mbci == 0 || d->min_trcount <= s); mbci++)
s = transit_state_singlebyte (d, s, pp);
- *pp += mbclen - i;
+ *pp += mbclen - mbci;
- if (d->states[s1].curr_dependent)
+ if (wc == WEOF)
{
- if (s < 0)
- d->mb_follows.nelem = 0;
- else
- copy (&d->states[s].elems, &d->mb_follows);
-
- for (i = 0; i < d->states[s1].mbps.nelem; i++)
- {
- if (!SUCCEEDS_IN_CONTEXT (d->states[s1].mbps.elems[i].constraint,
- d->states[s1].context, context))
- continue;
- for (j = 0; j < d->follows[d->states[s1].mbps.elems[i].index].nelem;
- j++)
- insert (d->follows[d->states[s1].mbps.elems[i].index].elems[j],
- &d->mb_follows);
- }
-
- separate_contexts = state_separate_contexts (&d->mb_follows);
- if (context_newline && separate_contexts & CTX_NEWLINE)
- s = state_index (d, &d->mb_follows, CTX_NEWLINE);
- else
- s = state_index (d, &d->mb_follows, separate_contexts ^ CTX_ANY);
- realloc_trans_if_necessary (d, s);
-
+ /* It is an invalid character, so ANYCHAR is not accepted. */
return s;
}
@@ -3187,54 +3036,43 @@ transit_state (struct dfa *d, state_num s, unsigned char const **pp,
{
if (MAX_TRCOUNT <= d->mb_trcount)
{
- state_num s2;
- for (s2 = -1; s2 < d->tralloc; s2++)
+ state_num s3;
+ for (s3 = -1; s3 < d->tralloc; s3++)
{
- free (d->mb_trans[s2]);
- d->mb_trans[s2] = NULL;
+ free (d->mb_trans[s3]);
+ d->mb_trans[s3] = NULL;
}
- for (i = 0; i < d->sindex; i++)
+ for (state_num i = 0; i < d->sindex; i++)
d->states[i].mb_trindex = -1;
d->mb_trcount = 0;
}
d->states[s1].mb_trindex = d->mb_trcount++;
}
- mb_index = d->states[s1].mb_trindex * 2;
-
if (! d->mb_trans[s])
{
enum { TRANSPTR_SIZE = sizeof *d->mb_trans[s] };
- enum { TRANSALLOC_SIZE = 2 * MAX_TRCOUNT * TRANSPTR_SIZE };
+ enum { TRANSALLOC_SIZE = MAX_TRCOUNT * TRANSPTR_SIZE };
d->mb_trans[s] = xmalloc (TRANSALLOC_SIZE);
- for (i = 0; i < 2 * MAX_TRCOUNT; i++)
+ for (int i = 0; i < MAX_TRCOUNT; i++)
d->mb_trans[s][i] = -1;
}
- else
- {
- state = d->mb_trans[s][mb_index + context_newline];
- if (0 <= state)
- return state;
- }
+ else if (d->mb_trans[s][d->states[s1].mb_trindex] >= 0)
+ return d->mb_trans[s][d->states[s1].mb_trindex];
- if (s < 0)
+ if (s == -1)
copy (&d->states[s1].mbps, &d->mb_follows);
else
merge (&d->states[s1].mbps, &d->states[s].elems, &d->mb_follows);
- separate_contexts = state_separate_contexts (&d->mb_follows);
- state = state_index (d, &d->mb_follows, separate_contexts ^ CTX_ANY);
- if (separate_contexts & CTX_NEWLINE)
- state_newline = state_index (d, &d->mb_follows, CTX_NEWLINE);
- else
- state_newline = state;
- realloc_trans_if_necessary (d, state_newline);
+ int separate_contexts = state_separate_contexts (&d->mb_follows);
+ state_num s2 = state_index (d, &d->mb_follows, separate_contexts ^ CTX_ANY);
+ realloc_trans_if_necessary (d);
- d->mb_trans[s][mb_index] = state;
- d->mb_trans[s][mb_index + 1] = state_newline;
+ d->mb_trans[s][d->states[s1].mb_trindex] = s2;
- return context_newline ? state_newline : state;
+ return s2;
}
/* The initial state may encounter a byte which is not a single byte character
@@ -3254,16 +3092,16 @@ transit_state (struct dfa *d, state_num s, unsigned char const **pp,
Both P and MBP must be no larger than END. */
static unsigned char const *
skip_remains_mb (struct dfa *d, unsigned char const *p,
- unsigned char const *mbp, char const *end, wint_t *wcp)
+ unsigned char const *mbp, char const *end)
{
- wint_t wc = WEOF;
if (d->syntax.never_trail[*p])
return p;
while (mbp < p)
- mbp += mbs_to_wchar (&wc, (char const *) mbp,
- end - (char const *) mbp, d);
- if (wcp != NULL)
- *wcp = wc;
+ {
+ wint_t wc;
+ mbp += mbs_to_wchar (&wc, (char const *) mbp,
+ end - (char const *) mbp, d);
+ }
return mbp;
}
@@ -3291,24 +3129,53 @@ static inline char *
dfaexec_main (struct dfa *d, char const *begin, char *end, bool allow_nl,
size_t *count, bool multibyte)
{
- state_num s, s1; /* Current state. */
- unsigned char const *p, *mbp; /* Current input character. */
- state_num **trans, *t; /* Copy of d->trans so it can be optimized
- into a register. */
- unsigned char eol = d->syntax.eolbyte; /* Likewise for eolbyte. */
- unsigned char saved_end;
- size_t nlcount = 0;
-
- if (!d->tralloc)
+ if (MAX_TRCOUNT <= d->sindex)
{
- realloc_trans_if_necessary (d, 1);
- build_state (0, d);
+ for (state_num s = d->min_trcount; s < d->sindex; s++)
+ {
+ free (d->states[s].elems.elems);
+ free (d->states[s].mbps.elems);
+ }
+ d->sindex = d->min_trcount;
+
+ if (d->trans)
+ {
+ for (state_num s = 0; s < d->tralloc; s++)
+ {
+ free (d->trans[s]);
+ free (d->fails[s]);
+ d->trans[s] = d->fails[s] = NULL;
+ }
+ d->trcount = 0;
+ }
+
+ if (d->localeinfo.multibyte && d->mb_trans)
+ {
+ for (state_num s = -1; s < d->tralloc; s++)
+ {
+ free (d->mb_trans[s]);
+ d->mb_trans[s] = NULL;
+ }
+ for (state_num s = 0; s < d->min_trcount; s++)
+ d->states[s].mb_trindex = -1;
+ d->mb_trcount = 0;
+ }
}
- s = s1 = 0;
- p = mbp = (unsigned char const *) begin;
- trans = d->trans;
- saved_end = *(unsigned char *) end;
+ if (!d->tralloc)
+ realloc_trans_if_necessary (d);
+
+ /* Current state. */
+ state_num s = 0, s1 = 0;
+
+ /* Current input character. */
+ unsigned char const *p = (unsigned char const *) begin;
+ unsigned char const *mbp = p;
+
+ /* Copy of d->trans so it can be optimized into a register. */
+ state_num **trans = d->trans;
+ unsigned char eol = d->syntax.eolbyte; /* Likewise for eolbyte. */
+ unsigned char saved_end = *(unsigned char *) end;
*end = eol;
if (multibyte)
@@ -3318,53 +3185,29 @@ dfaexec_main (struct dfa *d, char const *begin, char *end, bool allow_nl,
alloc_position_set (&d->mb_follows, d->nleaves);
}
+ size_t nlcount = 0;
for (;;)
{
- if (multibyte)
+ state_num *t;
+ while ((t = trans[s]) != NULL)
{
- while ((t = trans[s]) != NULL)
+ if (s < d->min_trcount)
{
- s1 = s;
-
- if (s < d->min_trcount)
+ if (!multibyte || d->states[s].mbps.nelem == 0)
{
- if (d->min_trcount == 1)
- {
- if (d->states[s].mbps.nelem == 0)
- {
- do
- {
- while (t[*p] == 0)
- p++;
- p = mbp = skip_remains_mb (d, p, mbp, end, NULL);
- }
- while (t[*p] == 0);
- }
- else
- p = mbp = skip_remains_mb (d, p, mbp, end, NULL);
- }
- else
- {
- wint_t wc;
- mbp = skip_remains_mb (d, p, mbp, end, &wc);
-
- /* If d->min_trcount is greater than 1, maybe
- transit to another initial state after skip. */
- if (p < mbp)
- {
- /* It's CTX_LETTER or CTX_NONE. CTX_NEWLINE
- cannot happen, as we assume that a newline
- is always a single byte character. */
- s1 = s = d->initstate_notbol;
- p = mbp;
- }
- }
+ while (t[*p] == s)
+ p++;
}
+ if (multibyte)
+ p = mbp = skip_remains_mb (d, p, mbp, end);
+ }
- if (d->states[s].mbps.nelem == 0 || (*p == eol && !allow_nl)
- || (*p == '\n' && !(d->syntax.syntax_bits & RE_DOT_NEWLINE))
- || (*p == '\0' && (d->syntax.syntax_bits & RE_DOT_NOT_NULL))
- || (char *) p >= end)
+ if (multibyte)
+ {
+ s1 = s;
+
+ if (d->states[s].mbps.nelem == 0
+ || d->localeinfo.sbctowc[*p] != WEOF || (char *) p >= end)
{
/* If an input character does not match ANYCHAR, do it
like a single-byte character. */
@@ -3373,28 +3216,11 @@ dfaexec_main (struct dfa *d, char const *begin, char *end, bool allow_nl,
else
{
s = transit_state (d, s, &p, (unsigned char *) end);
- if (s >= 0 && p[-1] == eol)
- nlcount++;
mbp = p;
trans = d->trans;
}
}
- }
- else
- {
- if (s == 0)
- {
- t = trans[s];
- if (t)
- {
- while (t[*p] == 0)
- p++;
- s1 = 0;
- s = t[*p++];
- }
- }
-
- while ((t = trans[s]) != NULL)
+ else
{
s1 = t[*p++];
t = trans[s1];
@@ -3405,36 +3231,54 @@ dfaexec_main (struct dfa *d, char const *begin, char *end, bool allow_nl,
s1 = tmp; /* swap */
break;
}
+ if (s < d->min_trcount)
+ {
+ while (t[*p] == s1)
+ p++;
+ }
s = t[*p++];
}
}
if (s < 0)
{
- if ((char *) p > end || p[-1] != eol || d->newlines[s1] < 0)
+ if (s == -2)
+ {
+ s = build_state (s1, d, p[-1]);
+ trans = d->trans;
+ }
+ else if ((char *) p <= end && p[-1] == eol && 0 <= d->newlines[s1])
+ {
+ /* The previous character was a newline. Count it, and skip
+ checking of multibyte character boundary until here. */
+ nlcount++;
+ mbp = p;
+
+ s = (allow_nl ? d->newlines[s1]
+ : d->syntax.sbit[eol] == CTX_NEWLINE ? 0
+ : d->syntax.sbit[eol] == CTX_LETTER ? d->min_trcount - 1
+ : d->initstate_notbol);
+ }
+ else
{
p = NULL;
goto done;
}
-
- /* The previous character was a newline, count it, and skip
- checking of multibyte character boundary until here. */
- nlcount++;
- mbp = p;
-
- s = allow_nl ? d->newlines[s1] : 0;
}
else if (d->fails[s])
{
- if (d->success[s] & d->syntax.sbit[*p])
+ if ((d->success[s] & d->syntax.sbit[*p])
+ || ((char *) p == end
+ && accepts_in_context (d->states[s].context, CTX_NEWLINE, s,
+ d)))
goto done;
+ if (multibyte && s < d->min_trcount)
+ p = mbp = skip_remains_mb (d, p, mbp, end);
+
s1 = s;
if (!multibyte || d->states[s].mbps.nelem == 0
- || (*p == eol && !allow_nl)
- || (*p == '\n' && !(d->syntax.syntax_bits & RE_DOT_NEWLINE))
- || (*p == '\0' && (d->syntax.syntax_bits & RE_DOT_NOT_NULL))
- || (char *) p >= end)
+ || d->localeinfo.sbctowc[*p] != WEOF || (char *) p >= end)
{
/* If a input character does not match ANYCHAR, do it
like a single-byte character. */
@@ -3443,15 +3287,13 @@ dfaexec_main (struct dfa *d, char const *begin, char *end, bool allow_nl,
else
{
s = transit_state (d, s, &p, (unsigned char *) end);
- if (s >= 0 && p[-1] == eol)
- nlcount++;
mbp = p;
trans = d->trans;
}
}
else
{
- build_state (s, d);
+ build_state (s, d, p[0]);
trans = d->trans;
}
}
@@ -3490,7 +3332,7 @@ dfaexec_noop (struct dfa *d, char const *begin, char *end,
return (char *) begin;
}
-/* Like dfaexec_main (D, BEGIN, END, ALLOW_NL, COUNT, D->multibyte),
+/* Like dfaexec_main (D, BEGIN, END, ALLOW_NL, COUNT, D->localeinfo.multibyte),
but faster and set *BACKREF if the DFA code does not support this
regexp usage. */
@@ -3516,14 +3358,8 @@ dfaisfast (struct dfa const *d)
static void
free_mbdata (struct dfa *d)
{
- size_t i;
-
free (d->multibyte_prop);
-
- for (i = 0; i < d->nmbcsets; ++i)
- free (d->mbcsets[i].chars);
-
- free (d->mbcsets);
+ free (d->lex.brack.chars);
free (d->mb_follows.elems);
if (d->mb_trans)
@@ -3531,7 +3367,7 @@ free_mbdata (struct dfa *d)
state_num s;
for (s = -1; s < d->tralloc; s++)
free (d->mb_trans[s]);
- free (d->mb_trans - 1);
+ free (d->mb_trans - 2);
}
}
@@ -3539,8 +3375,7 @@ free_mbdata (struct dfa *d)
static bool _GL_ATTRIBUTE_PURE
dfa_supported (struct dfa const *d)
{
- size_t i;
- for (i = 0; i < d->tindex; i++)
+ for (size_t i = 0; i < d->tindex; i++)
{
switch (d->tokens[i])
{
@@ -3548,10 +3383,9 @@ dfa_supported (struct dfa const *d)
case ENDWORD:
case LIMWORD:
case NOTLIMWORD:
- if (!d->multibyte)
+ if (!d->localeinfo.multibyte)
continue;
- /* fallthrough */
-
+ FALLTHROUGH;
case BACKREF:
case MBCSET:
return false;
@@ -3563,13 +3397,11 @@ dfa_supported (struct dfa const *d)
static void
dfaoptimize (struct dfa *d)
{
- size_t i;
- bool have_backref = false;
-
- if (!using_utf8)
+ if (!d->localeinfo.using_utf8)
return;
- for (i = 0; i < d->tindex; ++i)
+ bool have_backref = false;
+ for (size_t i = 0; i < d->tindex; ++i)
{
switch (d->tokens[i])
{
@@ -3596,7 +3428,7 @@ dfaoptimize (struct dfa *d)
}
free_mbdata (d);
- d->multibyte = false;
+ d->localeinfo.multibyte = false;
d->dfaexec = dfaexec_sb;
d->fast = true;
}
@@ -3604,17 +3436,12 @@ dfaoptimize (struct dfa *d)
static void
dfassbuild (struct dfa *d)
{
- size_t i, j;
- charclass ccl;
- bool have_achar = false;
- bool have_nchar = false;
struct dfa *sup = dfaalloc ();
*sup = *d;
- sup->multibyte = false;
+ sup->localeinfo.multibyte = false;
sup->dfaexec = dfaexec_sb;
sup->multibyte_prop = NULL;
- sup->mbcsets = NULL;
sup->superset = NULL;
sup->states = NULL;
sup->sindex = 0;
@@ -3635,33 +3462,39 @@ dfassbuild (struct dfa *d)
sup->tokens = xnmalloc (d->tindex, 2 * sizeof *sup->tokens);
sup->talloc = d->tindex * 2;
- for (i = j = 0; i < d->tindex; i++)
+ bool have_achar = false;
+ bool have_nchar = false;
+ size_t j;
+ for (size_t i = j = 0; i < d->tindex; i++)
{
switch (d->tokens[i])
{
case ANYCHAR:
case MBCSET:
case BACKREF:
- zeroset (ccl);
- notset (ccl);
- sup->tokens[j++] = CSET + dfa_charclass_index (sup, ccl);
- sup->tokens[j++] = STAR;
- if (d->tokens[i + 1] == QMARK || d->tokens[i + 1] == STAR
- || d->tokens[i + 1] == PLUS)
- i++;
- have_achar = true;
+ {
+ charclass ccl;
+ fillset (&ccl);
+ sup->tokens[j++] = CSET + charclass_index (sup, &ccl);
+ sup->tokens[j++] = STAR;
+ if (d->tokens[i + 1] == QMARK || d->tokens[i + 1] == STAR
+ || d->tokens[i + 1] == PLUS)
+ i++;
+ have_achar = true;
+ }
break;
case BEGWORD:
case ENDWORD:
case LIMWORD:
case NOTLIMWORD:
- if (d->multibyte)
+ if (d->localeinfo.multibyte)
{
/* These constraints aren't supported in a multibyte locale.
Ignore them in the superset DFA. */
sup->tokens[j++] = EMPTY;
break;
}
+ FALLTHROUGH;
default:
sup->tokens[j++] = d->tokens[i];
if ((0 <= d->tokens[i] && d->tokens[i] < NOTCHAR)
@@ -3672,7 +3505,7 @@ dfassbuild (struct dfa *d)
}
sup->tindex = j;
- if (have_nchar && (have_achar || d->multibyte))
+ if (have_nchar && (have_achar || d->localeinfo.multibyte))
d->superset = sup;
else
{
@@ -3709,15 +3542,13 @@ dfacomp (char const *s, size_t len, struct dfa *d, bool searchflag)
void
dfafree (struct dfa *d)
{
- size_t i;
-
free (d->charclasses);
free (d->tokens);
- if (d->multibyte)
+ if (d->localeinfo.multibyte)
free_mbdata (d);
- for (i = 0; i < d->sindex; ++i)
+ for (size_t i = 0; i < d->sindex; ++i)
{
free (d->states[i].elems.elems);
free (d->states[i].mbps.elems);
@@ -3726,20 +3557,20 @@ dfafree (struct dfa *d)
if (d->follows)
{
- for (i = 0; i < d->tindex; ++i)
+ for (size_t i = 0; i < d->tindex; ++i)
free (d->follows[i].elems);
free (d->follows);
}
if (d->trans)
{
- for (i = 0; i < d->tralloc; ++i)
+ for (size_t i = 0; i < d->tralloc; ++i)
{
free (d->trans[i]);
free (d->fails[i]);
}
- free (d->trans - 1);
+ free (d->trans - 2);
free (d->fails);
free (d->newlines);
free (d->success);
@@ -3834,13 +3665,11 @@ dfafree (struct dfa *d)
static char *
icatalloc (char *old, char const *new)
{
- char *result;
- size_t oldsize;
size_t newsize = strlen (new);
if (newsize == 0)
return old;
- oldsize = strlen (old);
- result = xrealloc (old, oldsize + newsize + 1);
+ size_t oldsize = strlen (old);
+ char *result = xrealloc (old, oldsize + newsize + 1);
memcpy (result + oldsize, new, newsize + 1);
return result;
}
@@ -3855,10 +3684,10 @@ freelist (char **cpp)
static char **
enlist (char **cpp, char *new, size_t len)
{
- size_t i, j;
new = memcpy (xmalloc (len + 1), new, len);
new[len] = '\0';
/* Is there already something in the list that's new (or longer)? */
+ size_t i;
for (i = 0; cpp[i] != NULL; ++i)
if (strstr (cpp[i], new) != NULL)
{
@@ -3866,8 +3695,7 @@ enlist (char **cpp, char *new, size_t len)
return cpp;
}
/* Eliminate any obsoleted strings. */
- j = 0;
- while (cpp[j] != NULL)
+ for (size_t j = 0; cpp[j] != NULL; )
if (strstr (new, cpp[j]) == NULL)
++j;
else
@@ -3891,9 +3719,8 @@ static char **
comsubs (char *left, char const *right)
{
char **cpp = xzalloc (sizeof *cpp);
- char *lcp;
- for (lcp = left; *lcp != '\0'; ++lcp)
+ for (char *lcp = left; *lcp != '\0'; lcp++)
{
size_t len = 0;
char *rcp = strchr (right, *lcp);
@@ -3926,11 +3753,10 @@ static char **
inboth (char **left, char **right)
{
char **both = xzalloc (sizeof *both);
- size_t lnum, rnum;
- for (lnum = 0; left[lnum] != NULL; ++lnum)
+ for (size_t lnum = 0; left[lnum] != NULL; ++lnum)
{
- for (rnum = 0; right[rnum] != NULL; ++rnum)
+ for (size_t rnum = 0; right[rnum] != NULL; ++rnum)
{
char **temp = comsubs (left[lnum], right[rnum]);
both = addlists (both, temp);
@@ -3994,17 +3820,14 @@ dfamust (struct dfa const *d)
{
must *mp = NULL;
char const *result = "";
- size_t i, ri;
bool exact = false;
bool begline = false;
bool endline = false;
- size_t rj;
bool need_begline = false;
bool need_endline = false;
bool case_fold_unibyte = d->syntax.case_fold && MB_CUR_MAX == 1;
- struct dfamust *dm;
- for (ri = 0; ri < d->tindex; ++ri)
+ for (size_t ri = 0; ri < d->tindex; ++ri)
{
token t = d->tokens[ri];
switch (t)
@@ -4047,7 +3870,7 @@ dfamust (struct dfa const *d)
size_t j, ln, rn, n;
/* Guaranteed to be. Unlikely, but ... */
- if (STREQ (lmp->is, rmp->is))
+ if (streq (lmp->is, rmp->is))
{
lmp->begline &= rmp->begline;
lmp->endline &= rmp->endline;
@@ -4059,7 +3882,7 @@ dfamust (struct dfa const *d)
lmp->endline = false;
}
/* Left side--easy */
- i = 0;
+ size_t i = 0;
while (lmp->left[i] != '\0' && lmp->left[i] == rmp->left[i])
++i;
lmp->left[i] = '\0';
@@ -4089,10 +3912,10 @@ dfamust (struct dfa const *d)
case END:
assert (!mp->prev);
- for (i = 0; mp->in[i] != NULL; ++i)
+ for (size_t i = 0; mp->in[i] != NULL; ++i)
if (strlen (mp->in[i]) > strlen (result))
result = mp->in[i];
- if (STREQ (result, mp->is))
+ if (streq (result, mp->is))
{
if ((!need_begline || mp->begline) && (!need_endline
|| mp->endline))
@@ -4159,7 +3982,7 @@ dfamust (struct dfa const *d)
charclass *ccl = &d->charclasses[t - CSET];
int j;
for (j = 0; j < NOTCHAR; j++)
- if (tstbit (j, *ccl))
+ if (tstbit (j, ccl))
break;
if (! (j < NOTCHAR))
{
@@ -4168,7 +3991,7 @@ dfamust (struct dfa const *d)
}
t = j;
while (++j < NOTCHAR)
- if (tstbit (j, *ccl)
+ if (tstbit (j, ccl)
&& ! (case_fold_unibyte
&& toupper (j) == toupper (t)))
break;
@@ -4179,7 +4002,7 @@ dfamust (struct dfa const *d)
}
}
- rj = ri + 2;
+ size_t rj = ri + 2;
if (d->tokens[ri + 1] == CAT)
{
for (; rj < d->tindex - 1; rj += 2)
@@ -4194,6 +4017,7 @@ dfamust (struct dfa const *d)
mp->is[0] = mp->left[0] = mp->right[0]
= case_fold_unibyte ? toupper (t) : t;
+ size_t i;
for (i = 1; ri + 2 < rj; i++)
{
ri += 2;
@@ -4208,7 +4032,7 @@ dfamust (struct dfa const *d)
}
done:;
- dm = NULL;
+ struct dfamust *dm = NULL;
if (*result)
{
dm = xmalloc (sizeof *dm);
@@ -4238,20 +4062,50 @@ dfamustfree (struct dfamust *dm)
struct dfa *
dfaalloc (void)
{
- struct dfa *d = xcalloc (1, sizeof (struct dfa));
- d->multibyte = MB_CUR_MAX > 1;
- d->dfaexec = d->multibyte ? dfaexec_mb : dfaexec_sb;
- d->fast = !d->multibyte;
- d->lexstate.cur_mb_len = 1;
- return d;
+ return xzalloc (sizeof (struct dfa));
}
+/* Initialize DFA. */
void
-dfa_init (void)
+dfasyntax (struct dfa *dfa, struct localeinfo const *linfo,
+ reg_syntax_t bits, int dfaopts)
{
- check_utf8 ();
- check_unibyte_c ();
- init_mbrtowc_cache ();
+ memset (dfa, 0, offsetof (struct dfa, dfaexec));
+ dfa->dfaexec = linfo->multibyte ? dfaexec_mb : dfaexec_sb;
+ dfa->simple_locale = using_simple_locale (linfo->multibyte);
+ dfa->localeinfo = *linfo;
+
+ dfa->fast = !dfa->localeinfo.multibyte;
+
+ dfa->canychar = -1;
+ dfa->lex.cur_mb_len = 1;
+ dfa->syntax.syntax_bits_set = true;
+ dfa->syntax.case_fold = (bits & RE_ICASE) != 0;
+ dfa->syntax.anchor = (dfaopts & DFA_ANCHOR) != 0;
+ dfa->syntax.eolbyte = dfaopts & DFA_EOL_NUL ? '\0' : '\n';
+ dfa->syntax.syntax_bits = bits;
+
+ for (int i = CHAR_MIN; i <= CHAR_MAX; ++i)
+ {
+ unsigned char uc = i;
+
+ dfa->syntax.sbit[uc] = char_context (dfa, uc);
+ switch (dfa->syntax.sbit[uc])
+ {
+ case CTX_LETTER:
+ setbit (uc, &dfa->syntax.letters);
+ break;
+ case CTX_NEWLINE:
+ setbit (uc, &dfa->syntax.newline);
+ break;
+ }
+
+ /* POSIX requires that the five bytes in "\n\r./" (including the
+ terminating NUL) cannot occur inside a multibyte character. */
+ dfa->syntax.never_trail[uc] = (dfa->localeinfo.using_utf8
+ ? (uc & 0xc0) != 0x80
+ : strchr ("\n\r./", uc) != NULL);
+ }
}
/* vim:set shiftwidth=2: */
diff --git a/dfa.h b/support/dfa.h
index 02f56f44..7d11f05d 100644
--- a/dfa.h
+++ b/support/dfa.h
@@ -1,5 +1,5 @@
/* dfa.h - declarations for GNU deterministic regexp compiler
- Copyright (C) 1988, 1998, 2007, 2009-2016 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1998, 2007, 2009-2017 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,7 +26,13 @@
#endif /* HAVE_STDBOOL_H */
#include <stddef.h>
-#define _GL_ATTRIBUTE_MALLOC
+#if 3 <= __GNUC__
+# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+#else
+# define _GL_ATTRIBUTE_MALLOC
+#endif
+
+struct localeinfo; /* See localeinfo.h. */
/* Element of a list of strings, at least one of which is known to
appear in any R.E. matching the DFA. */
@@ -48,17 +54,33 @@ struct dfa;
calling dfafree() on it. */
extern struct dfa *dfaalloc (void) _GL_ATTRIBUTE_MALLOC;
+/* DFA options that can be ORed together, for dfasyntax's 4th arg. */
+enum
+ {
+ /* ^ and $ match only the start and end of data, and do not match
+ end-of-line within data. This is always false for grep, but
+ possibly true for other apps. */
+ DFA_ANCHOR = 1 << 0,
+
+ /* '\0' in data is end-of-line, instead of the traditional '\n'. */
+ DFA_EOL_NUL = 1 << 1
+ };
+
+/* Initialize or reinitialize a DFA. This must be called before
+ any of the routines below. The arguments are:
+ 1. The DFA to operate on.
+ 2. Information about the current locale.
+ 3. Syntax bits described in regex.h.
+ 4. Additional DFA options described above. */
+extern void dfasyntax (struct dfa *, struct localeinfo const *,
+ reg_syntax_t, int);
+
/* Build and return the struct dfamust from the given struct dfa. */
extern struct dfamust *dfamust (struct dfa const *);
/* Free the storage held by the components of a struct dfamust. */
extern void dfamustfree (struct dfamust *);
-/* dfasyntax() takes four arguments; the first is the dfa to operate on, the
- second sets the syntax bits described earlier in this file, the third sets
- the case-folding flag, and the fourth specifies the line terminator. */
-extern void dfasyntax (struct dfa *, reg_syntax_t, bool, unsigned char);
-
/* Compile the given string of the given length into the given struct dfa.
Final argument is a flag specifying whether to build a searching or an
exact matcher. */
@@ -88,6 +110,11 @@ extern struct dfa *dfasuperset (struct dfa const *d) _GL_ATTRIBUTE_PURE;
/* The DFA is likely to be fast. */
extern bool dfaisfast (struct dfa const *) _GL_ATTRIBUTE_PURE;
+/* Copy the syntax settings from one dfa instance to another.
+ Saves considerable computation time if compiling many regular expressions
+ based on the same setting. */
+extern void dfacopysyntax (struct dfa *to, const struct dfa *from);
+
/* Free the storage held by the components of a struct dfa. */
extern void dfafree (struct dfa *);
@@ -103,8 +130,3 @@ extern void dfawarn (const char *);
takes a single argument, a NUL-terminated string describing the error.
The user must supply a dfaerror. */
extern _Noreturn void dfaerror (const char *);
-
-extern bool dfa_using_utf8 (void) _GL_ATTRIBUTE_PURE;
-
-/* This must be called before calling any of the above dfa*() functions. */
-extern void dfa_init (void);
diff --git a/getopt.c b/support/getopt.c
index 8bc59610..8bc59610 100644
--- a/getopt.c
+++ b/support/getopt.c
diff --git a/getopt.h b/support/getopt.h
index 8393569d..8393569d 100644
--- a/getopt.h
+++ b/support/getopt.h
diff --git a/getopt1.c b/support/getopt1.c
index 438fe52b..438fe52b 100644
--- a/getopt1.c
+++ b/support/getopt1.c
diff --git a/getopt_int.h b/support/getopt_int.h
index 514a1beb..514a1beb 100644
--- a/getopt_int.h
+++ b/support/getopt_int.h
diff --git a/support/intprops.h b/support/intprops.h
new file mode 100644
index 00000000..33a7ec5a
--- /dev/null
+++ b/support/intprops.h
@@ -0,0 +1,453 @@
+/* intprops.h -- properties of integer types
+
+ Copyright (C) 2001-2017 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#ifndef _GL_INTPROPS_H
+#define _GL_INTPROPS_H
+
+#include <limits.h>
+
+/* Return a value with the common real type of E and V and the value of V. */
+#define _GL_INT_CONVERT(e, v) (0 * (e) + (v))
+
+/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
+ <http://lists.gnu.org/archive/html/bug-gnulib/2011-05/msg00406.html>. */
+#define _GL_INT_NEGATE_CONVERT(e, v) (0 * (e) - (v))
+
+/* The extra casts in the following macros work around compiler bugs,
+ e.g., in Cray C 5.0.3.0. */
+
+/* True if the arithmetic type T is an integer type. bool counts as
+ an integer. */
+#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
+
+/* True if the real type T is signed. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+
+/* Return 1 if the real expression E, after promotion, has a
+ signed or floating type. */
+#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
+
+
+/* Minimum and maximum values for integer types and expressions. */
+
+/* The width in bits of the integer type or expression T.
+ Padding bits are not supported; this is checked at compile-time below. */
+#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
+
+/* The maximum and minimum values for the integer type T. */
+#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
+#define TYPE_MAXIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)))
+
+/* The maximum and minimum values for the type of the expression E,
+ after integer promotion. E should not have side effects. */
+#define _GL_INT_MINIMUM(e) \
+ (EXPR_SIGNED (e) \
+ ? ~ _GL_SIGNED_INT_MAXIMUM (e) \
+ : _GL_INT_CONVERT (e, 0))
+#define _GL_INT_MAXIMUM(e) \
+ (EXPR_SIGNED (e) \
+ ? _GL_SIGNED_INT_MAXIMUM (e) \
+ : _GL_INT_NEGATE_CONVERT (e, 1))
+#define _GL_SIGNED_INT_MAXIMUM(e) \
+ (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1)
+
+/* Work around OpenVMS incompatibility with C99. */
+#if !defined LLONG_MAX && defined __INT64_MAX
+# define LLONG_MAX __INT64_MAX
+# define LLONG_MIN __INT64_MIN
+#endif
+
+/* This include file assumes that signed types are two's complement without
+ padding bits; the above macros have undefined behavior otherwise.
+ If this is a problem for you, please let us know how to fix it for your host.
+ This assumption is tested by the intprops-tests module. */
+
+/* Does the __typeof__ keyword work? This could be done by
+ 'configure', but for now it's easier to do it by hand. */
+#if (2 <= __GNUC__ \
+ || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
+ || (0x5110 <= __SUNPRO_C && !__STDC__))
+# define _GL_HAVE___TYPEOF__ 1
+#else
+# define _GL_HAVE___TYPEOF__ 0
+#endif
+
+/* Return 1 if the integer type or expression T might be signed. Return 0
+ if it is definitely unsigned. This macro does not evaluate its argument,
+ and expands to an integer constant expression. */
+#if _GL_HAVE___TYPEOF__
+# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
+#else
+# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
+#endif
+
+/* Bound on length of the string representing an unsigned integer
+ value representable in B bits. log10 (2.0) < 146/485. The
+ smallest value of B where this bound is not tight is 2621. */
+#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
+
+/* Bound on length of the string representing an integer type or expression T.
+ Subtract 1 for the sign bit if T is signed, and then add 1 more for
+ a minus sign if needed.
+
+ Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is
+ signed, this macro may overestimate the true bound by one byte when
+ applied to unsigned types of size 2, 4, 16, ... bytes. */
+#define INT_STRLEN_BOUND(t) \
+ (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \
+ + _GL_SIGNED_TYPE_OR_EXPR (t))
+
+/* Bound on buffer size needed to represent an integer type or expression T,
+ including the terminating null. */
+#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
+
+
+/* Range overflow checks.
+
+ The INT_<op>_RANGE_OVERFLOW macros return 1 if the corresponding C
+ operators might not yield numerically correct answers due to
+ arithmetic overflow. They do not rely on undefined or
+ implementation-defined behavior. Their implementations are simple
+ and straightforward, but they are a bit harder to use than the
+ INT_<op>_OVERFLOW macros described below.
+
+ Example usage:
+
+ long int i = ...;
+ long int j = ...;
+ if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX))
+ printf ("multiply would overflow");
+ else
+ printf ("product is %ld", i * j);
+
+ Restrictions on *_RANGE_OVERFLOW macros:
+
+ These macros do not check for all possible numerical problems or
+ undefined or unspecified behavior: they do not check for division
+ by zero, for bad shift counts, or for shifting negative numbers.
+
+ These macros may evaluate their arguments zero or multiple times,
+ so the arguments should not have side effects. The arithmetic
+ arguments (including the MIN and MAX arguments) must be of the same
+ integer type after the usual arithmetic conversions, and the type
+ must have minimum value MIN and maximum MAX. Unsigned types should
+ use a zero MIN of the proper type.
+
+ These macros are tuned for constant MIN and MAX. For commutative
+ operations such as A + B, they are also tuned for constant B. */
+
+/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. */
+#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \
+ ((b) < 0 \
+ ? (a) < (min) - (b) \
+ : (max) - (b) < (a))
+
+/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. */
+#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \
+ ((b) < 0 \
+ ? (max) + (b) < (a) \
+ : (a) < (min) + (b))
+
+/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. */
+#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
+ ((min) < 0 \
+ ? (a) < - (max) \
+ : 0 < (a))
+
+/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Avoid && and || as they tickle
+ bugs in Sun C 5.11 2010/08/13 and other compilers; see
+ <http://lists.gnu.org/archive/html/bug-gnulib/2011-05/msg00401.html>. */
+#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
+ ((b) < 0 \
+ ? ((a) < 0 \
+ ? (a) < (max) / (b) \
+ : (b) == -1 \
+ ? 0 \
+ : (min) / (b) < (a)) \
+ : (b) == 0 \
+ ? 0 \
+ : ((a) < 0 \
+ ? (a) < (min) / (b) \
+ : (max) / (b) < (a)))
+
+/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Do not check for division by zero. */
+#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \
+ ((min) < 0 && (b) == -1 && (a) < - (max))
+
+/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Do not check for division by zero.
+ Mathematically, % should never overflow, but on x86-like hosts
+ INT_MIN % -1 traps, and the C standard permits this, so treat this
+ as an overflow too. */
+#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \
+ INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max)
+
+/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Here, MIN and MAX are for A only, and B need
+ not be of the same type as the other arguments. The C standard says that
+ behavior is undefined for shifts unless 0 <= B < wordwidth, and that when
+ A is negative then A << B has undefined behavior and A >> B has
+ implementation-defined behavior, but do not check these other
+ restrictions. */
+#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \
+ ((a) < 0 \
+ ? (a) < (min) >> (b) \
+ : (max) >> (b) < (a))
+
+/* True if __builtin_add_overflow (A, B, P) works when P is non-null. */
+#if 5 <= __GNUC__ && !defined __ICC
+# define _GL_HAS_BUILTIN_OVERFLOW 1
+#else
+# define _GL_HAS_BUILTIN_OVERFLOW 0
+#endif
+
+/* True if __builtin_add_overflow_p (A, B, C) works. */
+#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
+
+/* The _GL*_OVERFLOW macros have the same restrictions as the
+ *_RANGE_OVERFLOW macros, except that they do not assume that operands
+ (e.g., A and B) have the same type as MIN and MAX. Instead, they assume
+ that the result (e.g., A + B) has that type. */
+#if _GL_HAS_BUILTIN_OVERFLOW_P
+# define _GL_ADD_OVERFLOW(a, b, min, max) \
+ __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0)
+# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \
+ __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0)
+# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
+ __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0)
+#else
+# define _GL_ADD_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \
+ : (a) < 0 ? (b) <= (a) + (b) \
+ : (b) < 0 ? (a) <= (a) + (b) \
+ : (a) + (b) < (b))
+# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \
+ : (a) < 0 ? 1 \
+ : (b) < 0 ? (a) - (b) <= (a) \
+ : (a) < (b))
+# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
+ (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
+ || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
+#endif
+#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \
+ : (a) < 0 ? (b) <= (a) + (b) - 1 \
+ : (b) < 0 && (a) + (b) <= (a))
+#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \
+ : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \
+ : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max))
+
+/* Return a nonzero value if A is a mathematical multiple of B, where
+ A is unsigned, B is negative, and MAX is the maximum value of A's
+ type. A's type must be the same as (A % B)'s type. Normally (A %
+ -B == 0) suffices, but things get tricky if -B would overflow. */
+#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \
+ (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \
+ ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \
+ ? (a) \
+ : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \
+ : (a) % - (b)) \
+ == 0)
+
+/* Check for integer overflow, and report low order bits of answer.
+
+ The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators
+ might not yield numerically correct answers due to arithmetic overflow.
+ The INT_<op>_WRAPV macros also store the low-order bits of the answer.
+ These macros work correctly on all known practical hosts, and do not rely
+ on undefined behavior due to signed arithmetic overflow.
+
+ Example usage, assuming A and B are long int:
+
+ if (INT_MULTIPLY_OVERFLOW (a, b))
+ printf ("result would overflow\n");
+ else
+ printf ("result is %ld (no overflow)\n", a * b);
+
+ Example usage with WRAPV flavor:
+
+ long int result;
+ bool overflow = INT_MULTIPLY_WRAPV (a, b, &result);
+ printf ("result is %ld (%s)\n", result,
+ overflow ? "after overflow" : "no overflow");
+
+ Restrictions on these macros:
+
+ These macros do not check for all possible numerical problems or
+ undefined or unspecified behavior: they do not check for division
+ by zero, for bad shift counts, or for shifting negative numbers.
+
+ These macros may evaluate their arguments zero or multiple times, so the
+ arguments should not have side effects.
+
+ The WRAPV macros are not constant expressions. They support only
+ +, binary -, and *. The result type must be signed.
+
+ These macros are tuned for their last argument being a constant.
+
+ Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
+ A % B, and A << B would overflow, respectively. */
+
+#define INT_ADD_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW)
+#define INT_SUBTRACT_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW)
+#if _GL_HAS_BUILTIN_OVERFLOW_P
+# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a)
+#else
+# define INT_NEGATE_OVERFLOW(a) \
+ INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
+#endif
+#define INT_MULTIPLY_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
+#define INT_DIVIDE_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW)
+#define INT_REMAINDER_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW)
+#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
+ INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
+ _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
+
+/* Return 1 if the expression A <op> B would overflow,
+ where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test,
+ assuming MIN and MAX are the minimum and maximum for the result type.
+ Arguments should be free of side effects. */
+#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
+ op_result_overflow (a, b, \
+ _GL_INT_MINIMUM (0 * (b) + (a)), \
+ _GL_INT_MAXIMUM (0 * (b) + (a)))
+
+/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
+ Return 1 if the result overflows. See above for restrictions. */
+#define INT_ADD_WRAPV(a, b, r) \
+ _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW)
+#define INT_SUBTRACT_WRAPV(a, b, r) \
+ _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW)
+#define INT_MULTIPLY_WRAPV(a, b, r) \
+ _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW)
+
+/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
+ https://llvm.org/bugs/show_bug.cgi?id=25390
+ For now, assume all versions of GCC-like compilers generate bogus
+ warnings for _Generic. This matters only for older compilers that
+ lack __builtin_add_overflow. */
+#if __GNUC__
+# define _GL__GENERIC_BOGUS 1
+#else
+# define _GL__GENERIC_BOGUS 0
+#endif
+
+/* Store the low-order bits of A <op> B into *R, where OP specifies
+ the operation. BUILTIN is the builtin operation, and OVERFLOW the
+ overflow predicate. Return 1 if the result overflows. See above
+ for restrictions. */
+#if _GL_HAS_BUILTIN_OVERFLOW
+# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r)
+#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
+# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
+ (_Generic \
+ (*(r), \
+ signed char: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ signed char, SCHAR_MIN, SCHAR_MAX), \
+ short int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ short int, SHRT_MIN, SHRT_MAX), \
+ int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ int, INT_MIN, INT_MAX), \
+ long int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX), \
+ long long int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ long long int, LLONG_MIN, LLONG_MAX)))
+#else
+# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
+ (sizeof *(r) == sizeof (signed char) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ signed char, SCHAR_MIN, SCHAR_MAX) \
+ : sizeof *(r) == sizeof (short int) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ short int, SHRT_MIN, SHRT_MAX) \
+ : sizeof *(r) == sizeof (int) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ int, INT_MIN, INT_MAX) \
+ : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
+# ifdef LLONG_MAX
+# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
+ (sizeof *(r) == sizeof (long int) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ long long int, LLONG_MIN, LLONG_MAX))
+# else
+# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX)
+# endif
+#endif
+
+/* Store the low-order bits of A <op> B into *R, where the operation
+ is given by OP. Use the unsigned type UT for calculation to avoid
+ overflow problems. *R's type is T, with extrema TMIN and TMAX.
+ T must be a signed integer type. Return 1 if the result overflows. */
+#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
+ (sizeof ((a) op (b)) < sizeof (t) \
+ ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \
+ : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax))
+#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \
+ ((overflow (a, b) \
+ || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \
+ || (tmax) < ((a) op (b))) \
+ ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
+ : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
+
+/* Return the low-order bits of A <op> B, where the operation is given
+ by OP. Use the unsigned type UT for calculation to avoid undefined
+ behavior on signed integer overflow, and convert the result to type T.
+ UT is at least as wide as T and is no narrower than unsigned int,
+ T is two's complement, and there is no padding or trap representations.
+ Assume that converting UT to T yields the low-order bits, as is
+ done in all known two's-complement C compilers. E.g., see:
+ https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
+
+ According to the C standard, converting UT to T yields an
+ implementation-defined result or signal for values outside T's
+ range. However, code that works around this theoretical problem
+ runs afoul of a compiler bug in Oracle Studio 12.3 x86. See:
+ http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00049.html
+ As the compiler bug is real, don't try to work around the
+ theoretical problem. */
+
+#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
+ ((t) ((ut) (a) op (ut) (b)))
+
+#endif /* _GL_INTPROPS_H */
diff --git a/support/localeinfo.c b/support/localeinfo.c
new file mode 100644
index 00000000..ece679e3
--- /dev/null
+++ b/support/localeinfo.c
@@ -0,0 +1,113 @@
+/* locale information
+
+ Copyright 2016-2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#include <config.h>
+
+#include <localeinfo.h>
+
+#include <verify.h>
+
+#include <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wctype.h>
+
+/* The sbclen implementation relies on this. */
+verify (MB_LEN_MAX <= SCHAR_MAX);
+
+/* Return true if the locale uses UTF-8. */
+
+static bool
+is_using_utf8 (void)
+{
+ wchar_t wc;
+ mbstate_t mbs = {0};
+ return mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100;
+}
+
+/* Initialize *LOCALEINFO from the current locale. */
+
+void
+init_localeinfo (struct localeinfo *localeinfo)
+{
+ int i;
+
+ localeinfo->multibyte = MB_CUR_MAX > 1;
+ localeinfo->using_utf8 = is_using_utf8 ();
+
+ for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+ {
+ char c = i;
+ unsigned char uc = i;
+ mbstate_t s = {0};
+ wchar_t wc;
+ size_t len = mbrtowc (&wc, &c, 1, &s);
+ localeinfo->sbclen[uc] = len <= 1 ? 1 : - (int) - len;
+ localeinfo->sbctowc[uc] = len <= 1 ? wc : WEOF;
+ }
+}
+
+/* The set of wchar_t values C such that there's a useful locale
+ somewhere where C != towupper (C) && C != towlower (towupper (C)).
+ For example, 0x00B5 (U+00B5 MICRO SIGN) is in this table, because
+ towupper (0x00B5) == 0x039C (U+039C GREEK CAPITAL LETTER MU), and
+ towlower (0x039C) == 0x03BC (U+03BC GREEK SMALL LETTER MU). */
+static short const lonesome_lower[] =
+ {
+ 0x00B5, 0x0131, 0x017F, 0x01C5, 0x01C8, 0x01CB, 0x01F2, 0x0345,
+ 0x03C2, 0x03D0, 0x03D1, 0x03D5, 0x03D6, 0x03F0, 0x03F1,
+
+ /* U+03F2 GREEK LUNATE SIGMA SYMBOL lacks a specific uppercase
+ counterpart in locales predating Unicode 4.0.0 (April 2003). */
+ 0x03F2,
+
+ 0x03F5, 0x1E9B, 0x1FBE,
+ };
+
+/* Verify that the worst case fits. This is 1 for towupper, 1 for
+ towlower, and 1 for each entry in LONESOME_LOWER. */
+verify (1 + 1 + sizeof lonesome_lower / sizeof *lonesome_lower
+ <= CASE_FOLDED_BUFSIZE);
+
+/* Find the characters equal to C after case-folding, other than C
+ itself, and store them into FOLDED. Return the number of characters
+ stored; this is zero if C is WEOF. */
+
+int
+case_folded_counterparts (wint_t c, wchar_t folded[CASE_FOLDED_BUFSIZE])
+{
+ int i;
+ int n = 0;
+ wint_t uc = towupper (c);
+ wint_t lc = towlower (uc);
+ if (uc != c)
+ folded[n++] = uc;
+ if (lc != uc && lc != c && towupper (lc) == uc)
+ folded[n++] = lc;
+ for (i = 0; i < sizeof lonesome_lower / sizeof *lonesome_lower; i++)
+ {
+ wint_t li = lonesome_lower[i];
+ if (li != lc && li != uc && li != c && towupper (li) == uc)
+ folded[n++] = li;
+ }
+ return n;
+}
diff --git a/support/localeinfo.h b/support/localeinfo.h
new file mode 100644
index 00000000..a6773f52
--- /dev/null
+++ b/support/localeinfo.h
@@ -0,0 +1,54 @@
+/* locale information
+
+ Copyright 2016-2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#include <limits.h>
+#include <stdbool.h>
+#include <wchar.h>
+
+struct localeinfo
+{
+ /* MB_CUR_MAX > 1. */
+ bool multibyte;
+
+ /* The locale uses UTF-8. */
+ bool using_utf8;
+
+ /* An array indexed by byte values B that contains 1 if B is a
+ single-byte character, -1 if B is an encoding error, and -2 if B
+ is the leading byte of a multibyte character that contains more
+ than one byte. */
+ signed char sbclen[UCHAR_MAX + 1];
+
+ /* An array indexed by byte values B that contains the corresponding
+ wide character (if any) for B if sbclen[B] == 1. WEOF means the
+ byte is not a valid single-byte character, i.e., sbclen[B] == -1
+ or -2. */
+ wint_t sbctowc[UCHAR_MAX + 1];
+};
+
+extern void init_localeinfo (struct localeinfo *);
+
+/* Maximum number of characters that can be the case-folded
+ counterparts of a single character, not counting the character
+ itself. This is a generous upper bound. */
+enum { CASE_FOLDED_BUFSIZE = 32 };
+
+extern int case_folded_counterparts (wint_t, wchar_t[CASE_FOLDED_BUFSIZE]);
diff --git a/random.c b/support/random.c
index cba1b6bc..1aab2b50 100644
--- a/random.c
+++ b/support/random.c
@@ -60,6 +60,8 @@ static const char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95";
#include <unistd.h>
#endif
+#include <assert.h>
+
#include "random.h" /* gawk addition */
#ifdef HAVE_SYS_TIME_H /* gawk addition */
@@ -137,8 +139,20 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/random.c,v 1.24 2004/01/
* 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
* 128 bytes, this new version runs about 19 percent faster and for a 16
* byte buffer it is about 5 percent faster.
+ *
+ * Modified 06 February 2016 by Nelson H. F. Beebe to interface to a
+ * shuffle buffer, producing a huge period, and removing long-range
+ * correlations of the basic low-level generator. See comments and
+ * literature references in random() at the end of this file.
*/
+#define SHUFFLE_BITS 9 /* see comments in random() below for this choice */
+#define SHUFFLE_MAX (1 << SHUFFLE_BITS) /* MUST be power of two */
+#define SHUFFLE_MASK (SHUFFLE_MAX - 1) /* (k & SHUFFLE_MASK) is in [0, SHUFFLE_MAX - 1] */
+
+static int shuffle_init = 1;
+static long shuffle_buffer[SHUFFLE_MAX];
+
/*
* For each of the currently supported random number generators, we have a
* break value on the amount of state information (you need at least this
@@ -307,6 +321,8 @@ srandom(x)
{
int i, lim;
+ shuffle_init = 1;
+
state[0] = (uint32_t)x;
if (rand_type == TYPE_0)
lim = NSHUFF;
@@ -512,8 +528,8 @@ setstate(arg_state)
*
* Returns a 31-bit random number.
*/
-long
-random()
+static long
+random_old()
{
uint32_t i;
uint32_t *f, *r;
@@ -540,3 +556,87 @@ random()
}
return((long)i);
}
+
+long
+random()
+{
+ /*
+ * This function is a wrapper to the original random(), now renamed
+ * random_old(), to interpose a shuffle buffer to dramatically extend
+ * the generator period at nearly zero additional execution cost,
+ * and an additional storage cost set by the size of the
+ * shuffle buffer (default: 512 longs, or 2K or 4K bytes).
+ * The algorithm was first described in
+ *
+ * Carter Bays and S. D. Durham
+ * Improving a Poor Random Number Generator
+ * ACM Transactions on Mathematical Software (TOMS) 2(1) 59--64 (March 1976)
+ * http://dx.doi.org/10.1145/355666.355670
+ *
+ * and later revisited in
+ *
+ * Carter Bays
+ * C364. Improving a random number generator: a comparison between two shuffling methods
+ * Journal of Statistical Computation and Simulation 36(1) 57--59 (May 1990)
+ * http://dx.doi.org/10.1080/00949659008811264
+ *
+ * The second paper is critically important because it
+ * emphasizes how an apparently trivial change to the final
+ * element selection can destroy the period-lengthening
+ * feature of the original shuffle algorithm.
+ *
+ * Here is a table of the increase in period size for a
+ * shuffle generator using 32-bit and 64-bit unsigned integer
+ * linear congruential generators, which are known to have
+ * significant correlations, and are thus inadvisable for
+ * serious work with random numbers:
+ *
+ * hocd128> for (n = 32; n < 4096; n *= 2) \
+ * printf("%7d\t%12.3.4e\t%12.3.4e\n",
+ * n, \
+ * sqrt(PI * gamma(n + 1)/(2**32 - 1)) / (2**32 - 1), \\
+ * sqrt(PI * gamma(n + 1)/(2**64 - 1)) / (2**64 - 1))
+ *
+ * 32 3.230e+03 1.148e-11
+ * 64 2.243e+30 7.969e+15
+ * 128 3.910e+93 1.389e+79
+ * 256 1.844e+239 6.552e+224
+ * 512 1.174e+569 4.172e+554
+ * 1024 4.635e+1305 1.647e+1291
+ * 2048 8.144e+2932 2.893e+2918
+ *
+ * A generator giving one result per nanosecond would produce
+ * about 3.16e16 random numbers per year, so even for
+ * massively parallel operations with, say, one million CPU
+ * cores, it could not produce more than 10**23 values per
+ * year. The main benefit of an enormous period is that it
+ * makes long-range correlations vanishingly unlikely, even
+ * when starting seeds are similar (e.g., seeds of 0, 1, 2,
+ * ...), and therefore makes possible families of generators
+ * (needed in parallel computations) where the probability of
+ * sequence overlap between family members is essentially
+ * zero.
+ */
+
+ int k;
+ long r;
+ static long s = 0xcafefeedL;
+
+ if (shuffle_init) { /* first time, or seed changed by srand() */
+ for (k = 0; k < SHUFFLE_MAX; k++)
+ shuffle_buffer[k] = random_old();
+
+ s = random_old();
+ shuffle_init = 0;
+ }
+
+ r = random_old();
+ k = s & SHUFFLE_MASK; /* random index into shuffle_buffer[] */
+
+ assert(0L <= k && k < SHUFFLE_MAX);
+
+ s = shuffle_buffer[k];
+ shuffle_buffer[k] = r;
+
+ return (s);
+}
diff --git a/random.h b/support/random.h
index d4c6ef16..84b31414 100644
--- a/random.h
+++ b/support/random.h
@@ -2,22 +2,22 @@
* random.h - redefine name of random lib routines to avoid conflicts
*/
-/*
+/*
* Copyright (C) 1996, 2001, 2004, 2005, 2013 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
diff --git a/regcomp.c b/support/regcomp.c
index 11c94fc1..c45e91fc 100644
--- a/regcomp.c
+++ b/support/regcomp.c
@@ -1,5 +1,5 @@
/* Extended regular expression matching and search library.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
@@ -216,7 +216,7 @@ static const size_t __re_error_msgid_idx[] =
#ifndef HAVE_BTOWC
-wchar_t
+wchar_t
btowc (int c)
{
wchar_t wtmp[2];
@@ -853,10 +853,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));
@@ -878,11 +874,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,10 +899,6 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
if (strcasecmp (codeset_name, "UTF-8") == 0
|| strcasecmp (codeset_name, "UTF8") == 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) */
/* We check exhaustively in the loop below if this charset is a
superset of ASCII. */
@@ -973,8 +961,9 @@ static void
internal_function
init_word_char (re_dfa_t *dfa)
{
- int i, j, ch;
dfa->word_ops_used = 1;
+ int i = 0;
+ int ch = 0;
#ifndef GAWK
if (BE (dfa->map_notascii == 0, 1))
{
@@ -1008,8 +997,8 @@ init_word_char (re_dfa_t *dfa)
}
#endif
- for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
- for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ for (; i < BITSET_WORDS; ++i)
+ for (int j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
if (isalnum (ch) || ch == '_')
dfa->word_char[i] |= (bitset_word_t) 1 << j;
}
diff --git a/regex.c b/support/regex.c
index 9f133fab..d3a44851 100644
--- a/regex.c
+++ b/support/regex.c
@@ -1,5 +1,5 @@
/* Extended regular expression matching and search library.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
diff --git a/regex.h b/support/regex.h
index 872c4b6e..adddd9ee 100644
--- a/regex.h
+++ b/support/regex.h
@@ -1,6 +1,6 @@
/* Definitions for data structures and routines for the regular
expression library.
- Copyright (C) 1985, 1989-2016 Free Software Foundation, Inc.
+ Copyright (C) 1985, 1989-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -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/support/regex_internal.c
index 18641ef1..2b3120c2 100644
--- a/regex_internal.c
+++ b/support/regex_internal.c
@@ -840,7 +840,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
}
static unsigned char
-internal_function __attribute__ ((__pure__))
+internal_function __attribute ((pure))
re_string_peek_byte_case (const re_string_t *pstr, int idx)
{
int ch, off;
@@ -1372,7 +1372,7 @@ re_node_set_insert_last (re_node_set *set, int elem)
return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
static int
-internal_function __attribute__ ((__pure__))
+internal_function __attribute ((pure))
re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
{
int i;
@@ -1387,7 +1387,7 @@ re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
static int
-internal_function __attribute__ ((__pure__))
+internal_function __attribute ((pure))
re_node_set_contains (const re_node_set *set, int elem)
{
unsigned int idx, right, mid;
diff --git a/regex_internal.h b/support/regex_internal.h
index 09f17b25..9f4ff070 100644
--- a/regex_internal.h
+++ b/support/regex_internal.h
@@ -1,5 +1,5 @@
/* Extended regular expression matching and search library.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
diff --git a/regexec.c b/support/regexec.c
index aee21173..14813596 100644
--- a/regexec.c
+++ b/support/regexec.c
@@ -1,5 +1,5 @@
/* Extended regular expression matching and search library.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
@@ -55,7 +55,8 @@ static int re_search_stub (struct re_pattern_buffer *bufp,
int ret_len) internal_function;
static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
int nregs, int regs_allocated) internal_function;
-static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx);
+static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
+ internal_function;
static int check_matching (re_match_context_t *mctx, int fl_longest_match,
int *p_match_first) internal_function;
static int check_halt_state_context (const re_match_context_t *mctx,
@@ -937,6 +938,7 @@ re_search_internal (const regex_t *preg, const char *string, int length,
}
static reg_errcode_t
+internal_function __attribute_warn_unused_result__
prune_impossible_nodes (re_match_context_t *mctx)
{
const re_dfa_t *const dfa = mctx->dfa;
@@ -1032,7 +1034,7 @@ prune_impossible_nodes (re_match_context_t *mctx)
since initial states may have constraints like "\<", "^", etc.. */
static inline re_dfastate_t *
-__attribute__ ((always_inline)) internal_function
+__attribute ((always_inline)) internal_function
acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
int idx)
{
@@ -2393,7 +2395,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
/* Skip bytes in the input that correspond to part of a
multi-byte match, then look in the log for a state
from which to restart matching. */
-static re_dfastate_t *
+re_dfastate_t *
internal_function
find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
{
diff --git a/support/verify.h b/support/verify.h
new file mode 100644
index 00000000..dcba9c8c
--- /dev/null
+++ b/support/verify.h
@@ -0,0 +1,284 @@
+/* Compile-time assert-like macros.
+
+ Copyright (C) 2005-2006, 2009-2017 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
+
+#ifndef _GL_VERIFY_H
+#define _GL_VERIFY_H
+
+
+/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert works as per C11.
+ This is supported by GCC 4.6.0 and later, in C mode, and its use
+ here generates easier-to-read diagnostics when verify (R) fails.
+
+ Define _GL_HAVE_STATIC_ASSERT to 1 if static_assert works as per C++11.
+ This will likely be supported by future GCC versions, in C++ mode.
+
+ Use this only with GCC. If we were willing to slow 'configure'
+ down we could also use it with other compilers, but since this
+ affects only the quality of diagnostics, why bother? */
+#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
+ && (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
+ && !defined __cplusplus)
+# define _GL_HAVE__STATIC_ASSERT 1
+#endif
+/* The condition (99 < __GNUC__) is temporary, until we know about the
+ first G++ release that supports static_assert. */
+#if (99 < __GNUC__) && defined __cplusplus
+# define _GL_HAVE_STATIC_ASSERT 1
+#endif
+
+/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
+ system headers, defines a conflicting _Static_assert that is no
+ better than ours; override it. */
+#ifndef _GL_HAVE_STATIC_ASSERT
+# include <stddef.h>
+# undef _Static_assert
+#endif
+
+/* Each of these macros verifies that its argument R is nonzero. To
+ be portable, R should be an integer constant expression. Unlike
+ assert (R), there is no run-time overhead.
+
+ If _Static_assert works, verify (R) uses it directly. Similarly,
+ _GL_VERIFY_TRUE works by packaging a _Static_assert inside a struct
+ that is an operand of sizeof.
+
+ The code below uses several ideas for C++ compilers, and for C
+ compilers that do not support _Static_assert:
+
+ * The first step is ((R) ? 1 : -1). Given an expression R, of
+ integral or boolean or floating-point type, this yields an
+ expression of integral type, whose value is later verified to be
+ constant and nonnegative.
+
+ * Next this expression W is wrapped in a type
+ struct _gl_verify_type {
+ unsigned int _gl_verify_error_if_negative: W;
+ }.
+ If W is negative, this yields a compile-time error. No compiler can
+ deal with a bit-field of negative size.
+
+ One might think that an array size check would have the same
+ effect, that is, that the type struct { unsigned int dummy[W]; }
+ would work as well. However, inside a function, some compilers
+ (such as C++ compilers and GNU C) allow local parameters and
+ variables inside array size expressions. With these compilers,
+ an array size check would not properly diagnose this misuse of
+ the verify macro:
+
+ void function (int n) { verify (n < 0); }
+
+ * For the verify macro, the struct _gl_verify_type will need to
+ somehow be embedded into a declaration. To be portable, this
+ declaration must declare an object, a constant, a function, or a
+ typedef name. If the declared entity uses the type directly,
+ such as in
+
+ struct dummy {...};
+ typedef struct {...} dummy;
+ extern struct {...} *dummy;
+ extern void dummy (struct {...} *);
+ extern struct {...} *dummy (void);
+
+ two uses of the verify macro would yield colliding declarations
+ if the entity names are not disambiguated. A workaround is to
+ attach the current line number to the entity name:
+
+ #define _GL_CONCAT0(x, y) x##y
+ #define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
+ extern struct {...} * _GL_CONCAT (dummy, __LINE__);
+
+ But this has the problem that two invocations of verify from
+ within the same macro would collide, since the __LINE__ value
+ would be the same for both invocations. (The GCC __COUNTER__
+ macro solves this problem, but is not portable.)
+
+ A solution is to use the sizeof operator. It yields a number,
+ getting rid of the identity of the type. Declarations like
+
+ extern int dummy [sizeof (struct {...})];
+ extern void dummy (int [sizeof (struct {...})]);
+ extern int (*dummy (void)) [sizeof (struct {...})];
+
+ can be repeated.
+
+ * Should the implementation use a named struct or an unnamed struct?
+ Which of the following alternatives can be used?
+
+ extern int dummy [sizeof (struct {...})];
+ extern int dummy [sizeof (struct _gl_verify_type {...})];
+ extern void dummy (int [sizeof (struct {...})]);
+ extern void dummy (int [sizeof (struct _gl_verify_type {...})]);
+ extern int (*dummy (void)) [sizeof (struct {...})];
+ extern int (*dummy (void)) [sizeof (struct _gl_verify_type {...})];
+
+ In the second and sixth case, the struct type is exported to the
+ outer scope; two such declarations therefore collide. GCC warns
+ about the first, third, and fourth cases. So the only remaining
+ possibility is the fifth case:
+
+ extern int (*dummy (void)) [sizeof (struct {...})];
+
+ * GCC warns about duplicate declarations of the dummy function if
+ -Wredundant-decls is used. GCC 4.3 and later have a builtin
+ __COUNTER__ macro that can let us generate unique identifiers for
+ each dummy function, to suppress this warning.
+
+ * This implementation exploits the fact that older versions of GCC,
+ which do not support _Static_assert, also do not warn about the
+ last declaration mentioned above.
+
+ * GCC warns if -Wnested-externs is enabled and verify() is used
+ within a function body; but inside a function, you can always
+ arrange to use verify_expr() instead.
+
+ * In C++, any struct definition inside sizeof is invalid.
+ Use a template type to work around the problem. */
+
+/* Concatenate two preprocessor tokens. */
+#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
+#define _GL_CONCAT0(x, y) x##y
+
+/* _GL_COUNTER is an integer, preferably one that changes each time we
+ use it. Use __COUNTER__ if it works, falling back on __LINE__
+ otherwise. __LINE__ isn't perfect, but it's better than a
+ constant. */
+#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
+# define _GL_COUNTER __COUNTER__
+#else
+# define _GL_COUNTER __LINE__
+#endif
+
+/* Generate a symbol with the given prefix, making it unique if
+ possible. */
+#define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
+
+/* Verify requirement R at compile-time, as an integer constant expression
+ that returns 1. If R is false, fail at compile-time, preferably
+ with a diagnostic that includes the string-literal DIAGNOSTIC. */
+
+#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
+ (!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
+
+#ifdef __cplusplus
+# if !GNULIB_defined_struct__gl_verify_type
+template <int w>
+ struct _gl_verify_type {
+ unsigned int _gl_verify_error_if_negative: w;
+ };
+# define GNULIB_defined_struct__gl_verify_type 1
+# endif
+# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+ _gl_verify_type<(R) ? 1 : -1>
+#elif defined _GL_HAVE__STATIC_ASSERT
+# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+ struct { \
+ _Static_assert (R, DIAGNOSTIC); \
+ int _gl_dummy; \
+ }
+#else
+# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
+ struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
+#endif
+
+/* Verify requirement R at compile-time, as a declaration without a
+ trailing ';'. If R is false, fail at compile-time, preferably
+ with a diagnostic that includes the string-literal DIAGNOSTIC.
+
+ Unfortunately, unlike C11, this implementation must appear as an
+ ordinary declaration, and cannot appear inside struct { ... }. */
+
+#ifdef _GL_HAVE__STATIC_ASSERT
+# define _GL_VERIFY _Static_assert
+#else
+# define _GL_VERIFY(R, DIAGNOSTIC) \
+ extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
+ [_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
+#endif
+
+/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
+#ifdef _GL_STATIC_ASSERT_H
+# if !defined _GL_HAVE__STATIC_ASSERT && !defined _Static_assert
+# define _Static_assert(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
+# endif
+# if !defined _GL_HAVE_STATIC_ASSERT && !defined static_assert
+# define static_assert _Static_assert /* C11 requires this #define. */
+# endif
+#endif
+
+/* @assert.h omit start@ */
+
+/* Each of these macros verifies that its argument R is nonzero. To
+ be portable, R should be an integer constant expression. Unlike
+ assert (R), there is no run-time overhead.
+
+ There are two macros, since no single macro can be used in all
+ contexts in C. verify_true (R) is for scalar contexts, including
+ integer constant expression contexts. verify (R) is for declaration
+ contexts, e.g., the top level. */
+
+/* Verify requirement R at compile-time, as an integer constant expression.
+ Return 1. This is equivalent to verify_expr (R, 1).
+
+ verify_true is obsolescent; please use verify_expr instead. */
+
+#define verify_true(R) _GL_VERIFY_TRUE (R, "verify_true (" #R ")")
+
+/* Verify requirement R at compile-time. Return the value of the
+ expression E. */
+
+#define verify_expr(R, E) \
+ (_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E))
+
+/* Verify requirement R at compile-time, as a declaration without a
+ trailing ';'. */
+
+#ifdef __GNUC__
+# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
+#else
+/* PGI barfs if R is long. Play it safe. */
+# define verify(R) _GL_VERIFY (R, "verify (...)")
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+/* Assume that R always holds. This lets the compiler optimize
+ accordingly. R should not have side-effects; it may or may not be
+ evaluated. Behavior is undefined if R is false. */
+
+#if (__has_builtin (__builtin_unreachable) \
+ || 4 < __GNUC__ + (5 <= __GNUC_MINOR__))
+# define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
+#elif 1200 <= _MSC_VER
+# define assume(R) __assume (R)
+#elif ((defined GCC_LINT || defined lint) \
+ && (__has_builtin (__builtin_trap) \
+ || 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))))
+ /* Doing it this way helps various packages when configured with
+ --enable-gcc-warnings, which compiles with -Dlint. It's nicer
+ when 'assume' silences warnings even with older GCCs. */
+# define assume(R) ((R) ? (void) 0 : __builtin_trap ())
+#else
+# define assume(R) ((void) (0 && (R)))
+#endif
+
+/* @assert.h omit end@ */
+
+#endif
diff --git a/xalloc.h b/support/xalloc.h
index 0d169cf9..89dbe2c1 100644
--- a/xalloc.h
+++ b/support/xalloc.h
@@ -138,6 +138,17 @@ xnmalloc (size_t n, size_t s)
#include <errno.h>
extern void r_fatal(const char *msg, ...) ATTRIBUTE_NORETURN ;
+void *
+xmalloc(size_t bytes)
+{
+ void *p;
+ if (bytes == 0)
+ bytes = 1; /* avoid dfa.c mishegos */
+ if ((p = malloc(bytes)) == NULL)
+ xalloc_die ();
+ return p;
+}
+
/* Allocate an array of N objects, each with S bytes of memory,
dynamically, with error checking. S must be nonzero.
Clear the contents afterwards. */
@@ -145,8 +156,12 @@ extern void r_fatal(const char *msg, ...) ATTRIBUTE_NORETURN ;
void *
xcalloc(size_t nmemb, size_t size)
{
- void *p = xmalloc (nmemb * size);
- memset(p, '\0', nmemb * size);
+ void *p;
+
+ if (nmemb == 0 || size == 0)
+ nmemb = size = 1; /* avoid dfa.c mishegos */
+ if ((p = calloc(nmemb, size)) == NULL)
+ xalloc_die ();
return p;
}
@@ -314,7 +329,7 @@ xcharalloc (size_t n)
inline void *
xzalloc (size_t s)
{
- return memset (xmalloc (s), 0, s);
+ return xcalloc(1, s);
}
# endif
diff --git a/symbol.c b/symbol.c
index fe7e3753..cbbd8ed2 100644
--- a/symbol.c
+++ b/symbol.c
@@ -2,22 +2,22 @@
* symbol.c - routines for symbol table management and code allocation
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2015 the Free Software Foundation, Inc.
- *
+ *
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
- *
+ *
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
@@ -37,7 +37,7 @@ static NODE *symbol_list;
static void (*install_func)(NODE *) = NULL;
static NODE *make_symbol(const char *name, NODETYPE type);
static NODE *install(const char *name, NODE *parm, NODETYPE type);
-static void free_bcpool(INSTRUCTION *pl);
+static void free_bcpool(INSTRUCTION_POOL *pl);
static AWK_CONTEXT *curr_ctxt = NULL;
static int ctxt_level;
@@ -71,7 +71,7 @@ init_symbol_table()
/*
* install_symbol:
* Install a global name in the symbol table, even if it is already there.
- * Caller must check against redefinition if that is desired.
+ * Caller must check against redefinition if that is desired.
*/
NODE *
@@ -129,12 +129,11 @@ make_params(char **pnames, int pcount)
{
NODE *p, *parms;
int i;
-
+
if (pcount <= 0 || pnames == NULL)
return NULL;
- emalloc(parms, NODE *, pcount * sizeof(NODE), "make_params");
- memset(parms, '\0', pcount * sizeof(NODE));
+ ezalloc(parms, NODE *, pcount * sizeof(NODE), "make_params");
for (i = 0, p = parms; i < pcount; i++, p++) {
p->type = Node_param_list;
@@ -242,12 +241,12 @@ destroy_symbol(NODE *r)
NODE *n;
int i;
int pcount = r->param_cnt;
-
- /* function parameters of type Node_param_list */
+
+ /* function parameters of type Node_param_list */
for (i = 0; i < pcount; i++) {
n = r->fparms + i;
efree(n->param);
- }
+ }
efree(r->fparms);
}
break;
@@ -260,7 +259,7 @@ destroy_symbol(NODE *r)
assoc_clear(r);
break;
- case Node_var:
+ case Node_var:
unref(r->var_value);
break;
@@ -369,7 +368,7 @@ comp_symbol(const void *v1, const void *v2)
typedef enum { FUNCTION = 1, VARIABLE } SYMBOL_TYPE;
/* get_symbols --- return a list of optionally sorted symbols */
-
+
static NODE **
get_symbols(SYMBOL_TYPE what, bool sort)
{
@@ -448,7 +447,7 @@ function_list(bool sort)
return get_symbols(FUNCTION, sort);
}
-/* print_vars --- print names and values of global variables */
+/* print_vars --- print names and values of global variables */
void
print_vars(NODE **table, int (*print_func)(FILE *, const char *, ...), FILE *fp)
@@ -652,7 +651,7 @@ check_param_names(void)
memset(& n, 0, sizeof n);
n.type = Node_val;
n.flags = STRING|STRCUR;
- n.stfmt = -1;
+ n.stfmt = STFMT_UNUSED;
/*
* assoc_list() returns an array with two elements per awk array
@@ -693,22 +692,31 @@ check_param_names(void)
return result;
}
-#define pool_size d.dl
-#define freei x.xi
-static INSTRUCTION *pool_list;
+static INSTRUCTION_POOL *pools;
+
+/*
+ * For best performance, the INSTR_CHUNK value should be divisible by all
+ * possible sizes, i.e. 1 through MAX_INSTRUCTION_ALLOC. Otherwise, there
+ * will be wasted space at the end of the block.
+ */
+#define INSTR_CHUNK (2*3*21)
-/* INSTR_CHUNK must be > largest code size (3) */
-#define INSTR_CHUNK 127
+struct instruction_block {
+ struct instruction_block *next;
+ INSTRUCTION i[INSTR_CHUNK];
+};
/* bcfree --- deallocate instruction */
void
bcfree(INSTRUCTION *cp)
{
- cp->opcode = 0;
- cp->nexti = pool_list->freei;
- pool_list->freei = cp;
-}
+ assert(cp->pool_size >= 1 && cp->pool_size <= MAX_INSTRUCTION_ALLOC);
+
+ cp->opcode = Op_illegal;
+ cp->nexti = pools->pool[cp->pool_size - 1].free_list;
+ pools->pool[cp->pool_size - 1].free_list = cp;
+}
/* bcalloc --- allocate a new instruction */
@@ -716,38 +724,28 @@ INSTRUCTION *
bcalloc(OPCODE op, int size, int srcline)
{
INSTRUCTION *cp;
+ struct instruction_mem_pool *pool;
- if (size > 1) {
- /* wide instructions Op_rule, Op_func_call .. */
- emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), "bcalloc");
- cp->pool_size = size;
- cp->nexti = pool_list->nexti;
- pool_list->nexti = cp++;
+ assert(size >= 1 && size <= MAX_INSTRUCTION_ALLOC);
+ pool = &pools->pool[size - 1];
+
+ if (pool->free_list != NULL) {
+ cp = pool->free_list;
+ pool->free_list = cp->nexti;
+ } else if (pool->free_space && pool->free_space + size <= & pool->block_list->i[INSTR_CHUNK]) {
+ cp = pool->free_space;
+ pool->free_space += size;
} else {
- INSTRUCTION *pool;
-
- pool = pool_list->freei;
- if (pool == NULL) {
- INSTRUCTION *last;
- emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * sizeof(INSTRUCTION), "bcalloc");
-
- cp->pool_size = INSTR_CHUNK;
- cp->nexti = pool_list->nexti;
- pool_list->nexti = cp;
- pool = ++cp;
- last = &pool[INSTR_CHUNK - 1];
- for (; cp <= last; cp++) {
- cp->opcode = 0;
- cp->nexti = cp + 1;
- }
- --cp;
- cp->nexti = NULL;
- }
- cp = pool;
- pool_list->freei = cp->nexti;
+ struct instruction_block *block;
+ emalloc(block, struct instruction_block *, sizeof(struct instruction_block), "bcalloc");
+ block->next = pool->block_list;
+ pool->block_list = block;
+ cp = &block->i[0];
+ pool->free_space = &block->i[size];
}
memset(cp, 0, size * sizeof(INSTRUCTION));
+ cp->pool_size = size;
cp->opcode = op;
cp->source_line = srcline;
return cp;
@@ -760,8 +758,7 @@ new_context()
{
AWK_CONTEXT *ctxt;
- emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
- memset(ctxt, 0, sizeof(AWK_CONTEXT));
+ ezalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
ctxt->srcfiles.next = ctxt->srcfiles.prev = & ctxt->srcfiles;
ctxt->rule_list.opcode = Op_list;
ctxt->rule_list.lasti = & ctxt->rule_list;
@@ -773,7 +770,7 @@ new_context()
static void
set_context(AWK_CONTEXT *ctxt)
{
- pool_list = & ctxt->pools;
+ pools = & ctxt->pools;
symbol_list = & ctxt->symbols;
srcfiles = & ctxt->srcfiles;
rule_list = & ctxt->rule_list;
@@ -804,7 +801,7 @@ push_context(AWK_CONTEXT *ctxt)
ctxt_level++;
}
-/* pop_context --- switch to previous execution context. */
+/* pop_context --- switch to previous execution context. */
void
pop_context()
@@ -831,7 +828,7 @@ in_main_context()
return (ctxt_level == 1);
}
-/* free_context --- free context structure and related data. */
+/* free_context --- free context structure and related data. */
void
free_context(AWK_CONTEXT *ctxt, bool keep_globals)
@@ -864,7 +861,7 @@ free_context(AWK_CONTEXT *ctxt, bool keep_globals)
efree(ctxt);
}
-/* free_bc_internal --- free internal memory of an instruction. */
+/* free_bc_internal --- free internal memory of an instruction. */
static void
free_bc_internal(INSTRUCTION *cp)
@@ -881,14 +878,16 @@ free_bc_internal(INSTRUCTION *cp)
case Op_match:
case Op_nomatch:
m = cp->memory;
- if (m->re_reg != NULL)
- refree(m->re_reg);
+ if (m->re_reg[0] != NULL)
+ refree(m->re_reg[0]);
+ if (m->re_reg[1] != NULL)
+ refree(m->re_reg[1]);
if (m->re_exp != NULL)
unref(m->re_exp);
if (m->re_text != NULL)
unref(m->re_text);
freenode(m);
- break;
+ break;
case Op_token:
/* token lost during error recovery in yyparse */
if (cp->lextok != NULL)
@@ -906,31 +905,40 @@ free_bc_internal(INSTRUCTION *cp)
case Op_illegal:
cant_happen();
default:
- break;
+ break;
}
}
-/* free_bcpool --- free list of instruction memory pools */
+/* free_bc_mempool --- free a single pool */
static void
-free_bcpool(INSTRUCTION *pl)
+free_bc_mempool(struct instruction_mem_pool *pool, int size)
{
- INSTRUCTION *pool, *tmp;
+ bool first = true;
+ struct instruction_block *block, *next;
- for (pool = pl->nexti; pool != NULL; pool = tmp) {
- INSTRUCTION *cp, *last;
- long psiz;
- psiz = pool->pool_size;
- if (psiz == INSTR_CHUNK)
- last = pool + psiz;
- else
- last = pool + 1;
- for (cp = pool + 1; cp <= last ; cp++) {
- if (cp->opcode != 0)
+ for (block = pool->block_list; block; block = next) {
+ INSTRUCTION *cp, *end;
+
+ end = (first ? pool->free_space : & block->i[INSTR_CHUNK]);
+ for (cp = & block->i[0]; cp + size <= end; cp += size) {
+ if (cp->opcode != Op_illegal)
free_bc_internal(cp);
}
- tmp = pool->nexti;
- efree(pool);
+ next = block->next;
+ efree(block);
+ first = false;
}
- memset(pl, 0, sizeof(INSTRUCTION));
+}
+
+
+/* free_bcpool --- free list of instruction memory pools */
+
+static void
+free_bcpool(INSTRUCTION_POOL *pl)
+{
+ int i;
+
+ for (i = 0; i < MAX_INSTRUCTION_ALLOC; i++)
+ free_bc_mempool(& pl->pool[i], i + 1);
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 00000000..fee5eeca
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,90 @@
+#
+# test/CMakeLists.txt --- CMake input file for gawk
+#
+# Copyright (C) 2013
+# the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## process this file with CMake to produce Makefile
+
+if(WIN32)
+ set(SHELL_PREFIX "C:\\MinGW\\msys\\1.0\\bin\\sh")
+endif()
+
+# Find the names of the groups of tests in Makefile.am.
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am ALL_GROUPS)
+string(REGEX MATCHALL "[A-Z_]*_TESTS " ALL_GROUPS "${ALL_GROUPS}")
+string(REGEX REPLACE "_TESTS " ";" ALL_GROUPS "${ALL_GROUPS}")
+# For each group of test cases, search through Makefile.am and find the test cases.
+foreach(testgroup ${ALL_GROUPS} )
+ file(READ ${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am ONE_GROUP)
+ string(REGEX MATCH "${testgroup}_TESTS = [a-z0-9_ \\\n\t]*" ONE_GROUP "${ONE_GROUP}")
+ string(REGEX REPLACE "${testgroup}_TESTS = " "" ONE_GROUP "${ONE_GROUP}")
+ string(REGEX REPLACE "[\\\n\t]" "" ONE_GROUP "${ONE_GROUP}")
+ string(REGEX REPLACE " " ";" ONE_GROUP "${ONE_GROUP}")
+ # Use each name of a test case to start a script that executes the test case.
+ foreach(testcase ${ONE_GROUP} )
+ add_test("${testgroup}.${testcase}" ${SHELL_PREFIX} ${CMAKE_SOURCE_DIR}/cmake/basictest ${CMAKE_BINARY_DIR}/gawk${CMAKE_EXECUTABLE_SUFFIX} ${testcase})
+ endforeach(testcase)
+endforeach(testgroup)
+
+# Create an empty configuration file for customizing test execution.
+set(CTestCustom ${CMAKE_BINARY_DIR}/CTestCustom.cmake)
+file(WRITE ${CTestCustom} "# DO NOT EDIT, THIS FILE WILL BE OVERWRITTEN\n" )
+# Test case SHLIB.filefuncs needs a file named gawkapi.o in source directory.
+file(APPEND ${CTestCustom} "file(COPY ${CMAKE_SOURCE_DIR}/README DESTINATION ${CMAKE_SOURCE_DIR}/gawkapi.o)\n")
+# Exclude test cases from execution that make no sense on a certain platform.
+file(APPEND ${CTestCustom} "set(CTEST_CUSTOM_TESTS_IGNORE\n")
+if(WIN32)
+ file(APPEND ${CTestCustom} " BASIC.exitval2\n")
+ file(APPEND ${CTestCustom} " BASIC.hsprint\n")
+ file(APPEND ${CTestCustom} " BASIC.rstest4\n")
+ file(APPEND ${CTestCustom} " BASIC.rstest5\n")
+ file(APPEND ${CTestCustom} " UNIX.getlnhd\n")
+ file(APPEND ${CTestCustom} " UNIX.pid\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.beginfile1\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.beginfile2\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.clos1way\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.devfd\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.devfd1\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.devfd2\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.getlndir\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.posix\n")
+ file(APPEND ${CTestCustom} " GAWK_EXT.pty1\n")
+ file(APPEND ${CTestCustom} " INET.inetdayu\n")
+ file(APPEND ${CTestCustom} " INET.inetdayt\n")
+ file(APPEND ${CTestCustom} " INET.inetechu\n")
+ file(APPEND ${CTestCustom} " INET.inetecht\n")
+ file(APPEND ${CTestCustom} " MACHINE.double2\n")
+ file(APPEND ${CTestCustom} " LOCALE_CHARSET.fmttest\n")
+ file(APPEND ${CTestCustom} " LOCALE_CHARSET.lc_num1\n")
+ file(APPEND ${CTestCustom} " LOCALE_CHARSET.mbfw1\n")
+ file(APPEND ${CTestCustom} " SHLIB.filefuncs\n")
+ file(APPEND ${CTestCustom} " SHLIB.fnmatch\n")
+ file(APPEND ${CTestCustom} " SHLIB.fork\n")
+ file(APPEND ${CTestCustom} " SHLIB.fork2\n")
+ file(APPEND ${CTestCustom} " SHLIB.fts\n")
+ file(APPEND ${CTestCustom} " SHLIB.functab4\n")
+ file(APPEND ${CTestCustom} " SHLIB.readdir\n")
+ file(APPEND ${CTestCustom} " SHLIB.revtwoway\n")
+ file(APPEND ${CTestCustom} " SHLIB.rwarray\n")
+endif()
+file(APPEND ${CTestCustom} ")\n")
+
diff --git a/test/ChangeLog b/test/ChangeLog
index 04756281..165d0ccf 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,67 @@
+2017-06-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (mbprintf5): Skip this test on Cygwin.
+
+2017-06-22 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile4.ok, profile5.ok, profile7.ok: Updated after code changes.
+ * profile7.awk: Added two more statements.
+
+2017-06-18 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (mbprintf5): New test.
+ * mbprintf5.awk, mbprintf5.in, mbprintf5.ok: New files.
+
+2017-05-24 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * fwtest8.ok: Fix field number in error message, thanks to a bug
+ report from Michal Jaegermann.
+
+2017-05-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (fwtest5, fwtest6, fwtest7, fwtest8): New tests.
+ * fwtest5.awk, fwtest5.in, fwtest5.ok, fwtest6.awk, fwtest6.in,
+ fwtest6.ok, fwtest7.awk, fwtest7.in, fwtest7.ok, fwtest8.awk,
+ fwtest8.in, fwtest8.ok: New files.
+
+2017-05-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * noeffect.awk, noeffect.ok: Updated after code change.
+
+2017-05-01 Aharon Robbins <aharon.robbins@intel.com>
+
+ * Makefile.am (sourcesplit): New test.
+ * sourcesplit.ok: New file.
+ Thanks to Hermann Peifer for the report.
+
+ Unrelated:
+
+ * Makefile.am (charset-msg-start): Document that having
+ el_GR.iso88597 is helpful.
+
+2017-04-12 Manuel Collado <m-collado@users.sourceforge.net>
+
+ * Makefile.am (fpat6): New test.
+ * fpat6.awk, fpat6.in, fpat6.ok: New files.
+ Check for the bug reported by Ed Morton in the bug-gawk mailing list.
+ * patsplit.ok: Updated to the new patsplit behavior.
+
+2017-04-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (memleak): New test.
+ * memleak.awk, memleak.ok: New files.
+
+2017-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * fwtest4: Renamed from fwtest3.
+ * fwtest3: Renamed from fwtest2b.
+ * Makefile.am: Updated.
+
+2017-03-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (fwtest2b): Add new test of enhanced FIELDWIDTHS syntax.
+ * fwtest2b.awk, fwtest2b.ok: New files.
+
2017-03-19 Andrew J. Schorr <aschorr@telemetry-investments.com>
* Makefile.am (argarray): Always copy argarray.in to the local
@@ -5,17 +69,54 @@
$(srcdir) is the current directory.
* argarray.ok: Replace argarray.in with argarray.input.
+2017-03-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (readdir_test): New test to check whether get_record
+ field_width parsing is working by comparing the results from the
+ readdir and readdir_test extensions.
+ (SHLIB_TESTS): Add readdir_test.
+
+2017-02-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (mktime): New test.
+ * mktime.awk, mktime.in, mktime.ok: New files.
+
+2017-02-17 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (typeof5): New test.
+ * typeof5.awk, typeof5.in, typeof5.ok: New files.
+ Thanks to Andrew Schorr for part of the tests.
+
2017-01-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
* Makefile.am (gensub3): New test.
* gensub3.awk, gensub3.in, gensub3.ok: New files.
+2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (strftfld): New test.
+ * strftfld.awk, strftfld.in, strftfld.ok: New files.
+
2017-01-15 Andrew J. Schorr <aschorr@telemetry-investments.com>
* Makefile.am (concat5): New test.
* concat5.awk, concat5.ok: New files.
Check for bug forwarded by Corinna Vinschen from Cygwin mailing list.
+2016-12-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * rwarray.awk: Check that strnum is recreated correctly.
+
+2016-11-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * rwarray.awk: Use typeof() to verify that typed regex is
+ created correctly upon reading.
+
+2016-11-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ * rwarray.awk: Add a typed regex into the array before
+ writing it out and reading it back.
+
2016-11-21 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (EXTRA_DIST): Add valgrind.awk to the list.
@@ -28,10 +129,59 @@
Add check for invalid read and write.
* Makefile.am (valgrind-scan): Use valgrind.awk.
+2016-11-04 Fabio Berton <fabio.berton@ossystems.com.br>
+
+ * arrayind1.awk: Remove "#!/usr/local/bin/awk -f" as none of the
+ other awk scripts in the test suite have a hashbang.
+
+2016-10-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ * mpfrmemok1.ok: Update after code change.
+
+2016-09-09 Norihiro Tanaka <noritnk@kcn.ne.jp>
+
+ * Makefile.am (anchor): New test.
+ * anchor.awk, anchor.in, anchor.ok: New files.
+
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.4: Release tar ball made.
+2016-08-16 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (arrdbg): New test using adump.
+ (ARRAYDEBUG_TESTS): New test group requiring ARRAYDEBUG compilation.
+ (check): Add arraydebug-tests.
+ (arraydebug-tests): Check $(ARRAYDEBUG_TESTS) when compiled with
+ ARRAYDEBUG.
+ * arrdbg.awk: New test using adump to check array type.
+
+2016-08-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * intarray.awk, intarray.ok: Updated.
+
+2016-08-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ Restore typed regexp tests.
+
+ * typeof1.awk, typeof1.ok: Adjusted.
+ * typeof3.awk, typeof3.ok: Adjusted.
+ * gsubind.awk, gsubind.ok: Adjusted.
+ * Makefile.am (TYPED_RE_TESTS): Removed.
+ (dbugtypedre1, dbugtypedre2, typedregex1, typedregex2,
+ typedregex3): Moved back into regular tests.
+
+2016-08-03 Arnold D. Robbins <arnold@skeeve.com>
+
+ Remove typed regexes until they can be done correctly.
+
+ * typeof1.awk, typeof1.ok: Adjusted.
+ * typeof3.awk, typeof3.ok: Adjusted.
+ * gsubind.awk, gsubind.ok: Adjusted.
+ * Makefile.am (TYPED_RE_TESTS): New macro to hold typed regexp tests.
+ (dbugtypedre1, dbugtypedre2, typedregex1, typedregex2,
+ typedregex3): Moved into it.
+
2016-08-01 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (ignrcas3): Adjust to check that the el_GR.xxx locale
@@ -50,17 +200,81 @@
* ignrcas3.awk, ignrcas3.ok: New files.
Based on test code from Norihiro Tanaka <noritnk@kcn.ne.jp>.
+ * Makefile.am (ignrcas4): New test.
+ * ignrcas4.awk, ignrcas4.ok: Andrew Schorr's files, renamed.
+
+2016-07-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (status-close): New test.
+ * status-close.awk, status-close.ok: New files.
+
2015-06-17 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (ofmtstrnum): New test.
* ofmtstrnum.awk, ofmtstrnum.ok: New files.
+2016-07-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (EXTRA_DIST): Remove clos1way6.ok2.
+ (close1way6): Removed test, it will be autogenerated back into
+ the right place.
+ * clos1way6.awk: Use gensub on ERRNO to force the right text.
+ Thanks to Andrew Schorr for the suggestion.
+ * clos1way6.ok2: Removed.
+
+2016-07-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (clos1way6): Add additional file to check result
+ against for 32 bit Solaris. Thanks to Dagobert Michelsen for
+ the report.
+ * clos1way6.ok2: New file.
+
+2016-07-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (apiterm, fldterm): New tests to make sure that we
+ are handling unterminated field string values properly.
+ * apiterm.awk, apiterm.in, apiterm.ok: New files.
+ * fldterm.awk, fldterm.in, fldterm.ok: New files.
+
+2016-07-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * forcenum.awk: We no longer need to force the strnum conversion,
+ since typeof now does this automatically.
+ * forcenum.ok: Change "number" to "strnum" for the numeric strings.
+ * rebuild.in: Change input to include a strnum.
+ * rebuild.ok: Update results.
+
+2016-07-04 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (arrayind3): New test.
+ * arrayind3.awk, arrayind3.ok: New files.
+
+2016-07-03 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (rebuild): New test.
+ * rebuild.awk, rebuild.in, rebuild.ok: New files.
+
2016-07-01 Arnold D. Robbins <arnold@skeeve.com>
* arrayind1.awk, arrayind1.ok: Comment out prints to stderr to
avoid buffer flushing on obscure systems.
* dumpvars.ok, symtab6.ok, symtab8.ok: Update after code changes.
+2016-06-26 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * strnum2.ok: Fix results, since print for a strnum should not be
+ affected by OFMT or CONVFMT.
+
+2016-06-22 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * strnum2.awk, strnum2.ok: Improve test case to show both OFMT and
+ CONVFMT conversions.
+
+2016-06-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (strnum2): New test.
+ * strnum2.awk, strnum2.ok: New files.
+
2016-06-14 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (subback): New test.
@@ -78,6 +292,18 @@
* mixed1.ok: Adjust to match what the code produces.
Thanks to John E. Malmberg <wb8tyw@qsl.net> for the report.
+2016-06-13 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (forcenum, ignrcas3, intarray, lintexp, lintindex,
+ lintint, lintlength, lintset, mpfrstrtonum, mpgforcenum, printfchar,
+ strtonum1): New tests.
+ * forcenum.awk, forcenum.ok, ignrcas3.awk, ignrcas3.ok, intarray.awk,
+ intarray.ok, lintexp.awk, lintexp.ok, lintindex.awk, lintindex.ok,
+ lintint.awk, lintint.ok, lintlength.awk, lintlength.ok, lintset.awk,
+ lintset.ok, mpfrstrtonum.awk, mpfrstrtonum.ok, mpgforcenum.awk,
+ mpgforcenum.ok, printfchar.awk, printfchar.ok, strtonum1.awk,
+ strtonum1.ok: New files.
+
2016-06-08 Arnold D. Robbins <arnold@skeeve.com>
* symtab10.awk, symtab10.in, symtab10.ok: New files.
@@ -94,6 +320,12 @@
* Makefile.am (fsnul1): New test.
* fsnul1.awk, fsnul1.in, fsnul1.ok: New files.
+2016-05-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (arrayind2): New test.
+ * arrayind2.awk, arrayind2.ok: New files.
+ Thanks to Andrew J. Schorr <aschorr@telemetry-investments.com>.
+
2016-05-25 Arnold D. Robbins <arnold@skeeve.com>
* arrayind1.awk: Flush writes to stderr. We hope this helps
@@ -144,6 +376,11 @@
* clos1way2.ok, clos1way3.ok, clos1way4.ok: Updated after
code changes.
+2016-04-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (clos1way6): New test.
+ * clos1way6.awk, clos1way6.ok: New files.
+
2016-04-04 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (clos1way2, clos1way3, clos1way4, clos1way5):
@@ -154,10 +391,36 @@
* clos1way2.awk: Add call to fflush() to test it too.
* clos1way2.ok: Updated after code change.
+2016-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile5.ok: Adjust after code changes.
+
+2016-03-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile5.ok, profile10.awk, profile10.ok: Adjust after code changes.
+
+2016-03-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile5.ok: Adjust after code changes.
+ * Makefile.am (profile10): New test.
+ * profile10.awk, profile10.ok: New files.
+
+2016-02-21 Nelson H.F. Beebe <beebe@math.utah.edu>
+
+ * rand.ok: Updated after code change.
+
2016-02-18 Arnold D. Robbins <arnold@skeeve.com>
* profile2.ok, profile5.ok: Adjust after code changes.
+2016-02-05 Arnold D. Robbins <arnold@skeeve.com>
+
+ * badargs.ok: Update after adding Yet Another Command Line Option.
+
+2016-01-28 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (EXTRA_DIST): Add profile9.awk and profile9.ok.
+
2016-01-14 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (aryprm9): New test.
@@ -169,9 +432,16 @@
2015-12-27 Arnold D. Robbins <arnold@skeeve.com>
+ These came in from gawk-4.1-stable:
+
* Makefile.am (profile8): New test.
* profile8.awk, profile8.ok: New files.
+ These used to be profile8:
+
+ * Makefile.am (profile9): Renamed.
+ * profile9.awk, profile9.ok: Renamed files.
+
2015-11-24 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (watchpoint1): New test.
@@ -221,10 +491,65 @@
* Makefile.am (mbstr2): New test.
* mbstr2.awk, mbstr2.in, mbstr2.ok: New files.
+2015-06-29 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (dbugeval2, typedregex3): New tests.
+ * dbugeval2.awk, dbugeval2.in, dbugeval2.ok: New files.
+ * typedregex3.awk, typedregex3.ok: New files.
+ Thanks to Hermann Peifer for the reports.
+
+2015-06-28 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (typedregex2): New test.
+ * typedregex2.awk, typedregex2.ok: New files.
+ Thanks to Hermann Peifer for the report.
+
+2015-06-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (dbugtypedre1): Renamed from dbugtypedre.
+ (dbugtypedre2): New test.
+ * dbugtypedre1.awk, dbugtypedre1.in, dbugtypedre1.ok: Renamed files.
+ * dbugtypedre2.awk, dbugtypedre2.in, dbugtypedre2.ok: New files.
+
+ Unrelated:
+
+ * id.ok: Update after code changes.
+
+ Unrelated:
+
+ * Makefile.am (getfile, dbugtypedre1, dbugtypedre2): Fixed to
+ work if building out of the source tree.
+
+ Unrelated:
+
+ * dbugtypedre1.ok, typedregex1.awk, typeof1.ok, typeof3.ok:
+ Update after code changes.
+
2015-06-25 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (negtime): Fix out-of-tree test run.
+ Unrelated:
+
+ * Makefile.am (typeof3, typeof4): New tests.
+ * typeof2.awk, typeof2.ok, typeof3.awk, typeof3.ok: New files.
+
+ Unrelated:
+
+ * Makefile.am (dbugtypedre): New tests.
+ * dbugtypedre.awk, dbugtypedre.in, dbugtypedre.ok: New files.
+
+2015-06-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (typeof2): New test.
+ * typeof2.awk, typeof2.ok: New files.
+
+2015-06-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (gsubind, typedregex1, typeof1): New tests.
+ * gsubind.awk, gsubind.ok, typedregex1.awk, typedregex1.ok,
+ typeof1.awk, typeof1.ok: New files.
+
2015-06-17 Andrew J. Schorr <aschorr@telemetry-investments.com>
* inplace1.ok, inplace2.ok, inplace3.ok: Update line number in error
@@ -274,6 +599,11 @@
* regexpbrack2.awk, regexpbrack2.in, regexpbrack2.ok: New files.
Thanks to Nelson Beebe.
+2015-04-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (shadowbuiltin): New test.
+ * shadowbuiltin.awk, shadowbuiltin.ok: New files.
+
2015-04-14 Arnold D. Robbins <arnold@skeeve.com>
* indirectbuiltin.awk: Add another test (gensub 3 args).
@@ -298,11 +628,22 @@
* Makefile.am (mpfrmemok1): Use -p- for portability and
compatibility with pc/Makefile.tst.
+2015-04-02 Arnold D. Robbins <arnold@skeeve.com>
+
+ * id.ok, mpfrsqrt.awk: Update after rename of div() --> intdiv().
+
2015-03-31 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (indirectbuiltin): New test.
* indirectbuiltin.awk, indirectbuiltin.ok: New files.
+2015-03-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am: Remove defvar test and reference to files; test
+ code moved into extension/testext.c.
+ * defvar.awk, defvar.ok: Removed.
+ * testext.ok: Updated.
+
2015-03-24 Arnold D. Robbins <arnold@skeeve.com>
* id.ok: Update after fixes in code.
@@ -328,11 +669,38 @@
* Makefile.am (fpat4): New test.
* fpat4.awk, fpat4.ok: New files.
+2015-03-08 Arnold D. Robbins <arnold@skeeve.com>
+
+ * nonfatal3.awk, nonfatal3.ok: Adjust for portability.
+ Thanks to Hermann Peifer for the report.
+
2015-03-06 Arnold D. Robbins <arnold@skeeve.com>
* charasbytes.awk, ofs1.awk, range1.awk, sortglos.awk,
sortglos.in: Remove execute permission.
+2015-03-02 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * nonfatal1.awk: Do not print ERRNO, since the value appears to be
+ platform-dependent. Instead, print (ERRNO != "").
+ * nonfatal1.ok: Update.
+
+2015-02-28 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add nonfatal3.{awk,ok}.
+ (GAWK_EXT_TESTS): Add nonfatal3.
+ * nonfatal1.awk: Replace "ti10/357" with "local:host/25", since
+ "local:host" should be a universally bad hostname due to the
+ invalid ":" character.
+ * nonfatal1.ok: Update.
+ * nonfatal3.{awk,ok}: New test for connecting to a TCP port where
+ nobody is listening.
+
+2015-02-27 Arnold D. Robbins <arnold@skeeve.com>
+
+ * nonfatal1.ok: Update after code changes.
+ * id.ok: Updated after code change.
+
2015-02-26 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (EXTRA_DIST): Add profile0.in which got forgotten
@@ -348,6 +716,16 @@
* Makefile.am (profile0): New test.
* profile0.awk, profile0.in, profile0.ok: New files.
+2015-02-08 Arnold D. Robbins <arnold@skeeve.com>
+
+ * nonfatal1.awk, nonfatal2.awk: String is now "NONFATAL".
+
+2015-02-06 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (nonfatal1, nonfatal2): New tests.
+ * nonfatal1.awk, nonfatal1.ok: New files.
+ * nonfatal2.awk, nonfatal2.ok: New files.
+
2015-02-01 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (paramasfunc1, paramasfunc2): Now need --posix.
@@ -361,6 +739,16 @@
* paramasfunc2.awk, paramasfunc2.ok: New files.
* exit.sh, indirectcall.awk: Update after code change.
+2015-01-19 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (profile8): Actually add the test and the files.
+ Thanks to Hermann Peifer for the report.
+
+2015-01-16 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (profile8): New test.
+ * profile8.awk, profile8.ok: New files.
+
2015-01-14 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (dumpvars): Grep out ENVIRON and PROCINFO since
@@ -381,6 +769,34 @@
* testext.ok: Adjust for code changes.
+2015-01-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add defvar.awk and defvar.ok.
+ (SHLIB_TESTS): Add defvar.
+ (defvar): New test.
+ * defvar.awk, defvar.ok: New files.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add getfile.awk and getfile.ok.
+ (SHLIB_TESTS): Add getfile.
+ (getfile): New test.
+ * getfile.awk, getfile.ok: New files.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add timeout.awk and timeout.ok.
+ (BASIC_TESTS): Remove errno.
+ (GAWK_EXT_TESTS): Add errno and timeout.
+ * timeout.awk, timeout.ok: New files.
+
+2015-01-05 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add errno.awk, errno.in, and errno.ok.
+ (BASIC_TESTS): Add errno.
+ (errno): New test.
+ * errno.awk, errno.in, errno.ok: New files.
+
2014-12-24 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (badbuild): New test.
@@ -392,6 +808,10 @@
and exit 1. Should help distros to notice when they have built
gawk incorrectly. (Can you say "Fedora", boys and girls?)
+2014-12-12 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile5.ok: Updated after code changes.
+
2014-11-26 Arnold D. Robbins <arnold@skeeve.com>
* Gentests: Fix gensub call after adding warning.
@@ -404,12 +824,17 @@
* Makefile.am (sortglos): New test.
* sortglos.awk, sortglos.in, sortglos.ok: New files.
+ Thanks to Antonio Columbo.
2014-11-09 Arnold D. Robbins <arnold@skeeve.com>
* mbprintf4.awk: Add record and line number for debugging.
* mpprint4.ok: Adjust.
+2014-11-06 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * testext.ok: Add results from new test_get_file test.
+
2014-11-02 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (profile7): New test.
@@ -461,6 +886,16 @@
* filefuncs.awk: Change to build directory instead of "..".
* Makefile.am (filefuncs): Pass in $(abs_top_builddir).
+2014-09-13 Stephen Davies <sdavies@sdc.com.au>
+
+ * Makefile.am (profile4, profile5): Changes processing to not delete
+ the first two lines. This is no longer needed.
+ * profile4.ok, profile5.ok: Changed to suit new rules and comments.
+
+2014-09-10 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile2.ok, profile4.ok, profile5.ok: Update for new code.
+
2014-09-05 Arnold D. Robbins <arnold@skeeve.com>
* functab4.awk: Changed to use stat instead of chdir since
@@ -507,6 +942,11 @@
* printhuge.awk, printhuge.ok: New files.
Test from mail.green.fox@gmail.com.
+2014-06-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (profile1, profile4, profile5): Adjust for change to
+ --pretty-print option.
+
2014-06-19 Michael Forney <forney@google.com>
* Makefile.am (poundbang): Fix relative path of AWKPROG.
@@ -723,6 +1163,12 @@
* Makefile.am (badassign1): New test.
* badassign1.awk, badassign1.ok: New files.
+2013-09-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makfile.am (randtest): New test.
+ * randtest.sh, randtest.ok: New files.
+ * rand.ok: Updated to reflect new results based on code change.
+
2013-09-13 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am: Fix quoting for generation of Maketests file so
@@ -739,6 +1185,10 @@
in locations with spaces in their names (think Windows or Mac OS X).
* Gentests: Ditto for when creating Maketests file.
+2013-07-30 Arnold D. Robbins <arnold@skeeve.com>
+
+ * profile2.ok, profile5.ok: Update.
+
2013-07-04 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (mbprintf4): New test.
diff --git a/test/Makefile.am b/test/Makefile.am
index 445e77c6..b407ee8b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -47,6 +47,12 @@ EXTRA_DIST = \
anchgsub.awk \
anchgsub.in \
anchgsub.ok \
+ anchor.awk \
+ anchor.in \
+ anchor.ok \
+ apiterm.awk \
+ apiterm.in \
+ apiterm.ok \
argarray.awk \
argarray.in \
argarray.ok \
@@ -55,6 +61,10 @@ EXTRA_DIST = \
arrayind1.awk \
arrayind1.in \
arrayind1.ok \
+ arrayind2.awk \
+ arrayind2.ok \
+ arrayind3.awk \
+ arrayind3.ok \
arrayparm.awk \
arrayparm.ok \
arrayprm2.awk \
@@ -65,6 +75,7 @@ EXTRA_DIST = \
arrayref.ok \
arraysort.awk \
arraysort.ok \
+ arrdbg.awk \
arrymem1.awk \
arrymem1.ok \
arryref2.awk \
@@ -159,6 +170,8 @@ EXTRA_DIST = \
clos1way4.ok \
clos1way5.awk \
clos1way5.ok \
+ clos1way6.awk \
+ clos1way6.ok \
closebad.awk \
closebad.ok \
clsflnam.awk \
@@ -193,6 +206,15 @@ EXTRA_DIST = \
datanonl.ok \
dbugeval.in \
dbugeval.ok \
+ dbugeval2.awk \
+ dbugeval2.in \
+ dbugeval2.ok \
+ dbugtypedre1.awk \
+ dbugtypedre1.in \
+ dbugtypedre1.ok \
+ dbugtypedre2.awk \
+ dbugtypedre2.in \
+ dbugtypedre2.ok \
defref.awk \
defref.ok \
delargv.awk \
@@ -229,6 +251,9 @@ EXTRA_DIST = \
dynlj.ok \
eofsplit.awk \
eofsplit.ok \
+ errno.awk \
+ errno.in \
+ errno.ok \
exit.ok \
exit.sh \
exit2.awk \
@@ -258,6 +283,9 @@ EXTRA_DIST = \
fldchgnf.awk \
fldchgnf.in \
fldchgnf.ok \
+ fldterm.awk \
+ fldterm.in \
+ fldterm.ok \
fmtspcl-mpfr.ok \
fmtspcl.awk \
fmtspcl.tok \
@@ -286,6 +314,8 @@ EXTRA_DIST = \
fnparydl-mpfr.ok \
fnparydl.awk \
fnparydl.ok \
+ forcenum.awk \
+ forcenum.ok \
fordel.awk \
fordel.ok \
fork.awk \
@@ -309,6 +339,9 @@ EXTRA_DIST = \
fpat5.awk \
fpat5.in \
fpat5.ok \
+ fpat6.awk \
+ fpat6.in \
+ fpat6.ok \
fpatnull.awk \
fpatnull.in \
fpatnull.ok \
@@ -356,8 +389,22 @@ EXTRA_DIST = \
fwtest2.in \
fwtest2.ok \
fwtest3.awk \
- fwtest3.in \
fwtest3.ok \
+ fwtest4.awk \
+ fwtest4.in \
+ fwtest4.ok \
+ fwtest5.awk \
+ fwtest5.in \
+ fwtest5.ok \
+ fwtest6.awk \
+ fwtest6.in \
+ fwtest6.ok \
+ fwtest7.awk \
+ fwtest7.in \
+ fwtest7.ok \
+ fwtest8.awk \
+ fwtest8.in \
+ fwtest8.ok \
genpot.awk \
genpot.ok \
gensub.awk \
@@ -368,6 +415,8 @@ EXTRA_DIST = \
gensub3.awk \
gensub3.in \
gensub3.ok \
+ getfile.awk \
+ getfile.ok \
getline.awk \
getline.in \
getline.ok \
@@ -401,6 +450,8 @@ EXTRA_DIST = \
gnureops.ok \
gsubasgn.awk \
gsubasgn.ok \
+ gsubind.awk \
+ gsubind.ok \
gsubtest.awk \
gsubtest.ok \
gsubtst2.awk \
@@ -450,6 +501,8 @@ EXTRA_DIST = \
ignrcas2.ok \
ignrcas3.awk \
ignrcas3.ok \
+ ignrcas4.awk \
+ ignrcas4.ok \
ignrcase.awk \
ignrcase.in \
ignrcase.ok \
@@ -492,6 +545,8 @@ EXTRA_DIST = \
inplace3.2.bak.ok \
inputred.awk \
inputred.ok \
+ intarray.awk \
+ intarray.ok \
intest.awk \
intest.ok \
intformat.awk \
@@ -513,9 +568,19 @@ EXTRA_DIST = \
leadnl.ok \
lint.awk \
lint.ok \
+ lintexp.awk \
+ lintexp.ok \
+ lintindex.awk \
+ lintindex.ok \
+ lintint.awk \
+ lintint.ok \
+ lintlength.awk \
+ lintlength.ok \
lintold.awk \
lintold.in \
lintold.ok \
+ lintset.awk \
+ lintset.ok \
lintwarn.awk \
lintwarn.ok \
litoct.awk \
@@ -561,6 +626,9 @@ EXTRA_DIST = \
mbprintf4.awk \
mbprintf4.in \
mbprintf4.ok \
+ mbprintf5.awk \
+ mbprintf5.in \
+ mbprintf5.ok \
mbstr1.awk \
mbstr1.ok \
mbstr2.awk \
@@ -569,10 +637,15 @@ EXTRA_DIST = \
membug1.awk \
membug1.in \
membug1.ok \
+ memleak.awk \
+ memleak.ok \
messages.awk \
minusstr.awk \
minusstr.ok \
mixed1.ok \
+ mktime.awk \
+ mktime.in \
+ mktime.ok \
mmap8k.in \
mpfrbigint.awk \
mpfrbigint.ok \
@@ -595,6 +668,10 @@ EXTRA_DIST = \
mpfrsort.ok \
mpfrsqrt.awk \
mpfrsqrt.ok \
+ mpfrstrtonum.awk \
+ mpfrstrtonum.ok \
+ mpgforcenum.awk \
+ mpgforcenum.ok \
mtchi18n.awk \
mtchi18n.in \
mtchi18n.ok \
@@ -648,6 +725,12 @@ EXTRA_DIST = \
nondec.ok \
nondec2.awk \
nondec2.ok \
+ nonfatal1.awk \
+ nonfatal1.ok \
+ nonfatal2.awk \
+ nonfatal2.ok \
+ nonfatal3.awk \
+ nonfatal3.ok \
nonl.awk \
nonl.ok \
noparms.awk \
@@ -755,6 +838,8 @@ EXTRA_DIST = \
printfbad3.ok \
printfbad4.awk \
printfbad4.ok \
+ printfchar.awk \
+ printfchar.ok \
printfloat.awk \
printhuge.awk \
printhuge.ok \
@@ -781,6 +866,10 @@ EXTRA_DIST = \
profile7.ok \
profile8.awk \
profile8.ok \
+ profile9.awk \
+ profile9.ok \
+ profile10.awk \
+ profile10.ok \
prt1eval.awk \
prt1eval.ok \
prtoeval.awk \
@@ -790,6 +879,8 @@ EXTRA_DIST = \
rand-mpfr.ok \
rand.awk \
rand.ok \
+ randtest.sh \
+ randtest.ok \
range1.awk \
range1.in \
range1.ok \
@@ -809,6 +900,9 @@ EXTRA_DIST = \
rebuf.awk \
rebuf.in \
rebuf.ok \
+ rebuild.awk \
+ rebuild.in \
+ rebuild.ok \
redfilnm.awk \
redfilnm.in \
redfilnm.ok \
@@ -909,6 +1003,8 @@ EXTRA_DIST = \
sclifin.ok \
shadow.awk \
shadow.ok \
+ shadowbuiltin.awk \
+ shadowbuiltin.ok \
sigpipe1.awk \
sigpipe1.ok \
sort1.awk \
@@ -926,6 +1022,7 @@ EXTRA_DIST = \
sortglos.ok \
sortu.awk \
sortu.ok \
+ sourcesplit.ok \
space.ok \
split_after_fpat.awk \
split_after_fpat.in \
@@ -948,18 +1045,27 @@ EXTRA_DIST = \
sprintfc.awk \
sprintfc.in \
sprintfc.ok \
+ status-close.awk \
+ status-close.ok \
strcat1.awk \
strcat1.ok \
strftime.awk \
strftlng.awk \
strftlng.ok \
+ strftfld.awk \
+ strftfld.in \
+ strftfld.ok \
strnum1.awk \
strnum1.ok \
+ strnum2.awk \
+ strnum2.ok \
strtod.awk \
strtod.in \
strtod.ok \
strtonum.awk \
strtonum.ok \
+ strtonum1.awk \
+ strtonum1.ok \
subamp.awk \
subamp.in \
subamp.ok \
@@ -1011,12 +1117,31 @@ EXTRA_DIST = \
testext.ok \
time.awk \
time.ok \
+ timeout.awk \
+ timeout.ok \
tradanch.awk \
tradanch.in \
tradanch.ok \
tweakfld.awk \
tweakfld.in \
tweakfld.ok \
+ typedregex1.awk \
+ typedregex1.ok \
+ typedregex2.awk \
+ typedregex2.ok \
+ typedregex3.awk \
+ typedregex3.ok \
+ typeof1.awk \
+ typeof1.ok \
+ typeof2.awk \
+ typeof2.ok \
+ typeof3.awk \
+ typeof3.ok \
+ typeof4.awk \
+ typeof4.ok \
+ typeof5.awk \
+ typeof5.in \
+ typeof5.ok \
uninit2.awk \
uninit2.ok \
uninit3.awk \
@@ -1071,7 +1196,7 @@ CLEANFILES = core core.* fmtspcl.ok
# try to keep these sorted. each letter starts a new line
BASIC_TESTS = \
- addcomma anchgsub argarray arrayind1 arrayparm arrayprm2 arrayprm3 \
+ addcomma anchgsub anchor argarray arrayind1 arrayind2 arrayind3 arrayparm arrayprm2 arrayprm3 \
arrayref arrymem1 arryref2 arryref3 arryref4 arryref5 arynasty \
arynocls aryprm1 aryprm2 aryprm3 aryprm4 aryprm5 aryprm6 aryprm7 \
aryprm8 aryprm9 arysubnm asgext awkpath \
@@ -1080,7 +1205,7 @@ BASIC_TESTS = \
concat3 concat4 concat5 convfmt \
datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \
eofsplit exit2 exitval1 exitval2 exitval3 \
- fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \
+ fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \
fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \
fstabplus funsemnl funsmnam funstack \
getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \
@@ -1089,7 +1214,7 @@ BASIC_TESTS = \
hex hex2 hsprint \
inpref inputred intest intprec iobug1 \
leaddig leadnl litoct longsub longwrds \
- manglprm math membug1 messages minusstr mmap8k mtchi18n \
+ manglprm math membug1 memleak messages minusstr mmap8k mtchi18n \
nasty nasty2 negexp negrange nested nfldstr nfloop nfneg nfset nlfldsep \
nlinstr nlstrina noeffect nofile nofmtch noloop1 noloop2 nonl \
noparms nors nulinsrc nulrsend numindex numsubstr \
@@ -1097,15 +1222,15 @@ BASIC_TESTS = \
opasnidx opasnslf \
paramasfunc1 paramasfunc2 \
paramdup paramres paramtyp paramuninitglobal parse1 parsefld parseme \
- pcntplus posix2008sub prdupval prec printf0 printf1 prmarscl prmreuse \
+ pcntplus posix2008sub prdupval prec printf0 printf1 printfchar prmarscl prmreuse \
prt1eval prtoeval \
- rand range1 readbuf rebrackloc rebt8b1 redfilnm \
+ rand randtest range1 readbuf rebrackloc rebt8b1 rebuild redfilnm \
regeq regexpbrack regexpbrack2 \
regexprange regrange reindops \
reparse resplit rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 \
rstest3 rstest4 rstest5 rswhite \
scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr splitdef \
- splitvar splitwht strcat1 strnum1 strtod subamp subback subi18n \
+ splitvar splitwht status-close strcat1 strnum1 strnum2 strtod subamp subback subi18n \
subsepnm subslash substr swaplns synerr1 synerr2 tradanch tweakfld \
uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs \
wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \
@@ -1118,28 +1243,37 @@ UNIX_TESTS = \
GAWK_EXT_TESTS = \
aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \
backw badargs beginfile1 beginfile2 binmode1 charasbytes \
- colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \
- crlf dbugeval delsub devfd devfd1 devfd2 dumpvars exit \
- fieldwdth fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \
- functab1 functab2 functab3 fwtest fwtest2 fwtest3 \
- genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops \
- icasefs icasers id igncdym igncfs ignrcas2 ignrcase \
+ colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 clos1way6 \
+ crlf dbugeval dbugeval2 dbugtypedre1 dbugtypedre2 delsub \
+ devfd devfd1 devfd2 dumpvars errno exit \
+ fieldwdth forcenum fpat1 fpat2 fpat3 fpat4 fpat5 fpat6 fpatnull \
+ fsfwfs funlen functab1 functab2 functab3 \
+ fwtest fwtest2 fwtest3 fwtest4 fwtest5 fwtest6 fwtest7 fwtest8 \
+ genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops gsubind \
+ icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase \
incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
- include include2 indirectbuiltin indirectcall indirectcall2 \
- lint lintold lintwarn \
- mixed1 manyfiles match1 match2 match3 mbstr1 mbstr2 \
+ include include2 indirectbuiltin indirectcall indirectcall2 intarray \
+ lint lintexp lintindex lintint lintlength lintold lintset lintwarn \
+ mixed1 mktime manyfiles match1 match2 match3 mbstr1 mbstr2 \
muldimposix \
nastyparm negtime next nondec nondec2 \
+ nonfatal1 nonfatal2 nonfatal3 \
patsplit posix printfbad1 printfbad2 printfbad3 printfbad4 printhuge procinfs \
- profile0 profile1 profile2 profile3 profile4 profile5 profile6 \
- profile7 profile8 pty1 \
+ profile0 profile1 profile2 profile3 profile4 profile5 profile6 profile7 \
+ profile8 profile9 profile10 pty1 \
rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin rsstart1 \
- rsstart2 rsstart3 rstest6 shadow sortfor sortfor2 sortu split_after_fpat \
- splitarg4 strftime \
- strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \
+ rsstart2 rsstart3 rstest6 shadow shadowbuiltin \
+ sortfor sortfor2 sortu sourcesplit split_after_fpat \
+ splitarg4 strftime strftfld \
+ strtonum strtonum1 switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \
symtab7 symtab8 symtab9 symtab10 \
+ typedregex1 typedregex2 typedregex3 \
+ typeof1 typeof2 typeof3 typeof4 typeof5 \
+ timeout \
watchpoint1
+ARRAYDEBUG_TESTS = arrdbg
+
EXTRA_TESTS = inftest regtest ignrcas3
INET_TESTS = inetdayu inetdayt inetechu inetecht
@@ -1147,20 +1281,21 @@ INET_TESTS = inetdayu inetdayt inetechu inetecht
MACHINE_TESTS = double1 double2 fmtspcl intformat
MPFR_TESTS = mpfrnr mpfrnegzero mpfrmemok1 mpfrrem mpfrrnd mpfrieee \
- mpfrexprange mpfrsort mpfrsqrt mpfrbigint
+ mpfrexprange mpfrsort mpfrsqrt mpfrbigint mpfrstrtonum mpgforcenum
LOCALE_CHARSET_TESTS = \
asort asorti backbigs1 backsmalls1 backsmalls2 \
fmttest fnarydel fnparydl jarebug lc_num1 mbfw1 \
- mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc
+ mbprintf1 mbprintf2 mbprintf3 mbprintf4 mbprintf5 \
+ rebt8b2 rtlenmb sort1 sprintfc
SHLIB_TESTS = \
- fnmatch filefuncs fork fork2 fts functab4 inplace1 inplace2 inplace3 \
- ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time
+ apiterm fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \
+ ordchr ordchr2 readdir readdir_test readfile readfile2 revout revtwoway rwarray testext time
# List of the tests which should be run with --lint option:
NEED_LINT = \
- defref fmtspcl lintwarn noeffect nofmtch shadow \
+ defref fmtspcl lintexp lintindex lintint lintlength lintwarn noeffect nofmtch shadow \
uninit2 uninit3 uninit4 uninit5 uninitialized
# List of the tests which should be run with --lint-old option:
@@ -1207,7 +1342,7 @@ check: msg \
printlang \
basic-msg-start basic basic-msg-end \
unix-msg-start unix-tests unix-msg-end \
- extend-msg-start gawk-extensions extend-msg-end \
+ extend-msg-start gawk-extensions arraydebug-tests extend-msg-end \
machine-msg-start machine-tests machine-msg-end \
charset-tests-all \
shlib-msg-start shlib-tests shlib-msg-end \
@@ -1249,6 +1384,12 @@ mpfr-tests:
else $(MAKE) $(MPFR_TESTS) ; \
fi
+arraydebug-tests:
+ @if echo $(CFLAGS) | grep ARRAYDEBUG > /dev/null ; then \
+ $(MAKE) $(ARRAYDEBUG_TESTS) ; \
+ else echo gawk is not compiled to support the array debug tests ; \
+ fi
+
shlib-tests:
@if $(AWK) --version | $(AWK) ' /API/ { exit 1 }' ; then \
echo shlib tests not supported on this system ; \
@@ -1296,8 +1437,8 @@ charset-msg-start:
@echo "**************************************************************************"
@echo "* Some or all of these tests may fail if you have inadequate or missing *"
@echo "* locale support. At least en_US.UTF-8, ru_RU.UTF-8 and ja_JP.UTF-8 are *"
- @echo "* needed. However, if you see this message, the Makefile thinks you have *"
- @echo "* what you need ... *"
+ @echo "* needed. The el_GR.iso88597 is optional but helpful. However, if you *"
+ @echo "* see this message, the Makefile thinks you have what you need ... *"
@echo "**************************************************************************"
charset-msg-end:
@@ -1422,6 +1563,11 @@ devfd::
@$(AWK) 1 /dev/fd/4 /dev/fd/5 4<"$(srcdir)"/devfd.in4 5<"$(srcdir)"/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+errno:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fflush::
@echo $@
@"$(srcdir)"/fflush.sh >_$@
@@ -1676,6 +1822,16 @@ nondec2::
@$(AWK) --non-decimal-data -v a=0x1 -f "$(srcdir)"/$@.awk >_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+intarray::
+ @echo $@
+ @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+forcenum::
+ @echo $@
+ @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
nofile::
@echo $@
@$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1753,6 +1909,16 @@ mbprintf4::
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mbprintf5::
+ echo $@
+ @case `uname` in \
+ CYGWIN*) echo this test fails on cygwin --- skipping $@ ;; \
+ *) \
+ GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ $(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@ ; \
+ $(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ ; \
+ esac
+
mbfw1::
@echo $@
@GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
@@ -1805,10 +1971,11 @@ profile0:
profile1:
@echo $@
- @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1
+ @$(AWK) -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1
+ @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk
@$(AWK) -f ./ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out
@$(CMP) _$@.out1 _$@.out2 && rm _$@.out[12] || { echo EXIT CODE: $$? >>_$@ ; \
- cp "$(srcdir)"/dtdgport.awk > $@.ok ; }
+ cp "$(srcdir)"/dtdgport.awk $@.ok ; }
profile2:
@@ -1825,14 +1992,12 @@ profile3:
profile4:
@echo $@
- @GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
- @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
profile5:
@echo $@
- @GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
- @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
profile6:
@@ -1849,8 +2014,17 @@ profile7:
profile8:
@echo $@
- @$(AWK) --pretty=ap-$@.out -f "$(srcdir)"/$@.awk < /dev/null
- @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+profile9:
+ @echo $@
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+profile10:
+ @echo $@
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
posix2008sub:
@@ -1914,6 +2088,16 @@ mpfrsqrt:
@$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mpfrstrtonum:
+ @echo $@
+ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+mpgforcenum:
+ @echo $@
+ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
mpfrrem:
@echo $@
@$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
@@ -2023,6 +2207,11 @@ testext::
@$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk
+getfile:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -v TESTEXT_QUIET=1 -ltestext -f $@.awk < $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
readdir:
@if [ "`uname`" = Linux ] && [ "`stat -f . 2>/dev/null | awk 'NR == 2 { print $$NF }'`" = nfs ]; then \
echo This test may fail on GNU/Linux systems when run on an NFS filesystem.; \
@@ -2036,6 +2225,12 @@ readdir:
-v dirlist=_dirlist -v longlist=_longlist > $@.ok
@-$(CMP) $@.ok _$@ && rm -f $@.ok _$@ _dirlist _longlist
+readdir_test:
+ @echo $@
+ @$(AWK) -lreaddir -F/ '{printf "[%s] [%s] [%s] [%s]\n", $$1, $$2, $$3, $$4}' "$(top_srcdir)" > $@.ok
+ @$(AWK) -lreaddir_test '{printf "[%s] [%s] [%s] [%s]\n", $$1, $$2, $$3, $$4}' "$(top_srcdir)" > _$@
+ @-$(CMP) $@.ok _$@ && rm -f $@.ok _$@
+
fts:
@case `uname` in \
IRIX) \
@@ -2097,6 +2292,12 @@ dfamb1:
AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+randtest::
+ @echo $@
+ @GAWK="$(AWKPROG)" "$(srcdir)"/randtest.sh >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
backbigs1:
@echo $@
@[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
@@ -2153,6 +2354,21 @@ negtime::
@TZ=GMT AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@AWKPATH="$(srcdir)" $(AWK) -f checknegtime.awk "$(srcdir)"/$@.ok _$@ && rm -f _$@
+dbugtypedre1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugtypedre2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugeval2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
muldimposix::
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --posix >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2189,6 +2405,22 @@ ignrcas3::
$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ ; \
fi
+arrdbg:
+ @echo $@
+ @$(AWK) -v "okfile=$(srcdir)/$@.ok" -f "$(srcdir)"/$@.awk | grep array_f >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ "$(srcdir)"/$@.ok
+# @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ "$(srcdir)"/$@.ok || exit 0
+
+fwtest3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/fwtest2.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+sourcesplit:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) --source='BEGIN { a = 5;' --source='print a }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
# Targets generated for other tests:
include Maketests
diff --git a/test/Makefile.in b/test/Makefile.in
index 981a1e3b..0b9dfe3d 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -115,14 +115,14 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
- $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libsigsegv.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -215,6 +215,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POSUB = @POSUB@
+RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -304,6 +305,12 @@ EXTRA_DIST = \
anchgsub.awk \
anchgsub.in \
anchgsub.ok \
+ anchor.awk \
+ anchor.in \
+ anchor.ok \
+ apiterm.awk \
+ apiterm.in \
+ apiterm.ok \
argarray.awk \
argarray.in \
argarray.ok \
@@ -312,6 +319,10 @@ EXTRA_DIST = \
arrayind1.awk \
arrayind1.in \
arrayind1.ok \
+ arrayind2.awk \
+ arrayind2.ok \
+ arrayind3.awk \
+ arrayind3.ok \
arrayparm.awk \
arrayparm.ok \
arrayprm2.awk \
@@ -322,6 +333,7 @@ EXTRA_DIST = \
arrayref.ok \
arraysort.awk \
arraysort.ok \
+ arrdbg.awk \
arrymem1.awk \
arrymem1.ok \
arryref2.awk \
@@ -416,6 +428,8 @@ EXTRA_DIST = \
clos1way4.ok \
clos1way5.awk \
clos1way5.ok \
+ clos1way6.awk \
+ clos1way6.ok \
closebad.awk \
closebad.ok \
clsflnam.awk \
@@ -450,6 +464,15 @@ EXTRA_DIST = \
datanonl.ok \
dbugeval.in \
dbugeval.ok \
+ dbugeval2.awk \
+ dbugeval2.in \
+ dbugeval2.ok \
+ dbugtypedre1.awk \
+ dbugtypedre1.in \
+ dbugtypedre1.ok \
+ dbugtypedre2.awk \
+ dbugtypedre2.in \
+ dbugtypedre2.ok \
defref.awk \
defref.ok \
delargv.awk \
@@ -486,6 +509,9 @@ EXTRA_DIST = \
dynlj.ok \
eofsplit.awk \
eofsplit.ok \
+ errno.awk \
+ errno.in \
+ errno.ok \
exit.ok \
exit.sh \
exit2.awk \
@@ -515,6 +541,9 @@ EXTRA_DIST = \
fldchgnf.awk \
fldchgnf.in \
fldchgnf.ok \
+ fldterm.awk \
+ fldterm.in \
+ fldterm.ok \
fmtspcl-mpfr.ok \
fmtspcl.awk \
fmtspcl.tok \
@@ -543,6 +572,8 @@ EXTRA_DIST = \
fnparydl-mpfr.ok \
fnparydl.awk \
fnparydl.ok \
+ forcenum.awk \
+ forcenum.ok \
fordel.awk \
fordel.ok \
fork.awk \
@@ -566,6 +597,9 @@ EXTRA_DIST = \
fpat5.awk \
fpat5.in \
fpat5.ok \
+ fpat6.awk \
+ fpat6.in \
+ fpat6.ok \
fpatnull.awk \
fpatnull.in \
fpatnull.ok \
@@ -613,8 +647,22 @@ EXTRA_DIST = \
fwtest2.in \
fwtest2.ok \
fwtest3.awk \
- fwtest3.in \
fwtest3.ok \
+ fwtest4.awk \
+ fwtest4.in \
+ fwtest4.ok \
+ fwtest5.awk \
+ fwtest5.in \
+ fwtest5.ok \
+ fwtest6.awk \
+ fwtest6.in \
+ fwtest6.ok \
+ fwtest7.awk \
+ fwtest7.in \
+ fwtest7.ok \
+ fwtest8.awk \
+ fwtest8.in \
+ fwtest8.ok \
genpot.awk \
genpot.ok \
gensub.awk \
@@ -625,6 +673,8 @@ EXTRA_DIST = \
gensub3.awk \
gensub3.in \
gensub3.ok \
+ getfile.awk \
+ getfile.ok \
getline.awk \
getline.in \
getline.ok \
@@ -658,6 +708,8 @@ EXTRA_DIST = \
gnureops.ok \
gsubasgn.awk \
gsubasgn.ok \
+ gsubind.awk \
+ gsubind.ok \
gsubtest.awk \
gsubtest.ok \
gsubtst2.awk \
@@ -707,6 +759,8 @@ EXTRA_DIST = \
ignrcas2.ok \
ignrcas3.awk \
ignrcas3.ok \
+ ignrcas4.awk \
+ ignrcas4.ok \
ignrcase.awk \
ignrcase.in \
ignrcase.ok \
@@ -749,6 +803,8 @@ EXTRA_DIST = \
inplace3.2.bak.ok \
inputred.awk \
inputred.ok \
+ intarray.awk \
+ intarray.ok \
intest.awk \
intest.ok \
intformat.awk \
@@ -770,9 +826,19 @@ EXTRA_DIST = \
leadnl.ok \
lint.awk \
lint.ok \
+ lintexp.awk \
+ lintexp.ok \
+ lintindex.awk \
+ lintindex.ok \
+ lintint.awk \
+ lintint.ok \
+ lintlength.awk \
+ lintlength.ok \
lintold.awk \
lintold.in \
lintold.ok \
+ lintset.awk \
+ lintset.ok \
lintwarn.awk \
lintwarn.ok \
litoct.awk \
@@ -818,6 +884,9 @@ EXTRA_DIST = \
mbprintf4.awk \
mbprintf4.in \
mbprintf4.ok \
+ mbprintf5.awk \
+ mbprintf5.in \
+ mbprintf5.ok \
mbstr1.awk \
mbstr1.ok \
mbstr2.awk \
@@ -826,10 +895,15 @@ EXTRA_DIST = \
membug1.awk \
membug1.in \
membug1.ok \
+ memleak.awk \
+ memleak.ok \
messages.awk \
minusstr.awk \
minusstr.ok \
mixed1.ok \
+ mktime.awk \
+ mktime.in \
+ mktime.ok \
mmap8k.in \
mpfrbigint.awk \
mpfrbigint.ok \
@@ -852,6 +926,10 @@ EXTRA_DIST = \
mpfrsort.ok \
mpfrsqrt.awk \
mpfrsqrt.ok \
+ mpfrstrtonum.awk \
+ mpfrstrtonum.ok \
+ mpgforcenum.awk \
+ mpgforcenum.ok \
mtchi18n.awk \
mtchi18n.in \
mtchi18n.ok \
@@ -905,6 +983,12 @@ EXTRA_DIST = \
nondec.ok \
nondec2.awk \
nondec2.ok \
+ nonfatal1.awk \
+ nonfatal1.ok \
+ nonfatal2.awk \
+ nonfatal2.ok \
+ nonfatal3.awk \
+ nonfatal3.ok \
nonl.awk \
nonl.ok \
noparms.awk \
@@ -1012,6 +1096,8 @@ EXTRA_DIST = \
printfbad3.ok \
printfbad4.awk \
printfbad4.ok \
+ printfchar.awk \
+ printfchar.ok \
printfloat.awk \
printhuge.awk \
printhuge.ok \
@@ -1038,6 +1124,10 @@ EXTRA_DIST = \
profile7.ok \
profile8.awk \
profile8.ok \
+ profile9.awk \
+ profile9.ok \
+ profile10.awk \
+ profile10.ok \
prt1eval.awk \
prt1eval.ok \
prtoeval.awk \
@@ -1047,6 +1137,8 @@ EXTRA_DIST = \
rand-mpfr.ok \
rand.awk \
rand.ok \
+ randtest.sh \
+ randtest.ok \
range1.awk \
range1.in \
range1.ok \
@@ -1066,6 +1158,9 @@ EXTRA_DIST = \
rebuf.awk \
rebuf.in \
rebuf.ok \
+ rebuild.awk \
+ rebuild.in \
+ rebuild.ok \
redfilnm.awk \
redfilnm.in \
redfilnm.ok \
@@ -1166,6 +1261,8 @@ EXTRA_DIST = \
sclifin.ok \
shadow.awk \
shadow.ok \
+ shadowbuiltin.awk \
+ shadowbuiltin.ok \
sigpipe1.awk \
sigpipe1.ok \
sort1.awk \
@@ -1183,6 +1280,7 @@ EXTRA_DIST = \
sortglos.ok \
sortu.awk \
sortu.ok \
+ sourcesplit.ok \
space.ok \
split_after_fpat.awk \
split_after_fpat.in \
@@ -1205,18 +1303,27 @@ EXTRA_DIST = \
sprintfc.awk \
sprintfc.in \
sprintfc.ok \
+ status-close.awk \
+ status-close.ok \
strcat1.awk \
strcat1.ok \
strftime.awk \
strftlng.awk \
strftlng.ok \
+ strftfld.awk \
+ strftfld.in \
+ strftfld.ok \
strnum1.awk \
strnum1.ok \
+ strnum2.awk \
+ strnum2.ok \
strtod.awk \
strtod.in \
strtod.ok \
strtonum.awk \
strtonum.ok \
+ strtonum1.awk \
+ strtonum1.ok \
subamp.awk \
subamp.in \
subamp.ok \
@@ -1268,12 +1375,31 @@ EXTRA_DIST = \
testext.ok \
time.awk \
time.ok \
+ timeout.awk \
+ timeout.ok \
tradanch.awk \
tradanch.in \
tradanch.ok \
tweakfld.awk \
tweakfld.in \
tweakfld.ok \
+ typedregex1.awk \
+ typedregex1.ok \
+ typedregex2.awk \
+ typedregex2.ok \
+ typedregex3.awk \
+ typedregex3.ok \
+ typeof1.awk \
+ typeof1.ok \
+ typeof2.awk \
+ typeof2.ok \
+ typeof3.awk \
+ typeof3.ok \
+ typeof4.awk \
+ typeof4.ok \
+ typeof5.awk \
+ typeof5.in \
+ typeof5.ok \
uninit2.awk \
uninit2.ok \
uninit3.awk \
@@ -1327,7 +1453,7 @@ CLEANFILES = core core.* fmtspcl.ok
# try to keep these sorted. each letter starts a new line
BASIC_TESTS = \
- addcomma anchgsub argarray arrayind1 arrayparm arrayprm2 arrayprm3 \
+ addcomma anchgsub anchor argarray arrayind1 arrayind2 arrayind3 arrayparm arrayprm2 arrayprm3 \
arrayref arrymem1 arryref2 arryref3 arryref4 arryref5 arynasty \
arynocls aryprm1 aryprm2 aryprm3 aryprm4 aryprm5 aryprm6 aryprm7 \
aryprm8 aryprm9 arysubnm asgext awkpath \
@@ -1336,7 +1462,7 @@ BASIC_TESTS = \
concat3 concat4 concat5 convfmt \
datanonl defref delargv delarpm2 delarprm delfunc dfamb1 dfastress dynlj \
eofsplit exit2 exitval1 exitval2 exitval3 \
- fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \
+ fcall_exit fcall_exit2 fldchg fldchgnf fldterm fnamedat fnarray fnarray2 \
fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsnul1 fsrs fsspcoln \
fstabplus funsemnl funsmnam funstack \
getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \
@@ -1345,7 +1471,7 @@ BASIC_TESTS = \
hex hex2 hsprint \
inpref inputred intest intprec iobug1 \
leaddig leadnl litoct longsub longwrds \
- manglprm math membug1 messages minusstr mmap8k mtchi18n \
+ manglprm math membug1 memleak messages minusstr mmap8k mtchi18n \
nasty nasty2 negexp negrange nested nfldstr nfloop nfneg nfset nlfldsep \
nlinstr nlstrina noeffect nofile nofmtch noloop1 noloop2 nonl \
noparms nors nulinsrc nulrsend numindex numsubstr \
@@ -1353,15 +1479,15 @@ BASIC_TESTS = \
opasnidx opasnslf \
paramasfunc1 paramasfunc2 \
paramdup paramres paramtyp paramuninitglobal parse1 parsefld parseme \
- pcntplus posix2008sub prdupval prec printf0 printf1 prmarscl prmreuse \
+ pcntplus posix2008sub prdupval prec printf0 printf1 printfchar prmarscl prmreuse \
prt1eval prtoeval \
- rand range1 readbuf rebrackloc rebt8b1 redfilnm \
+ rand randtest range1 readbuf rebrackloc rebt8b1 rebuild redfilnm \
regeq regexpbrack regexpbrack2 \
regexprange regrange reindops \
reparse resplit rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 \
rstest3 rstest4 rstest5 rswhite \
scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr splitdef \
- splitvar splitwht strcat1 strnum1 strtod subamp subback subi18n \
+ splitvar splitwht status-close strcat1 strnum1 strnum2 strtod subamp subback subi18n \
subsepnm subslash substr swaplns synerr1 synerr2 tradanch tweakfld \
uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs \
wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \
@@ -1374,47 +1500,56 @@ UNIX_TESTS = \
GAWK_EXT_TESTS = \
aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \
backw badargs beginfile1 beginfile2 binmode1 charasbytes \
- colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \
- crlf dbugeval delsub devfd devfd1 devfd2 dumpvars exit \
- fieldwdth fpat1 fpat2 fpat3 fpat4 fpat5 fpatnull fsfwfs funlen \
- functab1 functab2 functab3 fwtest fwtest2 fwtest3 \
- genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops \
- icasefs icasers id igncdym igncfs ignrcas2 ignrcase \
+ colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 clos1way6 \
+ crlf dbugeval dbugeval2 dbugtypedre1 dbugtypedre2 delsub \
+ devfd devfd1 devfd2 dumpvars errno exit \
+ fieldwdth forcenum fpat1 fpat2 fpat3 fpat4 fpat5 fpat6 fpatnull \
+ fsfwfs funlen functab1 functab2 functab3 \
+ fwtest fwtest2 fwtest3 fwtest4 fwtest5 fwtest6 fwtest7 fwtest8 \
+ genpot gensub gensub2 gensub3 getlndir gnuops2 gnuops3 gnureops gsubind \
+ icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase \
incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
- include include2 indirectbuiltin indirectcall indirectcall2 \
- lint lintold lintwarn \
- mixed1 manyfiles match1 match2 match3 mbstr1 mbstr2 \
+ include include2 indirectbuiltin indirectcall indirectcall2 intarray \
+ lint lintexp lintindex lintint lintlength lintold lintset lintwarn \
+ mixed1 mktime manyfiles match1 match2 match3 mbstr1 mbstr2 \
muldimposix \
nastyparm negtime next nondec nondec2 \
+ nonfatal1 nonfatal2 nonfatal3 \
patsplit posix printfbad1 printfbad2 printfbad3 printfbad4 printhuge procinfs \
- profile0 profile1 profile2 profile3 profile4 profile5 profile6 \
- profile7 profile8 pty1 \
+ profile0 profile1 profile2 profile3 profile4 profile5 profile6 profile7 \
+ profile8 profile9 profile10 pty1 \
rebuf regnul1 regnul2 regx8bit reginttrad reint reint2 rsgetline rsglstdin rsstart1 \
- rsstart2 rsstart3 rstest6 shadow sortfor sortfor2 sortu split_after_fpat \
- splitarg4 strftime \
- strtonum switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \
+ rsstart2 rsstart3 rstest6 shadow shadowbuiltin \
+ sortfor sortfor2 sortu sourcesplit split_after_fpat \
+ splitarg4 strftime strftfld \
+ strtonum strtonum1 switch2 symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 \
symtab7 symtab8 symtab9 symtab10 \
+ typedregex1 typedregex2 typedregex3 \
+ typeof1 typeof2 typeof3 typeof4 typeof5 \
+ timeout \
watchpoint1
+ARRAYDEBUG_TESTS = arrdbg
EXTRA_TESTS = inftest regtest ignrcas3
INET_TESTS = inetdayu inetdayt inetechu inetecht
MACHINE_TESTS = double1 double2 fmtspcl intformat
MPFR_TESTS = mpfrnr mpfrnegzero mpfrmemok1 mpfrrem mpfrrnd mpfrieee \
- mpfrexprange mpfrsort mpfrsqrt mpfrbigint
+ mpfrexprange mpfrsort mpfrsqrt mpfrbigint mpfrstrtonum mpgforcenum
LOCALE_CHARSET_TESTS = \
asort asorti backbigs1 backsmalls1 backsmalls2 \
fmttest fnarydel fnparydl jarebug lc_num1 mbfw1 \
- mbprintf1 mbprintf2 mbprintf3 mbprintf4 rebt8b2 rtlenmb sort1 sprintfc
+ mbprintf1 mbprintf2 mbprintf3 mbprintf4 mbprintf5 \
+ rebt8b2 rtlenmb sort1 sprintfc
SHLIB_TESTS = \
- fnmatch filefuncs fork fork2 fts functab4 inplace1 inplace2 inplace3 \
- ordchr ordchr2 readdir readfile readfile2 revout revtwoway rwarray testext time
+ apiterm fnmatch filefuncs fork fork2 fts functab4 getfile inplace1 inplace2 inplace3 \
+ ordchr ordchr2 readdir readdir_test readfile readfile2 revout revtwoway rwarray testext time
# List of the tests which should be run with --lint option:
NEED_LINT = \
- defref fmtspcl lintwarn noeffect nofmtch shadow \
+ defref fmtspcl lintexp lintindex lintint lintlength lintwarn noeffect nofmtch shadow \
uninit2 uninit3 uninit4 uninit5 uninitialized
@@ -1649,7 +1784,7 @@ check: msg \
printlang \
basic-msg-start basic basic-msg-end \
unix-msg-start unix-tests unix-msg-end \
- extend-msg-start gawk-extensions extend-msg-end \
+ extend-msg-start gawk-extensions arraydebug-tests extend-msg-end \
machine-msg-start machine-tests machine-msg-end \
charset-tests-all \
shlib-msg-start shlib-tests shlib-msg-end \
@@ -1691,6 +1826,12 @@ mpfr-tests:
else $(MAKE) $(MPFR_TESTS) ; \
fi
+arraydebug-tests:
+ @if echo $(CFLAGS) | grep ARRAYDEBUG > /dev/null ; then \
+ $(MAKE) $(ARRAYDEBUG_TESTS) ; \
+ else echo gawk is not compiled to support the array debug tests ; \
+ fi
+
shlib-tests:
@if $(AWK) --version | $(AWK) ' /API/ { exit 1 }' ; then \
echo shlib tests not supported on this system ; \
@@ -1738,8 +1879,8 @@ charset-msg-start:
@echo "**************************************************************************"
@echo "* Some or all of these tests may fail if you have inadequate or missing *"
@echo "* locale support. At least en_US.UTF-8, ru_RU.UTF-8 and ja_JP.UTF-8 are *"
- @echo "* needed. However, if you see this message, the Makefile thinks you have *"
- @echo "* what you need ... *"
+ @echo "* needed. The el_GR.iso88597 is optional but helpful. However, if you *"
+ @echo "* see this message, the Makefile thinks you have what you need ... *"
@echo "**************************************************************************"
charset-msg-end:
@@ -1862,6 +2003,11 @@ devfd::
@$(AWK) 1 /dev/fd/4 /dev/fd/5 4<"$(srcdir)"/devfd.in4 5<"$(srcdir)"/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+errno:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fflush::
@echo $@
@"$(srcdir)"/fflush.sh >_$@
@@ -2116,6 +2262,16 @@ nondec2::
@$(AWK) --non-decimal-data -v a=0x1 -f "$(srcdir)"/$@.awk >_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+intarray::
+ @echo $@
+ @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+forcenum::
+ @echo $@
+ @$(AWK) --non-decimal-data -f "$(srcdir)"/$@.awk >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
nofile::
@echo $@
@$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2193,6 +2349,16 @@ mbprintf4::
$(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mbprintf5::
+ echo $@
+ @case `uname` in \
+ CYGWIN*) echo this test fails on cygwin --- skipping $@ ;; \
+ *) \
+ GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+ $(AWK) -f "$(srcdir)"/$@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@ ; \
+ $(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ ; \
+ esac
+
mbfw1::
@echo $@
@GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
@@ -2245,10 +2411,11 @@ profile0:
profile1:
@echo $@
- @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1
+ @$(AWK) -f "$(srcdir)"/xref.awk "$(srcdir)"/dtdgport.awk > _$@.out1
+ @$(AWK) --pretty-print=ap-$@.out -f "$(srcdir)"/xref.awk
@$(AWK) -f ./ap-$@.out "$(srcdir)"/dtdgport.awk > _$@.out2 ; rm ap-$@.out
@$(CMP) _$@.out1 _$@.out2 && rm _$@.out[12] || { echo EXIT CODE: $$? >>_$@ ; \
- cp "$(srcdir)"/dtdgport.awk > $@.ok ; }
+ cp "$(srcdir)"/dtdgport.awk $@.ok ; }
profile2:
@echo $@
@@ -2264,14 +2431,12 @@ profile3:
profile4:
@echo $@
- @GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
- @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
profile5:
@echo $@
- @GAWK_NO_PP_RUN=1 $(AWK) --profile=ap-$@.out -f "$(srcdir)"/$@.awk > /dev/null
- @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
profile6:
@@ -2288,8 +2453,17 @@ profile7:
profile8:
@echo $@
- @$(AWK) --pretty=ap-$@.out -f "$(srcdir)"/$@.awk < /dev/null
- @sed 1,2d < ap-$@.out > _$@; rm ap-$@.out
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+profile9:
+ @echo $@
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+profile10:
+ @echo $@
+ @$(AWK) --pretty-print=_$@ -f "$(srcdir)"/$@.awk > /dev/null
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
posix2008sub:
@@ -2353,6 +2527,16 @@ mpfrsqrt:
@$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mpfrstrtonum:
+ @echo $@
+ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+mpgforcenum:
+ @echo $@
+ @$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
mpfrrem:
@echo $@
@$(AWK) -M -f "$(srcdir)"/$@.awk > _$@ 2>&1
@@ -2462,6 +2646,11 @@ testext::
@$(AWK) -f ./testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ testext.awk
+getfile:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -v TESTEXT_QUIET=1 -ltestext -f $@.awk < $(srcdir)/$@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
readdir:
@if [ "`uname`" = Linux ] && [ "`stat -f . 2>/dev/null | awk 'NR == 2 { print $$NF }'`" = nfs ]; then \
echo This test may fail on GNU/Linux systems when run on an NFS filesystem.; \
@@ -2475,6 +2664,12 @@ readdir:
-v dirlist=_dirlist -v longlist=_longlist > $@.ok
@-$(CMP) $@.ok _$@ && rm -f $@.ok _$@ _dirlist _longlist
+readdir_test:
+ @echo $@
+ @$(AWK) -lreaddir -F/ '{printf "[%s] [%s] [%s] [%s]\n", $$1, $$2, $$3, $$4}' "$(top_srcdir)" > $@.ok
+ @$(AWK) -lreaddir_test '{printf "[%s] [%s] [%s] [%s]\n", $$1, $$2, $$3, $$4}' "$(top_srcdir)" > _$@
+ @-$(CMP) $@.ok _$@ && rm -f $@.ok _$@
+
fts:
@case `uname` in \
IRIX) \
@@ -2536,6 +2731,11 @@ dfamb1:
AWKPATH="$(srcdir)" $(AWK) -f $@.awk "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+randtest::
+ @echo $@
+ @GAWK="$(AWKPROG)" "$(srcdir)"/randtest.sh >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
backbigs1:
@echo $@
@[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
@@ -2592,6 +2792,21 @@ negtime::
@TZ=GMT AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@AWKPATH="$(srcdir)" $(AWK) -f checknegtime.awk "$(srcdir)"/$@.ok _$@ && rm -f _$@
+dbugtypedre1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugtypedre2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugeval2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -D -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
muldimposix::
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --posix >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2627,6 +2842,22 @@ ignrcas3::
AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ ; \
$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ ; \
fi
+
+arrdbg:
+ @echo $@
+ @$(AWK) -v "okfile=$(srcdir)/$@.ok" -f "$(srcdir)"/$@.awk | grep array_f >_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ "$(srcdir)"/$@.ok
+# @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ "$(srcdir)"/$@.ok || exit 0
+
+fwtest3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/fwtest2.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+sourcesplit:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) --source='BEGIN { a = 5;' --source='print a }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
Gt-dummy:
# file Maketests, generated from Makefile.am by the Gentests program
addcomma:
@@ -2639,11 +2870,26 @@ anchgsub:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+anchor:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
arrayind1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+arrayind2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+arrayind3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
arrayparm:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2899,6 +3145,11 @@ fldchgnf:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+fldterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fnamedat:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3114,6 +3365,11 @@ membug1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+memleak:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
minusstr:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3334,6 +3590,11 @@ printf1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+printfchar:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
prmarscl:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3381,6 +3642,11 @@ rebt8b1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+rebuild:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
regeq:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3516,6 +3782,11 @@ splitwht:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+status-close:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strcat1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3526,6 +3797,11 @@ strnum1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strnum2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strtod:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3681,6 +3957,11 @@ clos1way5:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+clos1way6:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
crlf:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3721,6 +4002,11 @@ fpat5:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+fpat6:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fpatnull:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3761,7 +4047,27 @@ fwtest2:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
-fwtest3:
+fwtest4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest5:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest6:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest7:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest8:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -3801,6 +4107,11 @@ gnureops:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+gsubind:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
icasefs:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3826,6 +4137,11 @@ igncfs:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+ignrcas4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
ignrcase:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3856,16 +4172,46 @@ lint:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+lintexp:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintindex:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintint:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintlength:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
lintold:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint-old < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+lintset:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
lintwarn:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mktime:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
match1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3891,6 +4237,21 @@ nondec:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+nonfatal1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+nonfatal2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+nonfatal3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
patsplit:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3951,6 +4312,11 @@ shadow:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+shadowbuiltin:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
sortfor:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -3976,11 +4342,21 @@ splitarg4:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strftfld:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strtonum:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strtonum1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
switch2:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -4016,6 +4392,51 @@ symtab7:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+typedregex1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typedregex2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typedregex3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof5:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+timeout:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
double1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -4075,6 +4496,11 @@ sprintfc:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+apiterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fnmatch:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/Maketests b/test/Maketests
index e7099ea2..f8c54f94 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -10,11 +10,26 @@ anchgsub:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+anchor:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
arrayind1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+arrayind2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+arrayind3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
arrayparm:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -270,6 +285,11 @@ fldchgnf:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+fldterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fnamedat:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -485,6 +505,11 @@ membug1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+memleak:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
minusstr:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -705,6 +730,11 @@ printf1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+printfchar:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
prmarscl:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -752,6 +782,11 @@ rebt8b1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+rebuild:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
regeq:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -887,6 +922,11 @@ splitwht:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+status-close:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strcat1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -897,6 +937,11 @@ strnum1:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strnum2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strtod:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1052,6 +1097,11 @@ clos1way5:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+clos1way6:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
crlf:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1092,6 +1142,11 @@ fpat5:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+fpat6:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fpatnull:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1132,7 +1187,27 @@ fwtest2:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
-fwtest3:
+fwtest4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest5:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest6:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest7:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+fwtest8:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
@@ -1172,6 +1247,11 @@ gnureops:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+gsubind:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
icasefs:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1197,6 +1277,11 @@ igncfs:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+ignrcas4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
ignrcase:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1227,16 +1312,46 @@ lint:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+lintexp:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintindex:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintint:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+lintlength:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
lintold:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint-old < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+lintset:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
lintwarn:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+mktime:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
match1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1262,6 +1377,21 @@ nondec:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+nonfatal1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+nonfatal2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+nonfatal3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
patsplit:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1322,6 +1452,11 @@ shadow:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+shadowbuiltin:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
sortfor:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1347,11 +1482,21 @@ splitarg4:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strftfld:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
strtonum:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+strtonum1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
switch2:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1387,6 +1532,51 @@ symtab7:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+typedregex1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typedregex2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typedregex3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof2:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof3:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof4:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+typeof5:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+timeout:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
double1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1446,6 +1636,11 @@ sprintfc:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+apiterm:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
fnmatch:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/README b/test/README
index 2343be2f..61976b8a 100644
--- a/test/README
+++ b/test/README
@@ -1,4 +1,5 @@
Mon Jan 22 13:08:58 EST 1996
+============================
This directory contains the tests for gawk. The tests use the
following conventions.
@@ -16,3 +17,8 @@ compare actual and expected results, in case they differ.
If they do differ (other than strftime.ok and _strftime!), send in a
bug report. See the manual for the bug report procedure.
+
+Known Issues:
+=============
+May 2017: On a system with no ptys available, the pty1 test will hang.
+There isn't anything that can be done about this.
diff --git a/test/anchor.awk b/test/anchor.awk
new file mode 100644
index 00000000..56f47569
--- /dev/null
+++ b/test/anchor.awk
@@ -0,0 +1,33 @@
+BEGIN { RS = "" }
+
+{
+ if (/^A/)
+ print "ok"
+ else
+ print "not ok"
+
+ if (/B$/)
+ print "not ok"
+ else
+ print "ok"
+
+ if (/^C/)
+ print "not ok"
+ else
+ print "ok"
+
+ if (/D$/)
+ print "not ok"
+ else
+ print "ok"
+
+ if (/^E/)
+ print "not ok"
+ else
+ print "ok"
+
+ if (/F$/)
+ print "ok"
+ else
+ print "not ok"
+}
diff --git a/test/anchor.in b/test/anchor.in
new file mode 100644
index 00000000..a97e9859
--- /dev/null
+++ b/test/anchor.in
@@ -0,0 +1,3 @@
+A line1 B
+C line2 D
+E line3 F
diff --git a/test/anchor.ok b/test/anchor.ok
new file mode 100644
index 00000000..7780b88b
--- /dev/null
+++ b/test/anchor.ok
@@ -0,0 +1,6 @@
+ok
+ok
+ok
+ok
+ok
+ok
diff --git a/test/apiterm.awk b/test/apiterm.awk
new file mode 100644
index 00000000..95e4b120
--- /dev/null
+++ b/test/apiterm.awk
@@ -0,0 +1,8 @@
+@load "filefuncs"
+
+{
+ print $1
+ # check whether API terminates field strings properly
+ print chdir($1)
+ print ERRNO
+}
diff --git a/test/apiterm.in b/test/apiterm.in
new file mode 100644
index 00000000..c4732514
--- /dev/null
+++ b/test/apiterm.in
@@ -0,0 +1 @@
+. fubar
diff --git a/test/apiterm.ok b/test/apiterm.ok
new file mode 100644
index 00000000..ef4043be
--- /dev/null
+++ b/test/apiterm.ok
@@ -0,0 +1,3 @@
+.
+0
+
diff --git a/test/arrayind1.awk b/test/arrayind1.awk
index 5d4a6f3d..59e8b4ea 100755..100644
--- a/test/arrayind1.awk
+++ b/test/arrayind1.awk
@@ -1,4 +1,3 @@
-#!/usr/local/bin/awk -f
# this script renums pedigrees with metafounders
# so that they are added *before*regular animals
# mf are ascertained because they are not in the 1st column
diff --git a/test/arrayind2.awk b/test/arrayind2.awk
new file mode 100644
index 00000000..200694eb
--- /dev/null
+++ b/test/arrayind2.awk
@@ -0,0 +1,8 @@
+BEGIN {
+ pos[0] = 0
+ posout[0] = 0
+ split("00000779770060", f) # f[1] is a strnum
+ print typeof(f[1])
+ pos[f[1]] = 1
+ print typeof(f[1])
+}
diff --git a/test/arrayind2.ok b/test/arrayind2.ok
new file mode 100644
index 00000000..335b2005
--- /dev/null
+++ b/test/arrayind2.ok
@@ -0,0 +1,2 @@
+strnum
+strnum
diff --git a/test/arrayind3.awk b/test/arrayind3.awk
new file mode 100644
index 00000000..ca4c58b5
--- /dev/null
+++ b/test/arrayind3.awk
@@ -0,0 +1,19 @@
+BEGIN {
+ # initialize cint arrays
+ pos[0] = 0
+ posout[0] = 0
+ split("00000779770060", f) # f[1] is a strnum
+ pos[f[1]] = 1 # subscripts must be strings!
+ for (x in pos) {
+ # if x is a strnum, then the
+ # x != 0 test may convert it to an integral NUMBER,
+ # and we might lose the unusual string representation
+ # if the cint code is not careful to recognize that this is
+ # actually a string
+ if (x != 0)
+ posout[x] = pos[x]
+ }
+ # which array element is populated?
+ print posout[779770060]
+ print posout["00000779770060"]
+}
diff --git a/test/arrayind3.ok b/test/arrayind3.ok
new file mode 100644
index 00000000..a464d9da
--- /dev/null
+++ b/test/arrayind3.ok
@@ -0,0 +1,2 @@
+
+1
diff --git a/test/arrdbg.awk b/test/arrdbg.awk
new file mode 100644
index 00000000..951acb41
--- /dev/null
+++ b/test/arrdbg.awk
@@ -0,0 +1,17 @@
+function check(x, exptype, f) {
+ f[x]
+ printf "array_f subscript [%s]\n", x
+ printf "array_f subscript [%s]\n", x > okfile
+ adump(f, -1)
+ printf " array_func: %s_array_func\n", exptype > okfile
+}
+
+BEGIN {
+ check(3.0, "cint")
+ check(-3, "int")
+ check("3.0", "str")
+ split(" 3", f, "|") # create a maybe_num value
+ check(f[1], "str")
+ check("0", "cint")
+ check("-1", "int")
+}
diff --git a/test/badargs.ok b/test/badargs.ok
index 1664ec1c..cd66dda0 100644
--- a/test/badargs.ok
+++ b/test/badargs.ok
@@ -26,6 +26,7 @@ Short options: GNU long options: (extensions)
-p[file] --profile[=file]
-P --posix
-r --re-interval
+ -s --no-optimize
-S --sandbox
-t --lint-old
-V --version
diff --git a/test/clos1way6.awk b/test/clos1way6.awk
new file mode 100644
index 00000000..f10c0193
--- /dev/null
+++ b/test/clos1way6.awk
@@ -0,0 +1,7 @@
+BEGIN {
+ cmd = "cat - 1>&2; sleep 2"
+ PROCINFO[cmd, "NONFATAL"] = 1
+ print "test1" |& cmd; close(cmd, "to")
+ fflush(cmd)
+ print "test2" |& cmd; print gensub(/number/, "descriptor", 1, ERRNO)
+}
diff --git a/test/clos1way6.ok b/test/clos1way6.ok
new file mode 100644
index 00000000..5768617d
--- /dev/null
+++ b/test/clos1way6.ok
@@ -0,0 +1,3 @@
+gawk: clos1way6.awk:5: warning: fflush: cannot flush: two-way pipe `cat - 1>&2; sleep 2' has closed write end
+test1
+Bad file descriptor
diff --git a/test/dbugeval2.awk b/test/dbugeval2.awk
new file mode 100644
index 00000000..4997d1b4
--- /dev/null
+++ b/test/dbugeval2.awk
@@ -0,0 +1,4 @@
+BEGIN {
+ a = 2
+ b = 3
+}
diff --git a/test/dbugeval2.in b/test/dbugeval2.in
new file mode 100644
index 00000000..165f7147
--- /dev/null
+++ b/test/dbugeval2.in
@@ -0,0 +1,3 @@
+b 3
+r
+eval "print and(a, 3)"
diff --git a/test/dbugeval2.ok b/test/dbugeval2.ok
new file mode 100644
index 00000000..4d645269
--- /dev/null
+++ b/test/dbugeval2.ok
@@ -0,0 +1,7 @@
+Breakpoint 1 set at file `dbugeval2.awk', line 3
+Starting program:
+Stopping in BEGIN ...
+Breakpoint 1, main() at `dbugeval2.awk':3
+3 b = 3
+2
+EXIT CODE: 2
diff --git a/test/dbugtypedre1.awk b/test/dbugtypedre1.awk
new file mode 100644
index 00000000..b8c0b6d7
--- /dev/null
+++ b/test/dbugtypedre1.awk
@@ -0,0 +1 @@
+@include "typeof1.awk"
diff --git a/test/dbugtypedre1.in b/test/dbugtypedre1.in
new file mode 100644
index 00000000..00158c65
--- /dev/null
+++ b/test/dbugtypedre1.in
@@ -0,0 +1,4 @@
+watch e
+run
+next
+p e
diff --git a/test/dbugtypedre1.ok b/test/dbugtypedre1.ok
new file mode 100644
index 00000000..dffee0e8
--- /dev/null
+++ b/test/dbugtypedre1.ok
@@ -0,0 +1,17 @@
+Watchpoint 1: e
+Starting program:
+number
+untyped
+regexp
+string
+array number
+Stopping in BEGIN ...
+Watchpoint 1: e
+ Old value: untyped variable
+ New value: @/foo/
+main() at `typeof1.awk':7
+7 e = @/foo/ ; print typeof(e)
+regexp
+8 print typeof(@/bar/)
+e = @/foo/
+EXIT CODE: 2
diff --git a/test/dbugtypedre2.awk b/test/dbugtypedre2.awk
new file mode 100644
index 00000000..a78de32b
--- /dev/null
+++ b/test/dbugtypedre2.awk
@@ -0,0 +1 @@
+BEGIN { x = 0; x = @/[a-z]/; x = "" }
diff --git a/test/dbugtypedre2.in b/test/dbugtypedre2.in
new file mode 100644
index 00000000..d01ce5a5
--- /dev/null
+++ b/test/dbugtypedre2.in
@@ -0,0 +1,4 @@
+w x
+ r
+ n
+ n
diff --git a/test/dbugtypedre2.ok b/test/dbugtypedre2.ok
new file mode 100644
index 00000000..9c04e1e7
--- /dev/null
+++ b/test/dbugtypedre2.ok
@@ -0,0 +1,15 @@
+Watchpoint 1: x
+Starting program:
+Stopping in BEGIN ...
+Watchpoint 1: x
+ Old value: untyped variable
+ New value: 0
+main() at `dbugtypedre2.awk':1
+1 BEGIN { x = 0; x = @/[a-z]/; x = "" }
+Watchpoint 1: x
+ Old value: 0
+ New value: @/[a-z]/
+main() at `dbugtypedre2.awk':1
+1 BEGIN { x = 0; x = @/[a-z]/; x = "" }
+Program exited normally with exit value: 0
+EXIT CODE: 2
diff --git a/test/dumpvars.ok b/test/dumpvars.ok
index 85d1c859..7caecd35 100644
--- a/test/dumpvars.ok
+++ b/test/dumpvars.ok
@@ -9,7 +9,7 @@ FILENAME: "-"
FNR: 3
FPAT: "[^[:space:]]+"
FS: " "
-FUNCTAB: array, 41 elements
+FUNCTAB: array, 42 elements
IGNORECASE: 0
LINT: 0
NF: 1
diff --git a/test/errno.awk b/test/errno.awk
new file mode 100644
index 00000000..bcb77614
--- /dev/null
+++ b/test/errno.awk
@@ -0,0 +1,10 @@
+BEGIN {
+ # check that PROCINFO["errno"] is working properly
+ getline
+ if (close(FILENAME)) {
+ print "Error `" ERRNO "' closing input file"
+ print "errno =", PROCINFO["errno"]
+ }
+ getline < (FILENAME "/bogus")
+ print (PROCINFO["errno"] > 0), ERRNO
+}
diff --git a/test/errno.in b/test/errno.in
new file mode 100644
index 00000000..a92d664b
--- /dev/null
+++ b/test/errno.in
@@ -0,0 +1,3 @@
+line 1
+line 2
+line 3
diff --git a/test/errno.ok b/test/errno.ok
new file mode 100644
index 00000000..181afdaf
--- /dev/null
+++ b/test/errno.ok
@@ -0,0 +1,3 @@
+Error `close of redirection that was never opened' closing input file
+errno = 0
+1 Not a directory
diff --git a/test/fldterm.awk b/test/fldterm.awk
new file mode 100644
index 00000000..26fe01fb
--- /dev/null
+++ b/test/fldterm.awk
@@ -0,0 +1,10 @@
+BEGIN {
+ # choose a field separator that is numeric, so we can test whether
+ # force_number properly handles unterminated numeric field strings
+ FS = "3"
+}
+
+{
+ print $1+0
+ print $1
+}
diff --git a/test/fldterm.in b/test/fldterm.in
new file mode 100644
index 00000000..14a41cae
--- /dev/null
+++ b/test/fldterm.in
@@ -0,0 +1 @@
+5.53apple
diff --git a/test/fldterm.ok b/test/fldterm.ok
new file mode 100644
index 00000000..ecd7600e
--- /dev/null
+++ b/test/fldterm.ok
@@ -0,0 +1,2 @@
+5.5
+5.5
diff --git a/test/forcenum.awk b/test/forcenum.awk
new file mode 100644
index 00000000..1a7ddce7
--- /dev/null
+++ b/test/forcenum.awk
@@ -0,0 +1,6 @@
+BEGIN {
+ # make some strnums
+ nf = split("|5apple|+NaN| 6|0x1az|011Q|027", f, "|")
+ for (i = 1; i <= nf; i++)
+ printf "[%s] -> %g (type %s)\n", f[i], f[i], typeof(f[i])
+}
diff --git a/test/forcenum.ok b/test/forcenum.ok
new file mode 100644
index 00000000..a379db62
--- /dev/null
+++ b/test/forcenum.ok
@@ -0,0 +1,7 @@
+[] -> 0 (type string)
+[5apple] -> 5 (type string)
+[+NaN] -> nan (type strnum)
+[ 6] -> 6 (type strnum)
+[0x1az] -> 26 (type string)
+[011Q] -> 9 (type string)
+[027] -> 23 (type strnum)
diff --git a/test/fpat6.awk b/test/fpat6.awk
new file mode 100644
index 00000000..de7824a4
--- /dev/null
+++ b/test/fpat6.awk
@@ -0,0 +1,8 @@
+BEGIN {
+ FPAT = "([^,]*)|(\"[^\"]+\")"
+}
+{
+ print "NF =", NF
+ for (i = 1; i <= NF; i++)
+ printf("$%d = <%s>\n", i, $i)
+}
diff --git a/test/fpat6.in b/test/fpat6.in
new file mode 100644
index 00000000..1924cd97
--- /dev/null
+++ b/test/fpat6.in
@@ -0,0 +1,13 @@
+,,3
+,,3
+,,a,,b,,
+,,a,,b,,
+"a",,"b"
+
+
+""
+""
+xx
+xx
+,
+,
diff --git a/test/fpat6.ok b/test/fpat6.ok
new file mode 100644
index 00000000..f9c393a1
--- /dev/null
+++ b/test/fpat6.ok
@@ -0,0 +1,44 @@
+NF = 3
+$1 = <>
+$2 = <>
+$3 = <3>
+NF = 3
+$1 = <>
+$2 = <>
+$3 = <3>
+NF = 7
+$1 = <>
+$2 = <>
+$3 = <a>
+$4 = <>
+$5 = <b>
+$6 = <>
+$7 = <>
+NF = 7
+$1 = <>
+$2 = <>
+$3 = <a>
+$4 = <>
+$5 = <b>
+$6 = <>
+$7 = <>
+NF = 3
+$1 = <"a">
+$2 = <>
+$3 = <"b">
+NF = 0
+NF = 0
+NF = 1
+$1 = <"">
+NF = 1
+$1 = <"">
+NF = 1
+$1 = <xx>
+NF = 1
+$1 = <xx>
+NF = 2
+$1 = <>
+$2 = <>
+NF = 2
+$1 = <>
+$2 = <>
diff --git a/test/fwtest3.awk b/test/fwtest3.awk
index d1384eaf..5e96c1aa 100644
--- a/test/fwtest3.awk
+++ b/test/fwtest3.awk
@@ -1 +1,6 @@
-BEGIN { FIELDWIDTHS="5" } { print $1 }
+BEGIN {
+ FIELDWIDTHS = "2:13 2:13 2:13";
+}
+{
+ printf "%s|%s|%s\n", $1, $2, $3
+}
diff --git a/test/fwtest3.ok b/test/fwtest3.ok
index e56e15bb..f4d28232 100644
--- a/test/fwtest3.ok
+++ b/test/fwtest3.ok
@@ -1 +1,12 @@
-12345
+ 0.4867373206| 1.3206333033|-0.2333178127
+ 0.5668176165| 1.3711756314|-0.2193558040
+ 0.4325251781| 1.3399488722|-0.1568307497
+ 0.4900487563| 1.3295759570|-0.2217392402
+-0.6790064191| 1.2536623801|-0.2955415433
+-0.6311440220| 1.2966579993|-0.2246692210
+-0.7209390351| 1.1783407099|-0.2539408209
+-0.6782473356| 1.2495242556|-0.2811436366
+-0.7062054082| 1.1223820964|-1.1619805834
+-0.6491590119| 1.1248946162|-1.0851579675
+-0.7948856821| 1.1208852325|-1.1259821556
+-0.7102549262| 1.1225121126|-1.1475381286
diff --git a/test/fwtest4.awk b/test/fwtest4.awk
new file mode 100644
index 00000000..d1384eaf
--- /dev/null
+++ b/test/fwtest4.awk
@@ -0,0 +1 @@
+BEGIN { FIELDWIDTHS="5" } { print $1 }
diff --git a/test/fwtest3.in b/test/fwtest4.in
index a32a4347..a32a4347 100644
--- a/test/fwtest3.in
+++ b/test/fwtest4.in
diff --git a/test/fwtest4.ok b/test/fwtest4.ok
new file mode 100644
index 00000000..e56e15bb
--- /dev/null
+++ b/test/fwtest4.ok
@@ -0,0 +1 @@
+12345
diff --git a/test/fwtest5.awk b/test/fwtest5.awk
new file mode 100644
index 00000000..be030eab
--- /dev/null
+++ b/test/fwtest5.awk
@@ -0,0 +1,2 @@
+BEGIN { FIELDWIDTHS = "2 3 4" }
+{ print NF }
diff --git a/test/fwtest5.in b/test/fwtest5.in
new file mode 100644
index 00000000..c24c70ed
--- /dev/null
+++ b/test/fwtest5.in
@@ -0,0 +1,4 @@
+12
+12345
+123456789
+123456789abcd
diff --git a/test/fwtest5.ok b/test/fwtest5.ok
new file mode 100644
index 00000000..7d8164bf
--- /dev/null
+++ b/test/fwtest5.ok
@@ -0,0 +1,4 @@
+1
+2
+3
+3
diff --git a/test/fwtest6.awk b/test/fwtest6.awk
new file mode 100644
index 00000000..b36d75a2
--- /dev/null
+++ b/test/fwtest6.awk
@@ -0,0 +1,4 @@
+# BEGIN { FIELDWIDTHS = "2 2 *" }
+BEGIN { FIELDWIDTHS = "2 2 * " }
+{ print NF, $1, $2, $3 }
+END { FIELDWIDTHS = "2 * 2" }
diff --git a/test/fwtest6.in b/test/fwtest6.in
new file mode 100644
index 00000000..fea8d647
--- /dev/null
+++ b/test/fwtest6.in
@@ -0,0 +1 @@
+1234abcdefghi
diff --git a/test/fwtest6.ok b/test/fwtest6.ok
new file mode 100644
index 00000000..9ba87f2a
--- /dev/null
+++ b/test/fwtest6.ok
@@ -0,0 +1,3 @@
+3 12 34 abcdefghi
+gawk: fwtest6.awk:4: (FILENAME=- FNR=1) fatal: `*' must be the last designator in FIELDWIDTHS
+EXIT CODE: 2
diff --git a/test/fwtest7.awk b/test/fwtest7.awk
new file mode 100644
index 00000000..af424d94
--- /dev/null
+++ b/test/fwtest7.awk
@@ -0,0 +1,2 @@
+BEGIN { FIELDWIDTHS = "2 1:*" }
+{ print $1, $2 }
diff --git a/test/fwtest7.in b/test/fwtest7.in
new file mode 100644
index 00000000..1accfe88
--- /dev/null
+++ b/test/fwtest7.in
@@ -0,0 +1 @@
+abcdefghijklmn
diff --git a/test/fwtest7.ok b/test/fwtest7.ok
new file mode 100644
index 00000000..c321c19c
--- /dev/null
+++ b/test/fwtest7.ok
@@ -0,0 +1 @@
+ab defghijklmn
diff --git a/test/fwtest8.awk b/test/fwtest8.awk
new file mode 100644
index 00000000..27cbff44
--- /dev/null
+++ b/test/fwtest8.awk
@@ -0,0 +1,2 @@
+BEGIN { FIELDWIDTHS = "2:1 3:-1 4" }
+{ print $2 }
diff --git a/test/fwtest8.in b/test/fwtest8.in
new file mode 100644
index 00000000..b378a015
--- /dev/null
+++ b/test/fwtest8.in
@@ -0,0 +1 @@
+ssAsssBCCCC
diff --git a/test/fwtest8.ok b/test/fwtest8.ok
new file mode 100644
index 00000000..8ecd1678
--- /dev/null
+++ b/test/fwtest8.ok
@@ -0,0 +1,2 @@
+gawk: fwtest8.awk:1: fatal: invalid FIELDWIDTHS value, for field 2, near `-1 4'
+EXIT CODE: 2
diff --git a/test/getfile.awk b/test/getfile.awk
new file mode 100644
index 00000000..6ee783f6
--- /dev/null
+++ b/test/getfile.awk
@@ -0,0 +1,35 @@
+function basename(x) {
+ return gensub(/^.*\//, "", 1, x)
+}
+
+BEGIN {
+ print "BEGIN"
+
+ cmd = "echo hello; echo goodbye"
+ rc = get_file(cmd, "<<", -1, res)
+ print "expected error result", rc, ERRNO
+ print "get_file returned", get_file(cmd, "|<", -1, res)
+ print "input_name", basename(res["input_name"])
+ print (cmd | getline x)
+ print x
+
+ # check that calling get_file on "" triggers the BEGINFILE rule
+ print "get_file returned", get_file("", "", -1, res)
+ print "input_name", basename(res["input_name"])
+ print "end BEGIN"
+}
+
+BEGINFILE {
+ printf "BEGINFILE (%s) ERRNO (%s)\n", basename(FILENAME), ERRNO
+}
+
+ENDFILE {
+ printf "ENDFILE (%s) ERRNO (%s)\n", basename(FILENAME), ERRNO
+}
+
+END {
+ print "END"
+ print (cmd | getline x)
+ print x
+ print close(cmd)
+}
diff --git a/test/getfile.ok b/test/getfile.ok
new file mode 100644
index 00000000..1109a303
--- /dev/null
+++ b/test/getfile.ok
@@ -0,0 +1,17 @@
+BEGIN
+gawk: getfile.awk:9: warning: cannot open unrecognized file type `<<' for `echo hello; echo goodbye'
+get_file: get_file(echo hello; echo goodbye, <<, -1) failed
+expected error result 0
+get_file returned 1
+input_name echo hello; echo goodbye
+1
+hello
+BEGINFILE (-) ERRNO ()
+get_file returned 1
+input_name -
+end BEGIN
+ENDFILE (-) ERRNO ()
+END
+1
+goodbye
+0
diff --git a/test/gsubind.awk b/test/gsubind.awk
new file mode 100644
index 00000000..fce0d818
--- /dev/null
+++ b/test/gsubind.awk
@@ -0,0 +1,9 @@
+BEGIN {
+ f = "foo"
+ p = @/o/
+ gsub(p, "q", f)
+ print f
+ fun = "gsub"
+ @fun(p, "q", f)
+ print f
+}
diff --git a/test/gsubind.ok b/test/gsubind.ok
new file mode 100644
index 00000000..d25f018a
--- /dev/null
+++ b/test/gsubind.ok
@@ -0,0 +1,3 @@
+fqq
+gawk: gsubind.awk:7: fatal: gsub: can be called indirectly only with two arguments
+EXIT CODE: 2
diff --git a/test/id.ok b/test/id.ok
index ab9f6392..7454a4fc 100644
--- a/test/id.ok
+++ b/test/id.ok
@@ -40,7 +40,6 @@ cos -> builtin
dcgettext -> builtin
dcngettext -> builtin
exp -> builtin
-extension -> builtin
fflush -> builtin
function1 -> user
gensub -> builtin
@@ -48,6 +47,7 @@ gsub -> builtin
i -> untyped
index -> builtin
int -> builtin
+intdiv -> builtin
isarray -> builtin
length -> builtin
log -> builtin
@@ -71,4 +71,5 @@ system -> builtin
systime -> builtin
tolower -> builtin
toupper -> builtin
+typeof -> builtin
xor -> builtin
diff --git a/test/ignrcas4.awk b/test/ignrcas4.awk
new file mode 100644
index 00000000..e74eea64
--- /dev/null
+++ b/test/ignrcas4.awk
@@ -0,0 +1,7 @@
+BEGIN {
+ x = "0"
+ print x+0 # trigger NUMCUR
+ IGNORECASE = x # should enable ignorecase, since x is a non-null string
+ y = "aBc"
+ print (y ~ /abc/)
+}
diff --git a/test/ignrcas4.ok b/test/ignrcas4.ok
new file mode 100644
index 00000000..0d66ea1a
--- /dev/null
+++ b/test/ignrcas4.ok
@@ -0,0 +1,2 @@
+0
+1
diff --git a/test/intarray.awk b/test/intarray.awk
new file mode 100644
index 00000000..8785ea9e
--- /dev/null
+++ b/test/intarray.awk
@@ -0,0 +1,19 @@
+BEGIN {
+ nf = split("5 |05|0x4|00| 5|-0x12| 011|-013|1.0|5.1e1|-5|-05|+2", f, "|")
+ for (i = 1; i <= nf; i++) {
+ delete g
+ g[f[i]]
+ for (x in g) {
+ if (x"" != f[i]"")
+ printf "Error in string test: [%s] != [%s]\n", x, f[i]
+ }
+
+ delete g
+ z = f[i]+0 # trigger numeric conversion
+ g[f[i]]
+ for (x in g) {
+ if (x"" != f[i]"")
+ printf "Error in strnum test: [%s] != [%s]\n", x, f[i]
+ }
+ }
+}
diff --git a/test/intarray.ok b/test/intarray.ok
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/intarray.ok
diff --git a/test/lintexp.awk b/test/lintexp.awk
new file mode 100644
index 00000000..082d7447
--- /dev/null
+++ b/test/lintexp.awk
@@ -0,0 +1,9 @@
+BEGIN {
+ split("0|0a", f, "|")
+ z = exp(f[1]) # no warning, since strnum converted to number
+ x = f[2]+0 # trigger NUMCUR
+ z = exp(f[2]) # should print a warning
+ x = "0"
+ y = x+0 # trigger NUMCUR
+ z = exp(x) # should print a warning, since x is still a string!
+}
diff --git a/test/lintexp.ok b/test/lintexp.ok
new file mode 100644
index 00000000..33122f6d
--- /dev/null
+++ b/test/lintexp.ok
@@ -0,0 +1,2 @@
+gawk: lintexp.awk:5: warning: exp: received non-numeric argument
+gawk: lintexp.awk:8: warning: exp: received non-numeric argument
diff --git a/test/lintindex.awk b/test/lintindex.awk
new file mode 100644
index 00000000..8e6d7e56
--- /dev/null
+++ b/test/lintindex.awk
@@ -0,0 +1,10 @@
+BEGIN {
+ x = 537
+ y = 3
+ z = index(x, y) # should print lint warning
+ # now that STRCUR has been trigged on x and y, check that we still
+ # get the warning
+ z = index(x, y) # should print lint warning
+ if (z != 2)
+ print "oops"
+}
diff --git a/test/lintindex.ok b/test/lintindex.ok
new file mode 100644
index 00000000..b89db6a5
--- /dev/null
+++ b/test/lintindex.ok
@@ -0,0 +1,4 @@
+gawk: lintindex.awk:4: warning: index: received non-string first argument
+gawk: lintindex.awk:4: warning: index: received non-string second argument
+gawk: lintindex.awk:7: warning: index: received non-string first argument
+gawk: lintindex.awk:7: warning: index: received non-string second argument
diff --git a/test/lintint.awk b/test/lintint.awk
new file mode 100644
index 00000000..f4f687b0
--- /dev/null
+++ b/test/lintint.awk
@@ -0,0 +1,9 @@
+BEGIN {
+ split("0|0a", f, "|")
+ z = int(f[1]) # no warning, since strnum converted to number
+ x = f[2]+0 # trigger NUMCUR
+ z = int(f[2]) # should print a warning
+ x = "0"
+ y = x+0 # trigger NUMCUR
+ z = int(x) # should print a warning, since x is still a string!
+}
diff --git a/test/lintint.ok b/test/lintint.ok
new file mode 100644
index 00000000..5bd5d589
--- /dev/null
+++ b/test/lintint.ok
@@ -0,0 +1,2 @@
+gawk: lintint.awk:5: warning: int: received non-numeric argument
+gawk: lintint.awk:8: warning: int: received non-numeric argument
diff --git a/test/lintlength.awk b/test/lintlength.awk
new file mode 100644
index 00000000..ad217912
--- /dev/null
+++ b/test/lintlength.awk
@@ -0,0 +1,6 @@
+BEGIN {
+ x = 5
+ z = length(x) # should issue a warning
+ y = (x "") # trigger STRCUR
+ z = length(x) # should still issue a warning
+}
diff --git a/test/lintlength.ok b/test/lintlength.ok
new file mode 100644
index 00000000..cb369f7f
--- /dev/null
+++ b/test/lintlength.ok
@@ -0,0 +1,2 @@
+gawk: lintlength.awk:3: warning: length: received non-string argument
+gawk: lintlength.awk:5: warning: length: received non-string argument
diff --git a/test/lintset.awk b/test/lintset.awk
new file mode 100644
index 00000000..8d52eeb4
--- /dev/null
+++ b/test/lintset.awk
@@ -0,0 +1,5 @@
+BEGIN {
+ split("0a", f) # set f[0] to a strnum that is really a string
+ LINT = f[1] # lint should be enabled
+ x = exp("0") # should generate a warning
+}
diff --git a/test/lintset.ok b/test/lintset.ok
new file mode 100644
index 00000000..7d67c614
--- /dev/null
+++ b/test/lintset.ok
@@ -0,0 +1 @@
+gawk: lintset.awk:4: warning: exp: received non-numeric argument
diff --git a/test/mbprintf5.awk b/test/mbprintf5.awk
new file mode 100644
index 00000000..c9a57b48
--- /dev/null
+++ b/test/mbprintf5.awk
@@ -0,0 +1 @@
+{printf "%-5s%s\n", $1, $2}
diff --git a/test/mbprintf5.in b/test/mbprintf5.in
new file mode 100644
index 00000000..c63daaf6
--- /dev/null
+++ b/test/mbprintf5.in
@@ -0,0 +1,3 @@
+Ö ABC
+• ABC
+🜠ABC
diff --git a/test/mbprintf5.ok b/test/mbprintf5.ok
new file mode 100644
index 00000000..252d95e6
--- /dev/null
+++ b/test/mbprintf5.ok
@@ -0,0 +1,3 @@
+Ö ABC
+• ABC
+🜠ABC
diff --git a/test/memleak.awk b/test/memleak.awk
new file mode 100644
index 00000000..3937658f
--- /dev/null
+++ b/test/memleak.awk
@@ -0,0 +1,20 @@
+# This program doesn't do anything except allow us to
+# check for memory leak from using a user-supplied
+# sorting function.
+#
+# From Andrew Schorr.
+
+function my_func(i1, v1, i2, v2) {
+ return v2-v1
+}
+
+BEGIN {
+ a[1] = "3"
+ a[2] = "2"
+ a[3] = "4"
+ for (i = 0; i < 10000; i++) {
+ n = asort(a, b, "my_func")
+ s += n
+ }
+ print s
+}
diff --git a/test/memleak.ok b/test/memleak.ok
new file mode 100644
index 00000000..3a05c8b3
--- /dev/null
+++ b/test/memleak.ok
@@ -0,0 +1 @@
+30000
diff --git a/test/mktime.awk b/test/mktime.awk
new file mode 100644
index 00000000..8a83df14
--- /dev/null
+++ b/test/mktime.awk
@@ -0,0 +1,3 @@
+{
+ print mktime($0, 1)
+}
diff --git a/test/mktime.in b/test/mktime.in
new file mode 100644
index 00000000..bfc7d68a
--- /dev/null
+++ b/test/mktime.in
@@ -0,0 +1 @@
+2017 1 1 0 0 0
diff --git a/test/mktime.ok b/test/mktime.ok
new file mode 100644
index 00000000..677b3ebc
--- /dev/null
+++ b/test/mktime.ok
@@ -0,0 +1 @@
+1483228800
diff --git a/test/mpfrmemok1.ok b/test/mpfrmemok1.ok
index 2389a2d5..6bbd0309 100644
--- a/test/mpfrmemok1.ok
+++ b/test/mpfrmemok1.ok
@@ -2,6 +2,6 @@
# BEGIN rule(s)
BEGIN {
- 1 v = 340282366920938463463374607431768211456
+ 1 v = 0x0100000000000000000000000000000000
}
diff --git a/test/mpfrsqrt.awk b/test/mpfrsqrt.awk
index 23a15c92..3fb1f5f8 100644
--- a/test/mpfrsqrt.awk
+++ b/test/mpfrsqrt.awk
@@ -14,7 +14,7 @@ a=11111111111111111111111111111111111111111111111111111111111
print sqrt(a^2)
#print sq_root(a^2)
-# ADR: Added for gawk-4.1-stable which doesn't have built-in div() function
+# ADR: Added for gawk-4.1-stable which doesn't have built-in intdiv() function
if (PROCINFO["version"] < "4.1.60")
print sq_root2(a^2)
else
@@ -27,9 +27,9 @@ function sq_root(x, temp,r,z)
z=0
while (abs(z-temp)>1)
{ z=temp
- div(x,temp,r)
+ intdiv(x,temp,r)
temp=r["quotient"] + temp
- div(temp,2,r)
+ intdiv(temp,2,r)
temp=r["quotient"]
}
return temp
diff --git a/test/mpfrstrtonum.awk b/test/mpfrstrtonum.awk
new file mode 100644
index 00000000..79d6ad13
--- /dev/null
+++ b/test/mpfrstrtonum.awk
@@ -0,0 +1,5 @@
+BEGIN {
+ x = "011"
+ print x+0 # trigger NUMCUR
+ print strtonum(x)
+}
diff --git a/test/mpfrstrtonum.ok b/test/mpfrstrtonum.ok
new file mode 100644
index 00000000..48a9ed43
--- /dev/null
+++ b/test/mpfrstrtonum.ok
@@ -0,0 +1,2 @@
+11
+9
diff --git a/test/mpgforcenum.awk b/test/mpgforcenum.awk
new file mode 100644
index 00000000..b2d0b6f1
--- /dev/null
+++ b/test/mpgforcenum.awk
@@ -0,0 +1,5 @@
+BEGIN {
+ split("5apple", f) # make a strnum
+ x = f[1]+0 # force strnum conversion to number or string
+ print typeof(f[1]) # should be string
+}
diff --git a/test/mpgforcenum.ok b/test/mpgforcenum.ok
new file mode 100644
index 00000000..ee8a39c3
--- /dev/null
+++ b/test/mpgforcenum.ok
@@ -0,0 +1 @@
+string
diff --git a/test/noeffect.awk b/test/noeffect.awk
index b67a5c57..472c408e 100644
--- a/test/noeffect.awk
+++ b/test/noeffect.awk
@@ -2,4 +2,5 @@ BEGIN {
s == "hello, world";
s + 1
;;
+ "s" 1
}
diff --git a/test/noeffect.ok b/test/noeffect.ok
index e9bed995..6a0cc752 100644
--- a/test/noeffect.ok
+++ b/test/noeffect.ok
@@ -1,4 +1,5 @@
gawk: noeffect.awk:2: warning: statement may have no effect
gawk: noeffect.awk:3: warning: statement may have no effect
+gawk: noeffect.awk:5: warning: statement may have no effect
gawk: noeffect.awk:2: warning: reference to uninitialized variable `s'
gawk: noeffect.awk:3: warning: reference to uninitialized variable `s'
diff --git a/test/nonfatal1.awk b/test/nonfatal1.awk
new file mode 100644
index 00000000..a9228f3a
--- /dev/null
+++ b/test/nonfatal1.awk
@@ -0,0 +1,6 @@
+BEGIN {
+ PROCINFO["NONFATAL"]
+ # note that ":" is not a valid hostname character
+ print |& "/inet/tcp/0/local:host/25"
+ print (ERRNO != "")
+}
diff --git a/test/nonfatal1.ok b/test/nonfatal1.ok
new file mode 100644
index 00000000..51583f2c
--- /dev/null
+++ b/test/nonfatal1.ok
@@ -0,0 +1,2 @@
+gawk: nonfatal1.awk:4: warning: remote host and port information (local:host, 25) invalid
+1
diff --git a/test/nonfatal2.awk b/test/nonfatal2.awk
new file mode 100644
index 00000000..fedbba43
--- /dev/null
+++ b/test/nonfatal2.awk
@@ -0,0 +1,5 @@
+BEGIN {
+ PROCINFO["NONFATAL"] = 1
+ print > "/dev/no/such/file"
+ print ERRNO
+}
diff --git a/test/nonfatal2.ok b/test/nonfatal2.ok
new file mode 100644
index 00000000..ddc88691
--- /dev/null
+++ b/test/nonfatal2.ok
@@ -0,0 +1 @@
+No such file or directory
diff --git a/test/nonfatal3.awk b/test/nonfatal3.awk
new file mode 100644
index 00000000..b2a4ec9e
--- /dev/null
+++ b/test/nonfatal3.awk
@@ -0,0 +1,6 @@
+BEGIN {
+ PROCINFO["NONFATAL"]
+ # valid host but bogus port
+ print |& "/inet/tcp/0/localhost/0"
+ print ERRNO != ""
+}
diff --git a/test/nonfatal3.ok b/test/nonfatal3.ok
new file mode 100644
index 00000000..d00491fd
--- /dev/null
+++ b/test/nonfatal3.ok
@@ -0,0 +1 @@
+1
diff --git a/test/patsplit.ok b/test/patsplit.ok
index cda8319e..02387d86 100644
--- a/test/patsplit.ok
+++ b/test/patsplit.ok
@@ -8,6 +8,7 @@ seps[0] = <>
seps[1] = <,>
seps[2] = <,>
seps[3] = <,>
+seps[4] = <>
Splitting: <Smith,,"1234 A Pretty Place, NE",Sometown,NY,12345-6789,USA>
n = 7
fields[1] = <Smith>
@@ -24,6 +25,7 @@ seps[3] = <,>
seps[4] = <,>
seps[5] = <,>
seps[6] = <,>
+seps[7] = <>
Splitting: <Robbins,Arnold,"1234 A Pretty Place, NE",Sometown,NY,12345-6789,USA>
n = 7
fields[1] = <Robbins>
@@ -40,6 +42,7 @@ seps[3] = <,>
seps[4] = <,>
seps[5] = <,>
seps[6] = <,>
+seps[7] = <>
Splitting: <bbbaaacccdddaaaaaqqqq>
n = 2
fields[1] = <aaa>
diff --git a/test/poundbang.awk b/test/poundbang.awk
index a6440fff..a6440fff 100755..100644
--- a/test/poundbang.awk
+++ b/test/poundbang.awk
diff --git a/test/printfchar.awk b/test/printfchar.awk
new file mode 100644
index 00000000..9e703c31
--- /dev/null
+++ b/test/printfchar.awk
@@ -0,0 +1,7 @@
+BEGIN {
+ x[65]
+ for (i in x) {
+ # i should be a string
+ printf "%c\n", i # should print 1st char of string
+ }
+}
diff --git a/test/printfchar.ok b/test/printfchar.ok
new file mode 100644
index 00000000..1e8b3149
--- /dev/null
+++ b/test/printfchar.ok
@@ -0,0 +1 @@
+6
diff --git a/test/profile10.awk b/test/profile10.awk
new file mode 100644
index 00000000..b78ae447
--- /dev/null
+++ b/test/profile10.awk
@@ -0,0 +1,42 @@
+BEGIN { # Comment 0
+ if (1) { # Comment 1
+ print "ABC" # Comment2
+ } else { # Comment 3
+ print "XYZ" # Comment 4
+ } # Comment 5
+
+ while (c == d) { # Comment 6
+ print "DEF" # Comment 7
+ } # Comment 8
+
+ do { # Comment 9
+ print "GHI" # Comment 10
+ } while (e == f) # Comment 11
+
+ for (i in data) { # Comment 12
+ print "JKL" # Comment 13
+ } # Comment 14
+
+ for (z = 1; z <= 10; z++) { # Comment 15
+ print "MNO" # Comment 16
+ } # Comment 17
+
+ switch (q) { # Comment 18
+ case "a": # Comment 19
+ case "b":
+ # Comment 20
+ break # Comment 21
+ default: # Comment 22
+ break # Comment 23
+ } # Comment 24
+
+ if (1) {
+ print "foo"
+ } # Comment 25
+
+ if (2) {
+ print "bar"
+ }
+ # Comment 26
+}
+# Comment 27
diff --git a/test/profile10.ok b/test/profile10.ok
new file mode 100644
index 00000000..13f0b67b
--- /dev/null
+++ b/test/profile10.ok
@@ -0,0 +1,40 @@
+BEGIN { # Comment 0
+ if (1) { # Comment 1
+ print "ABC" # Comment2
+ } else { # Comment 3
+ print "XYZ" # Comment 4
+ } # Comment 5
+ while (c == d) { # Comment 6
+ print "DEF" # Comment 7
+ } # Comment 8
+ do { # Comment 9
+ print "GHI" # Comment 10
+ } while (e == f) # Comment 11
+ for (i in data) { # Comment 12
+ print "JKL" # Comment 13
+ } # Comment 14
+ for (z = 1; z <= 10; z++) { # Comment 15
+ print "MNO" # Comment 16
+ } # Comment 17
+ switch (q) {
+ case "a":
+ # Comment 18
+ case "b":
+ # Comment 19
+ break # Comment 20
+ # Comment 21
+ default:
+ # Comment 22
+ break # Comment 23
+ }
+ # Comment 24
+ if (1) {
+ print "foo"
+ } # Comment 25
+ if (2) {
+ print "bar"
+ }
+ # Comment 26
+}
+
+# Comment 27
diff --git a/test/profile4.ok b/test/profile4.ok
index dd845c1c..06b31bc1 100644
--- a/test/profile4.ok
+++ b/test/profile4.ok
@@ -1,11 +1,9 @@
- # BEGIN rule(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 720683e2..c8abf1fb 100644
--- a/test/profile5.ok
+++ b/test/profile5.ok
@@ -1,5805 +1,7149 @@
- # BEGIN rule(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 {
- _addlib("_BASE")
- }
+BEGIN {
+ _datablock_length = 262144
+}
- BEGIN {
- BINMODE = "rw"
- SUBSEP = "\000"
- _NULARR[""]
- delete _NULARR[""]
- _INITBASE()
- }
+#_____________________________________________________
+BEGIN {
+ _initrdreg()
+}
- BEGIN {
- _addlib("_sYS")
- }
+#_____________________________________________________
+BEGIN {
+ _initregpath0()
+}
- BEGIN {
- _addlib("_rEG")
- }
+#_____________________________________________________
+BEGIN {
+ _initsys()
+}
- BEGIN {
- _addlib("_INSTRUC")
- }
+#_________________________________________________________________________________________
+##########################################################################################
- BEGIN {
- _delay_perfmsdelay = 11500
- }
- BEGIN {
- _addlib("_ARR")
- }
- BEGIN {
- }
- BEGIN {
- _addlib("_EXTFN")
- }
- BEGIN {
- delete _XCHR
- delete _ASC
- delete _CHR
- t = ""
- for (i = 0; i < 256; i++) {
- _ASC[a = _CHR[i] = sprintf("%c", i)] = i
- _QASC[a] = sprintf("%.3o", i)
- _XCHR[_CHR[i]] = sprintf("%c", (i < 128 ? i + 128 : i - 128))
- }
- for (i = 0; i < 256; i++) {
- _QSTRQ[_CHR[i]] = "\\" sprintf("%.3o", i)
- }
- for (i = 0; i < 32; i++) {
- _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]]
- }
- for (; i < 128; i++) {
- _QSTR[_CHR[i]] = _CHR[i]
- }
- for (; i < 256; i++) {
- _QSTR[_CHR[i]] = _QSTRQ[_CHR[i]]
- }
- _QSTR["\\"] = "\\\\"
- _CHR["CR"] = "\r"
- _CHR["EOL"] = "\r\n"
- _CHR["EOF"] = "\032"
- _QSTR[_CHR["EOL"]] = "\\015\\012"
- _CHR["MONTH"][_CHR["MONTH"]["Jan"] = "01"] = "Jan"
- _CHR["MONTH"][_CHR["MONTH"]["Feb"] = "02"] = "Feb"
- _CHR["MONTH"][_CHR["MONTH"]["Mar"] = "03"] = "Mar"
- _CHR["MONTH"][_CHR["MONTH"]["Apr"] = "04"] = "Apr"
- _CHR["MONTH"][_CHR["MONTH"]["May"] = "05"] = "May"
- _CHR["MONTH"][_CHR["MONTH"]["Jun"] = "06"] = "Jun"
- _CHR["MONTH"][_CHR["MONTH"]["Jul"] = "07"] = "Jul"
- _CHR["MONTH"][_CHR["MONTH"]["Aug"] = "08"] = "Aug"
- _CHR["MONTH"][_CHR["MONTH"]["Sep"] = "09"] = "Sep"
- _CHR["MONTH"][_CHR["MONTH"]["Oct"] = "10"] = "Oct"
- _CHR["MONTH"][_CHR["MONTH"]["Nov"] = "11"] = "Nov"
- _CHR["MONTH"][_CHR["MONTH"]["Dec"] = "12"] = "Dec"
- _TAB_STEP_DEFAULT = 8
- for (i = 0; i < 32; i++) {
- _REXPSTR[_CHR[i]] = _QSTRQ[_CHR[i]]
- }
- for (; i < 256; i++) {
- _REXPSTR[_CHR[i]] = _CHR[i]
- }
- _gensubfn("\\^$.()|{,}[-]?+*", ".", "_rexpstr_i0")
- }
- BEGIN {
- _addlib("_SYSIO")
- }
- BEGIN {
- _SYS_STDCON = "CON"
- _CON_WIDTH = (match(_cmd("MODE " _SYS_STDCON " 2>NUL"), /Columns:[ \t]*([0-9]+)/, A) ? strtonum(A[1]) : 80)
+#BootDevice BuildNumber BuildType Caption CodeSet CountryCode CreationClassName CSCreationClassName CSDVersion CSName CurrentTimeZone DataExecutionPrevention_32BitApplications DataExecutionPrevention_Available DataExecutionPrevention_Drivers DataExecutionPrevention_SupportPolicy Debug Description Distributed EncryptionLevel ForegroundApplicationBoost FreePhysicalMemory FreeSpaceInPagingFiles FreeVirtualMemory InstallDate LargeSystemCache LastBootUpTime LocalDateTime Locale Manufacturer MaxNumberOfProcesses MaxProcessMemorySize MUILanguages Name NumberOfLicensedUsers NumberOfProcesses NumberOfUsers OperatingSystemSKU Organization OSArchitecture OSLanguage OSProductSuite OSType OtherTypeDescription PAEEnabled PlusProductID PlusVersionNumber Primary ProductType RegisteredUser SerialNumber ServicePackMajorVersion ServicePackMinorVersion SizeStoredInPagingFiles Status SuiteMask SystemDevice SystemDirectory SystemDrive TotalSwapSpaceSize TotalVirtualMemorySize TotalVisibleMemorySize Version WindowsDirectory
+#\Device\HarddiskVolume1 7601 Multiprocessor Free Microsoft Windows Server 2008 R2 Enterprise 1252 1 Win32_OperatingSystem Win32_ComputerSystem Service Pack 1 CPU 180 TRUE TRUE TRUE 3 FALSE FALSE 256 0 6925316 33518716 41134632 20110502192745.000000+180 20130426120425.497469+180 20130510134606.932000+180 0409 Microsoft Corporation -1 8589934464 {"en-US"} Microsoft Windows Server 2008 R2 Enterprise |C:\Windows|\Device\Harddisk0\Partition2 0 116 2 10 64-bit 1033 274 18 TRUE 3 Windows User 55041-507-2389175-84833 1 0 33554432 OK 274 \Device\HarddiskVolume2 C:\Windows\system32 C: 50311020 16758448 6.1.7601 C:\Windows
+BEGIN {
+ a = ENVIRON["EGAWK_CMDLINE"]
+ gsub(/^[ \t]*/, "", a)
+ a = _lib_CMDLN(a)
+ if ((a != "") && (! _LIBAPI["F"]["!"])) {
+ _out(_lib_HELP())
+ _fatal("Bad comandline argument `" a "'")
}
-
- BEGIN {
- _addlib("_FILEIO")
+ gsub(/^[ \t]*/, "", a)
+ ENVIRON["EGAWK_CMDLINE"] = a
+ _lib_APPLY()
+ if (_basexit_fl) {
+ exit
}
+ _INIT()
+ _START()
+ _END()
+}
- 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")
- }
+#_____________________________________________________________________________
+END {
+ _EXIT()
+}
- 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"), "")
+#_______________________________________________________________________
+########################################################################
+END {
+ if (_gawk_scriptlevel < 1) {
+ close(_errlog_file)
+ p = _Zimport(_rdfile(_errlog_file), _N())
+ if ((t = _get_errout(p)) != "") {
+ _expout(t, "/dev/stderr")
}
}
+}
- BEGIN {
- _addlib("_SHORTCUT")
- }
-
- BEGIN {
- _shortcut_init()
- }
-
- BEGIN {
- _addlib("_eXTFN")
- }
-
- BEGIN {
- _extfn_init()
- }
-
- BEGIN {
- _addlib("_sHARE")
- }
-
- BEGIN {
- _addlib("_FILEVER")
- }
-
- BEGIN {
- _addlib("_DS")
- _PRODUCT_NAME = "Deployment Solution Control"
- _PRODUCT_VERSION = "1.0"
- _PRODUCT_COPYRIGHT = "Copyright (C) 2013 by CosumoGEN"
- _PRODUCT_FILENAME = "_main.ewk"
- }
-
- BEGIN {
- _inituidefault()
- }
-
- BEGIN {
- _initfilever()
- }
-
- BEGIN {
- _initshare()
- }
-
- BEGIN {
- _inspass(_IMPORT, "_import_data")
- }
-
- BEGIN {
- _TEND[_ARRLEN] = 0
- _TYPEWORD = "_TYPE"
- }
-
- BEGIN {
- _ARRLEN = "\032LEN"
- _ARRPTR = "\032PTR"
- _ARRSTR = ""
- }
-
- BEGIN {
- _getperf_fn = "_nop"
- }
-
- BEGIN {
- _datablock_length = 262144
+##########################################################################################
+# 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 "".
+END {
+ if (_gawk_scriptlevel < 1) {
+ if (! _fileio_notdeltmpflag) {
+ _FILEIO_TMPATHS[_FILEIO_TMPRD]
+ _Foreach(_FILEIO_TMPATHS, "_uninit_del")
+ }
+ }
+}
+
+#___________________________________________________________________________________
+####################################################################################
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#___________________________________________________________________________________
+# 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.
+#_______________________________________________________________________
+#
+# 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
+#___________________________________________________________________________________
+####################################################################################
+END {
+ if (_constatstrln > 0) {
+ _constat()
}
+}
- BEGIN {
- _initrdreg()
- }
+#___________________________________________________________________________________
+####################################################################################
- BEGIN {
- _initregpath0()
- }
- BEGIN {
- _initsys()
- }
-
- BEGIN {
- a = ENVIRON["EGAWK_CMDLINE"]
- gsub(/^[ \t]*/, "", a)
- a = _lib_CMDLN(a)
- if (a != "" && ! _LIBAPI["F"]["!"]) {
- _out(_lib_HELP())
- _fatal("Bad comandline argument `" a "'")
- }
- gsub(/^[ \t]*/, "", a)
- ENVIRON["EGAWK_CMDLINE"] = a
- _lib_APPLY()
- if (_basexit_fl) {
- exit
- }
- _INIT()
- _START()
- _END()
- }
- # END rule(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) {
- _FILEIO_TMPATHS[_FILEIO_TMPRD]
- _Foreach(_FILEIO_TMPATHS, "_uninit_del")
- }
- }
- }
- END {
- if (_constatstrln > 0) {
- _constat()
- }
- }
+# 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
-
- # 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]
+#_______________________________________________________________________
+function W(p, p0, p1)
+{
+ #####################################################
+ if (isarray(p0)) {
+ delete p0[p]
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])
+ p0[p][i][""]
+ delete p0[p][i][""]
+ _N_i0(p0[p][i], p1[i])
} else {
- _[p][p0][i] = p1[i]
+ p0[p][i] = p1[i]
}
}
return p
}
- return (_[p][p0] = p1)
+ return (p0[p] = p1)
}
-
- 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 _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)
+ 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
- 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 p
}
+ return (_[p][p0] = p1)
+}
- function _END()
- {
+##########################################################
+function _ARR(c, t, P)
+{
+ switch (c) {
+ case "_lib_CMDLN":
+ return t
+ #___________________________________________________________
+ case "_lib_APPLY":
+ return
+ #___________________________________________________________
+ case "_lib_HELP":
+ return
+ #___________________________________________________________
+ case "_lib_NAMEVER":
+ return _ln("_ARR 1.0")
+ #___________________________________________________________
+ case "_lib_BEGIN":
+ return
+ #___________________________________________________________
+ case "_lib_END":
+ return
}
-
- 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 _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
}
+}
- function _EXIT()
- {
+#____________________________________________________________________________
+function _DS(c, t, P, a, A)
+{
+ ######################################################
+ switch (c) {
+ case "_lib_CMDLN":
+ #___________________________________________________________
+ return t
+ #_____________________________________________________
+ case "_lib_APPLY":
+ return
+ #_____________________________________________________
+ case "_lib_HELP":
+ return (_ln() _ln(" Usage: " _PRODUCT_NAME " [/key1 /key2...] sourcefile [cmdline]") _ln())
+ #_____________________________________________________
+ case "_lib_NAMEVER":
+ return
+ #_____________________________________________________
+ case "_lib_BEGIN":
+ return
+ #_____________________________________________________
+ case "_lib_END":
+ return
}
+}
- function _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 _END()
+{
+ #################################################################################
+}
- 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
+########################################################
+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 {
- _fileio_notdeltmpflag = ""
+ 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 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"])
+ 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_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 _Foreach(A, f, p0, i)
- {
- for (i in A) {
- @f(A, i, p0)
}
+ 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 _INIT(f)
- {
- }
+#______________________________________________________________________________________________
+function _EXIT()
+{
+ ################################################################################
+}
- function _INITBASE()
- {
- _egawk_utilpath = ENVIRON["EGAWK_PATH"] "BIN\\UTIL\\"
+########################################################
+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 _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 _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 = ""
+ }
}
- }
-
- function _N(F, v, p)
- {
- for (p in _UIDS) {
- delete _UIDS[p]
- return _nN_i0(p, F, v)
+ return t
+ #___________________________________________________________
+ case "_lib_APPLY":
+ if (_fileio_notdeltmpflag) {
+ _info("Temporary objects deletion DISABLED (inherited)")
}
- 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
+ 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 _START(t, i, A)
- {
- _torexp_init()
- test_uid()
- return
- _conl(patsplit("a,b,c", A, /[^,]/, B))
- test_splitstr()
+############################################################
+function _FILEVER(c, t, P, a, A)
+{
+ #_____________________________________________________________________________
+ switch (c) {
+ case "_lib_CMDLN":
+ #################################################
+ return t
+ #___________________________________________________________
+ #_____________________________________________________
+ case "_lib_APPLY":
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_HELP":
return
- _tstini()
+ #_____________________________________________________
+ case "_lib_NAMEVER":
return
- _splitpath_test()
+ #_____________________________________________________
+ case "_lib_BEGIN":
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_END":
return
- _pathSMA = "C:\\Program Files\\Altiris\\Altiris Agent\\"
- DSPlugInPath = _pathSMA "Agents\\Deployment\\Agent\\"
- DSAutoPath = _pathSMA
- if (! _sysinfo(_SYS, _hostname)) {
- _fatal("_sysinfo: unknown error")
- }
- _REG[""]
- delete _REG[""]
- _servoutput = _CHR["EOL"] _cmd("sc query state= all")
- _dsbasepath = "\\\\CPU\\CPU\\DEV\\PROJECT\\_DS\\"
- _rdreg(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris")
- _wrfile("rego.txt", _dumparr(_REG))
- _conl("fF")
- c = _getreg_i1(DDD, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\\204~.*\224Install path", _REG)
- pp = _n("NAME", "NS")
- p = _defsolution(pp, "DS Plug-in", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\")
- ClientConfiguration = _defdll(p, "Client Configuration", "ClientConfiguration")
- ClientImagingPrep = _defdll(p, "Client Inaging Preparation", "ClientImagingPrep")
- ClientImaging = _defdll(p, "Client Imaging", "ClientImaging")
- ClientPCT = _defdll(p, "Client PCT", "ClientPCT")
- ClientRebootTo = _defdll(p, "Client Reboot To", "ClientRebootTo")
- DeploymentAgent = _defdll(p, "Deployment Agent", "Deployment Agent")
- DeploymentSolutionBaseAgent = _defdll(p, "Deployment Solution Base Agent", "Deployment Solution Base Agent")
- ClientBCDEdit = _defile(p, "Client BCD Edit", "ClientBCDEdit.dll")
- ClientCopyFile = _defile(p, "Client Copy File", "ClientCopyFile.dll")
- ClientPreImage = _defile(p, "Client Pre Image", "ClientPreImage.dll")
- ClientRebootTo = _defile(p, "Client Reboot To", "ClientRebootTo.dll")
- _defile(p, "ConfigService.exe", "ConfigService.exe", "")
- _defile(p, "config.dll", "config.dll", "")
- _defsrv(p, "DS Plug-in Service", "Altiris Deployment Solution - System Configuration")
- _defreg(p, "Deployment Agent Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR")
- _defile(p, "Altiris_DeploymentSolutionAgent_7_1_x86.msi", (_SYS["OSArchitecture"] == "64-bit" ? "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{9D76E4CA-377A-472D-A82E-EDAD77E7E4ED}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x64.msi" : "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\SoftwareManagement\\Software Delivery\\{4B747D25-612F-48FC-B6B5-9916D1BB755C}\\cache\\Altiris_DeploymentSolutionAgent_7_1_x86.msi"), "")
- _defdir(p, "Deployment Folder", a = gensub(/[^\\]*$/, "", 1, _rdsafe(_REG, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Deployment\\AgentInstallPath.STR", "C:\\Program Files\\Altiris\\Altiris Agent\\Agents\\Deployment\\Agent\\")))
- p = _defsolution(pp, "DS Auto", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\Altiris Agent\\Plugin Objects\\Agents\\")
- _defdir(p, "C:\\Boot\\Altiris\\iso\\boot\\fonts\\", "C:\\Boot\\Altiris\\iso\\boot\\fonts\\")
- _defdir(p, "C:\\Boot\\Altiris\\iso\\sources\\", "C:\\Boot\\Altiris\\iso\\sources\\")
- _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.exe", "C:\\Boot\\Altiris\\iso\\autoinst.exe", "")
- _defile(p, "C:\\Boot\\Altiris\\iso\\autoinst.ini", "C:\\Boot\\Altiris\\iso\\autoinst.ini", "")
- _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.exe", "C:\\Boot\\Altiris\\iso\\autoutil.exe", "")
- _defile(p, "C:\\Boot\\Altiris\\iso\\autoutil.ini", "C:\\Boot\\Altiris\\iso\\autoutil.ini", "")
- _defile(p, "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "C:\\Boot\\Altiris\\iso\\bcdedit.exe", "")
- _defile(p, "C:\\Boot\\Altiris\\iso\\bootmgr", "C:\\Boot\\Altiris\\iso\\bootmgr", "")
- _defile(p, "C:\\Boot\\Altiris\\iso\\bootsect.exe", "C:\\Boot\\Altiris\\iso\\bootsect.exe", "")
- _defreg(p, "Deployment Automation reg.File", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\File.XSZ", "autoutil.exe")
- _defreg(p, "Deployment Automation reg.Path", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Altiris\\AutoUtil\\Path.XSZ", "%systemdrive%\\boot\\altiris\\iso")
- _check(pp)
- _conl(_report(pp))
- _wrfile("report.txt", _report(pp))
- }
-
- function _SYSIO(c, t, P)
- {
- switch (c) {
- case "_lib_CMDLN":
- return t
- case "_lib_APPLY":
- return
- case "_lib_HELP":
- return
- case "_lib_NAMEVER":
- return _ln("_SYSIO 1.0")
- case "_lib_BEGIN":
- return
- case "_lib_END":
- return
- }
}
+}
- function _W(p, A, v)
- {
- if (isarray(v)) {
- if (p) {
- delete A[p]
- A[p][""]
- delete A[p][""]
- _movarr(A[p], v)
- }
- return p
- }
- if (p) {
- delete A[p]
- return (A[p] = v)
- }
- return v
+function _Foreach(A, f, p0, i)
+{
+ for (i in A) {
+ @f(A, i, p0)
}
+}
- 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
- }
+function _INIT(f)
+{
+}
- 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"))
- }
+#___________________________________________________________________________________
+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 _Zexparr_i1(t)
- {
- gsub(/\x1B/, "\033;", t)
- gsub(/\x11/, "\0331", t)
- gsub(/\x10/, "\0330", t)
- return t
+#___________________________________________________________________________________
+
+
+####################################################################################
+
+
+#_____________________________________________________________________________
+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 _Zexparr_i2(t)
- {
- gsub(/\x10/, "\0330", t)
+#####################################################
+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 _Zexparr_i3(t)
- {
- gsub(/\x1B/, "\033;", t)
- gsub(/\x11/, "\0331", t)
+}
+
+#______________________________________________________________________________________________
+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
+ #___________________________________________________________
+ case "_lib_HELP":
+ return
+ #___________________________________________________________
+ case "_lib_NAMEVER":
+ return _ln("_SYSIO 1.0")
+ #___________________________________________________________
+ case "_lib_BEGIN":
+ return
+ #___________________________________________________________
+ case "_lib_END":
+ return
}
+}
- 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 _W(p, A, v)
+{
+ if (isarray(v)) {
+ if (p) {
+ delete A[p]
+ A[p][""]
+ delete A[p][""]
+ _movarr(A[p], v)
}
+ return p
}
-
- 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]
- }
- 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)
- }
- }
+ if (p) {
+ delete A[p]
+ return (A[p] = v)
}
+ return v
+}
- function _Zimparr_i2(t)
- {
- gsub(/\x1B\x31/, "\021", t)
+#_______________________________________________________________________
+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
+}
+
+#_________________________________________________________________
+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 _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 ((t = _pass(_IMPORT, t, p, A)) != "") {
- gsub(/\x1B\x3B/, "\033", t)
- _wLCHLD(p, _N(_tSTR, t))
- }
+#_________________________________________________________________
+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]
}
- return p
+ D[n] = _Zimparr_i2(substr(t, a + 1))
} else {
- _expout(t)
+ 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 ((t = _pass(_IMPORT, t, p, A)) != "") {
+ gsub(/\x1B\x3B/, "\033", t)
+ _wLCHLD(p, _N(_tSTR, 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 {
- A[--A[_ARRPTR]] = a t
- }
+ 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 {
- A[++A[_ARRLEN]] = t
+ A[--A[_ARRPTR]] = a t
}
- return ""
+ } else {
+ A[++A[_ARRLEN]] = t
}
- return (a t)
+ return ""
}
- return a
+ return (a t)
}
+ return a
+}
- 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 {
+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
}
- _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 ""
}
+ return d
+}
- function _bframe_i0(A, t, p, f)
- {
- return ((f ? _bframe_i0(A, t, p, A[f]) (@f(t, p)) : ""))
- }
+#_____________________________________________________________________________
+function _addlib(f)
+{
+ ###########################################################
+ _addf(_LIBAPI, f)
+}
- function _cfguid(p, optr, pfx, sfx, hstrcnt, lstrchr)
- {
- delete _UIDOBL[p]
- if (_isptr(optr)) {
- if (optr == p) {
- delete _UIDOBLV[p]
- delete _UIDOBLV[_UIDOBLV[_UIDOBL[p] = p][""] = p][""]
- } else if (optr in _UIDOBL) {
- _UIDOBL[p] = _UIDOBL[optr]
- }
- }
- _UIDPFX[p] = (_istr(pfx) ? pfx : "")
- _UIDSFX[p] = (_istr(sfx) ? sfx : "")
- if (_isptr(hstrcnt)) {
- if (hstrcnt != p) {
- _UIDCHR[p] = _UIDCHR[_UIDCNT[p] = _UIDCNT[hstrcnt]]
- return p
- }
- hstrcnt = _NOP
- }
- _UIDCNTL[_UIDCNT[p] = p] = _cfguidchr(p, hstrcnt, lstrchr)
- return p
- }
+#___________________________________________________________________________________
+####################################################################################
- function _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 _addlist(A, v)
+{
+ ##################################################
+ A[++A[0]] = v
+}
- function _check(p)
- {
- _dll_check(p)
- _file_check(p)
- _serv_check(p)
- _reg_check(p)
+############################################
+function _bearray(A)
+{
+ #_______________________________________________________________________
+ if (isarray(A) || (A == 0 && A == "")) {
+ return 1 ####################################################
}
+}
- 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 _bframe(A, t, p)
+{
+ ###########################################
+ return _bframe_i0(A, t, p, A[""])
+}
- 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 _bframe_i0(A, t, p, f)
+{
+ return (f ? (_bframe_i0(A, t, p, A[f]) (@f(t, p))) : "")
+}
- 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
- }
+# add to _dumparr: checking that if element is undefined
- 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
- }
- }
- } 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 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)
- }
+#_______________________________________________________________________
+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 if (optr in _UIDOBL) {
+ _UIDOBL[p] = _UIDOBL[optr]
}
- return a
}
-
- function _delay(t, a)
- {
- for (a = 1; a <= t; a++) {
- _delayms()
+ _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 _delayms(a)
- {
- for (a = 1; a <= _delay_perfmsdelay; 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 _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 _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]
+ 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
}
-
- function _delf(A, f)
- {
- A["B"][A["F"][A["B"][f]] = A["F"][f]] = A["B"][f]
- delete A["F"][f]
- delete A["B"][f]
+ RLENGTH = d
+}
+
+#_______________________________________________________________________
+function _conin(t, a, b)
+{
+ #################################################
+ _constatpush()
+ _constat()
+ a = BINMODE
+ b = RS
+ BINMODE = "rw"
+ RS = "\n"
+ _con(t)
+ getline t < "CON"
+ close("CON")
+ _conlastrln = 0
+ _conlastr = ""
+ gsub(/[\x0D\x0A]+/, "", t)
+ BINMODE = a
+ RS = b
+ _constatpop()
+ return t
+}
+
+#_______________________________________________________________________
+function _conl(t, ts)
+{
+ ####################################################
+ return _con(t (t ~ /\x0A$/ ? "" : _CHR["EOL"]), ts)
+}
+
+#_______________________________________________________________________
+function _conline(t, ts)
+{
+ #################################################
+ return _con(_chrline(t, ts))
+}
+
+#___________________________________________________________________________________
+####################################################################################
+function _conlq(t, ts)
+{
+ return _conl("`" t "'", ts)
+}
+
+#_______________________________________________________________________
+function _constat(t, ts, ln, a)
+{
+ ###########################################
+ if (_constatstrln > (ln = length(t = _constatgtstr(_constatstr = _tabtospc(t, ts), _CON_WIDTH - 1 - _conlastrln)))) {
+ t = t _getchrln(" ", _constatstrln - ln)
+ }
+ _constatstrln = ln
+ ln = ORS
+ a = BINMODE
+ BINMODE = "rw"
+ ORS = ""
+ print((t _CHR["CR"] _conlastr)) > _SYS_STDCON
+ fflush(_SYS_STDCON)
+ ORS = ln
+ BINMODE = a
+ return _constatstr
+}
+
+#_________________________________________________________________
+function _constatgtstr(t, ln, a, b)
+{
+ if (ln < 1) {
+ return ""
}
-
- function _deluid(p)
- {
- if (p in _CLASSPTR) {
- _deluida0 = _CLASSPTR[p]
- if (_deluida0 in _UIDOBL) {
- _UIDOBLV[_UIDOBL[_deluida0]][p]
+ 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
}
}
- delete _CLASSPTR[p]
- return _deluida0
- }
-
- function _dir(A, rd, i, r, f, ds, pf, B, C)
- {
- delete A
- gsub(/(^[ \t]*)|([ \t]*$)/, "", rd)
- if (rd == "") {
+ } 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 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 ""
}
- 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 {
+ 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 r
}
+ return a
+}
- 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 _delay(t, a)
+{
+ ###################################################
+ for (a = 1; a <= t; a++) {
+ _delayms()
}
+}
- 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)
+#_________________________________________________________________
+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 ""
+ }
+ 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)
+ }
+ if ((f = _filepath(pf C[6] (C[4] ? "\\" : ""))) != "") {
+ A[f] = ds C[1] " " C[2]
+ r++
}
- } 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]
}
}
- return i
}
-
- function _dll_check(pp)
- {
- _dllchktv = ""
- _missfl = 1
- _tframe("_dll_check_i0", pp, _REG, pp)
- if (1 || "AGENT" in _[pp]) {
- if (_dllchktv != _[pp][".Product Version"]) {
- _dllerr(_[pp]["AGENT"], "agent version (" _[pp][".Product Version"] ") do not match all lib versions: " _dllchktv "'")
+ return r
+}
+
+#_________________________________________________________________
+function _dirtree(A, f, B)
+{
+ #########################################
+ gsub(/(^[ \t]*)|([ \t]*$)/, "", f)
+ delete A
+ A[""]
+ delete A[""]
+ _dirtree_i0(B, 8, split(_cmd("dir \"" f "\" /-C /S 2>NUL"), B, /\x0D?\x0A/), A, f = _filerd(f))
+ return f
+}
+
+#___________________________________________________________
+function _dirtree_i0(B, i, c, A, f, lf, a, C)
+{
+ delete A[f]
+ A[f][0]
+ delete A[f][0]
+ lf = length(f)
+ for (; i <= c; ) {
+ if (match(B[i], /^[ \t]*Directory of (.+)/, C)) {
+ if (substr(a = _filerd(C[1] "\\"), 1, lf) == f) {
+ i = _dirtree_i0(B, i + 4, c, A[f], a)
+ } else {
+ return i
}
- } else if (! _missfl) {
- _creport(pp, "agent not detected in registry")
- } else {
- _dllerr(pp, "agent not detected in registry but some registry entries exist:")
- _tframe("_dll_check_i1", pp, pp)
- }
- }
-
- 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 == "\\") {
+ } 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]
+ }
+ }
+ return i
+}
+
+#_______________________________________________________________________
+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))
- } else {
- if (_dllchktv == "") {
- _dllchktv = v
- } else if (v != _dllchktv) {
- return _dllerr(p, "different versions detected: " _dllchktv "!=" v "'")
- }
- ERRNO = ""
- if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) {
- delete _[p]["DATA"]
- return _dllerr(p, "read lib: " ERRNO, f)
- }
- if (v != (_[p]["VERSION"] = _getfilever(f))) {
- return _dllerr(p, "library file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f)
- }
- _creport(p, "OK: LIBRARY DETECTED(" v "): " substr(f, 1, 100))
- }
+ } #{ 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 {
- tf = 1
- _dllerr(p, "registry corrupt: `" i "' not present")
+ if (_dllchktv == "") {
+ _dllchktv = v
+ } else if (v != _dllchktv) {
+ return _dllerr(p, "different versions detected: " _dllchktv "!=" v "'")
+ }
+ ERRNO = ""
+ if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) {
+ delete _[p]["DATA"]
+ return _dllerr(p, "read lib: " ERRNO, f)
+ }
+ if (v != (_[p]["VERSION"] = _getfilever(f))) {
+ return _dllerr(p, "library file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f)
+ }
+ _creport(p, "OK: LIBRARY DETECTED(" v "): " substr(f, 1, 100))
}
} else {
- _[p]["STATUS"] = "MISSED"
+ tf = 1
+ _dllerr(p, "registry corrupt: `" i "' not present")
}
+ } else {
+ _[p]["STATUS"] = "MISSED"
}
}
+}
- function _dll_check_i1(p, pp, p1, p2, p3, i)
- {
- if (_[p]["TYPE"] == "defdll") {
- for (i in _[p]) {
- if (i ~ /^\./) {
- _dllerr(pp, " " _[p]["REGPATH"] "\\" substr(i, 2))
- }
+#_______________________________________________
+function _dll_check_i1(p, pp, p1, p2, p3, i)
+{
+ if (_[p]["TYPE"] == "defdll") {
+ for (i in _[p]) {
+ if (i ~ /^\./) {
+ _dllerr(pp, " " _[p]["REGPATH"] "\\" substr(i, 2))
}
}
}
+}
- function _dllerr(p, t, f)
- {
- if (t !~ /\x00/) {
- t = "ERROR: \000" t
- }
- _errfl = 1
- _[p]["ERROR"] = _[p]["ERROR"] _ln(t ((f == "" ? "" : ": " f)))
+#___________________________________________________________________________________
+function _dllerr(p, t, f)
+{
+ if (t !~ /\x00/) {
+ t = "ERROR: \000" t
}
+ _errfl = 1
+ _[p]["ERROR"] = _[p]["ERROR"] _ln(t (f == "" ? "" : ": " f))
+}
- function _drawuid(p, cn, ch, o)
- {
- _conl("uid: " p)
- _conl("\toblptr: " ((p in _UIDOBL ? _UIDOBL[p] "'" : "-")))
- if (p in _UIDOBL) {
- if (! _isptr(o = _UIDOBL[p])) {
- _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> oblptr not pointer")
- }
- if (! isarray(_UIDOBLV[o])) {
- _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> no OBLV array at ptr")
- }
+function _drawuid(p, cn, ch, o)
+{
+ _conl("uid: " p)
+ _conl("\toblptr: " (p in _UIDOBL ? _UIDOBL[p] "'" : "-"))
+ if (p in _UIDOBL) {
+ if (! _isptr(o = _UIDOBL[p])) {
+ _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> oblptr not pointer")
}
- _conl("\tprefix: " ((p in _UIDPFX ? _UIDPFX[p] "'" : "-")))
- _conl("\tsuffix: " ((p in _UIDSFX ? _UIDSFX[p] "'" : "-")))
- _conl("\tcounters: " (cn = (p in _UIDCNT ? _UIDCNT[p] "'" : "-")))
- if (cn != "-") {
- _conl("\t\tcntrL: " _UIDCNTL[_UIDCNT[p]] "'")
- _conl("\t\tcntrH: " _UIDCNTH[_UIDCNT[p]] "'")
- }
- _conl("\tcharset: " (ch = (p in _UIDCHR ? _UIDCHR[p] "'" : "-")))
- if (ch != "-") {
- _conl("chrH: ")
- _conl(_dumparr(_UIDCHRH[_UIDCHR[p]]))
- _conl()
- _conl("chrL: ")
- _conl(_dumparr(_UIDCHRL[_UIDCHR[p]]))
- _conl()
- }
- }
-
- function _dumparr(A, t, lv, a)
- {
- b = PROCINFO["sorted_in"]
- PROCINFO["sorted_in"] = "_lengthsort"
- if (isarray(A)) {
- delete _DUMPARR
- _dumparrc = _dumparrd = ""
- _dumparr_i1(A, lv = ((lv == "" ? 16 : (lv == 0 || lv + 0 != 0 ? lv : (lv == "-*" ? -3 : (lv ~ /^\+?\*$/ ? 3 : 16))))) + 0, (lv < 0 ? -1 : 1), 0, _tabtospc(t))
- PROCINFO["sorted_in"] = a
- return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "")
- }
- }
-
- function _dumparr_i1(A, lv, ls, ln, t, t2, i, a, f)
- {
- t2 = _getchrln(" ", length(t))
- if (ln == lv) {
- if (ls > 0) {
- for (i in A) {
- ++a
- }
- } else {
- for (i in A) {
- (isarray(A[i]) ? ++a : "")
- }
- }
- if (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) {
- _DUMPARR[++_dumparrc] = _dumparrd
- _dumparrd = ""
- }
- return
+ if (! isarray(_UIDOBLV[o])) {
+ _conl(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> no OBLV array at ptr")
}
- if (ls >= 0) {
+ }
+ _conl("\tprefix: " (p in _UIDPFX ? _UIDPFX[p] "'" : "-"))
+ _conl("\tsuffix: " (p in _UIDSFX ? _UIDSFX[p] "'" : "-"))
+ _conl("\tcounters: " (cn = p in _UIDCNT ? _UIDCNT[p] "'" : "-"))
+ if (cn != "-") {
+ _conl("\t\tcntrL: " _UIDCNTL[_UIDCNT[p]] "'")
+ _conl("\t\tcntrH: " _UIDCNTH[_UIDCNT[p]] "'")
+ }
+ _conl("\tcharset: " (ch = p in _UIDCHR ? _UIDCHR[p] "'" : "-"))
+ if (ch != "-") {
+ _conl("chrH: ")
+ _conl(_dumparr(_UIDCHRH[_UIDCHR[p]]))
+ _conl()
+ _conl("chrL: ")
+ _conl(_dumparr(_UIDCHRL[_UIDCHR[p]]))
+ _conl()
+ }
+}
+
+#_______________________________________________________________________
+function _dumparr(A, t, lv, a)
+{
+ ############################################
+ b = PROCINFO["sorted_in"]
+ PROCINFO["sorted_in"] = "_lengthsort"
+ if (isarray(A)) {
+ delete _DUMPARR
+ _dumparrc = _dumparrd = ""
+ _dumparr_i1(A, lv = (lv == "" ? 16 : lv == 0 || (lv + 0) != 0 ? lv : lv == "-*" ? -3 : lv ~ /^\+?\*$/ ? 3 : 16) + 0, lv < 0 ? -1 : 1, 0, _tabtospc(t))
+ PROCINFO["sorted_in"] = a
+ return _retarrd(_DUMPARR, _dumparrd, _dumparrd = "")
+ }
+}
+
+#___________________________________________________________
+function _dumparr_i1(A, lv, ls, ln, t, t2, i, a, f)
+{
+ t2 = _getchrln(" ", length(t))
+ if (ln == lv) {
+ if (ls > 0) {
for (i in A) {
- if (! isarray(A[i])) {
- if (length(_dumparrd = _dumparrd ((f ? t2 : t _nop(f = 1))) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) {
- _DUMPARR[++_dumparrc] = _dumparrd
- _dumparrd = ""
- }
- }
+ ++a
}
- }
- for (i in A) {
- if (isarray(A[i])) {
- _dumparr_i1(A[i], lv, ls, ln + ls, _th0((f ? t2 : t), f = 1) "[" i "]")
+ } else {
+ for (i in A) {
+ isarray(A[i]) ? ++a : ""
}
}
- if (! f) {
- if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) {
- _DUMPARR[++_dumparrc] = _dumparrd
- _dumparrd = ""
- }
+ if (length(_dumparrd = _dumparrd t (a > 0 ? " ... (x" a ")" : "") _CHR["EOL"]) > 262144) {
+ _DUMPARR[++_dumparrc] = _dumparrd
+ _dumparrd = ""
}
+ return
}
-
- function _dumpobj(p, f, t, s)
- {
- s = _dumpobj_i0(p, f, t = t "." p "{")
- if (p = _rFCHLD(p)) {
- return (s = s _dumpobjm(p, f, (s ? _getchrln(" ", length(t) - 1) : t " ")))
- }
- return s
- }
-
- 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_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) {
- 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 (ls >= 0) {
+ for (i in A) {
+ if (! isarray(A[i])) {
+ if (length(_dumparrd = _dumparrd (f ? t2 : t _nop(f = 1)) "[" i "]=" A[i] "'" _CHR["EOL"]) > 262144) {
+ _DUMPARR[++_dumparrc] = _dumparrd
+ _dumparrd = ""
}
- return s
}
- return ((e == "" ? "" : t e))
}
- if (A == 0 && A == "") {
- return
+ }
+ for (i in A) {
+ if (isarray(A[i])) {
+ _dumparr_i1(A[i], lv, ls, ln + ls, _th0(f ? t2 : t, f = 1) "[" i "]")
}
- 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))
+ if (! f) {
+ if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) {
+ _DUMPARR[++_dumparrc] = _dumparrd
+ _dumparrd = ""
}
- 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
- }
+#___________________________________________________________________________________
+# OTHER tFUNCTIONs #################################################################
- 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 _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 _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 _dumpobj_i0(p, f, t)
+{
+ if (f == "") {
+ return _dumpobj_i2(p, t)
}
-
- function _endpass(t)
- {
- _endpass_v0 = t
+ if (f == 0) {
+ return _dumpobj_i1(p, t " ")
}
+ return (_dumpobj_i1(p, t " ") _dumpobj_i2(p, _getchrln(" ", length(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 _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 _errnl(t)
- {
- return _err(t ((t ~ /\x0A$/ ? "" : _CHR["EOL"])))
- }
+#___________________________________________________________
+function _dumpobj_i2(p, t)
+{
+ return (_dumpobj_i3(_[p], t " ") _dumpobj_i3(_ptr[p], _getchrln(" ", length(t)) "`", "`"))
+}
- function _error(t, d, A)
- {
- if (_ERRLOG_EF) {
- A["TYPE"] = "ERROR"
- A["TEXT"] = t
- _log(A, d)
+#___________________________________________________________
+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) {
+ 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
+ }
+ return s
}
+ return (e == "" ? "" : t e)
}
-
- function _exit(c)
- {
- exit c
- }
-
- function _export_data(t, i, A)
- {
- A["DATA"] = t
- A["ID"] = i
- _expout("_DATA: " _Zexparr(A) "\n")
+ if (A == 0 && A == "") {
+ 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
+ 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 _extfn_init()
- {
- _formatstrs_init()
- _formatstrd_init()
- _formatrexp_init()
- _unformatstr_init()
- _mac_init()
+}
+
+#_________________________________________________________________
+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 _faccl_i0(A, t, p, P, f, r)
- {
- f = r = ""
- if (isarray(A)) {
- while (f = A[f]) {
- r = (@f(t, p, P)) r
- }
+ 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 {
+ v = _[pp][".Product Version"]
}
- 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)
- }
+ ERRNO = ""
+ if (_th1(_[p]["DATA"] = _rdfile(f), ERRNO)) {
+ delete _[p]["DATA"]
+ return _dllerr(p, "read file: " ERRNO, f)
}
- return r
- }
-
- function _fatal(t, d, A)
- {
- if (_ERRLOG_FF) {
- A["TYPE"] = "FATAL"
- A["TEXT"] = t
- _log(A, d)
+ if (v != "" && v != (_[p]["VERSION"] = _getfilever(f))) {
+ return _dllerr(p, " file version mismatch: ==`" _[p]["VERSION"] "'; !=`" v "'", f)
}
- if (! d) {
- exit
+ _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 _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 _filed(f, dd, d)
+{
+ ##########################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
-
- function _ffaccl(A, t, p, P)
- {
- return _faccl_i0(A["F"], t, p, P)
+ if (f in _FILEDIRFL) {
+ return _FILEDIR[f]
}
-
- function _ffaccr(A, t, p, P)
- {
- return _faccr_i0(A["F"], t, p, P)
+ if (f in _FILEROOT) {
+ if ((d = filegetdrvdir(_FILEROOT[f]))) {
+ _FILEDIRFL[f]
+ }
+ return (_FILEDIR[f] = d _FILEDIR[f])
}
-
- function _fframe(A, t, p)
- {
- return _fframe_i0(A, t, p, A[""])
+ if (((dd = dd ? dd : _FILEIO_RD), f) in _FILEDIR) {
+ return _FILEDIR[dd, f]
}
-
- function _fframe_i0(A, t, p, f)
- {
- return ((f ? (@f(t, p)) _fframe_i0(A, t, p, A[f]) : ""))
+ if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) {
+ return (_FILEDIR[dd, f] = d)
}
+ return d
+}
- function _file(f)
- {
- if ((f = _filerdnehnd(f)) == "") {
- return ""
- }
- return ((f in _FILEXT ? _FILEXT[f] : ""))
+#_________________________________________________________________
+function _filen(f)
+{
+ ################################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
+ return (f in _FILENAM ? _FILENAM[f] : "")
+}
- function _file_check(p)
- {
- if (1 || "AGENT" in _[p]) {
- _tframe("_file_check_i0", p, p)
- }
+#_________________________________________________________________
+function _filene(f)
+{
+ ###############################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
+ return (f in _FILENAM ? _FILENAM[f] : "") (f in _FILEXT ? _FILEXT[f] : "")
+}
- 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 {
- 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 _filenotexist(f, a)
+{
+ ######################################
+ if (f == "") {
+ return ""
}
-
- 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]
- }
- return (_FILEDIR[f] = d _FILEDIR[f])
- }
- if ((dd = (dd ? dd : _FILEIO_RD), f) in _FILEDIR) {
- return _FILEDIR[dd, f]
- }
- if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) {
- return (_FILEDIR[dd, f] = d)
- }
- return d
+ if ((a = _filepath(f)) == "") {
+ ERRNO = "Filepath error `" f "'"
+ return ""
}
-
- function _filen(f)
- {
- if ((f = _filerdnehnd(f)) == "") {
- return ""
- }
- return ((f in _FILENAM ? _FILENAM[f] : ""))
+ _cmd("if exist \"" a "\" exit 1 2>NUL")
+ if (_exitcode == 1) {
+ return (ERRNO = _NOP)
}
+ return a
+}
- function _filene(f)
- {
- if ((f = _filerdnehnd(f)) == "") {
- return ""
- }
- return (((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : "")))
+#_______________________________________________________________________
+function _filepath(f, dd)
+{
+ ################################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
+ return (filegetrootdir(f, dd) (f in _FILENAM ? _FILENAM[f] : "") (f in _FILEXT ? _FILEXT[f] : ""))
+}
- 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)
- }
- return a
+#_________________________________________________________________
+function _filer(f, dd)
+{
+ #############################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
-
- function _filepath(f, dd)
- {
- if ((f = _filerdnehnd(f)) == "") {
- return ""
- }
- return (filegetrootdir(f, dd) ((f in _FILENAM ? _FILENAM[f] : "")) ((f in _FILEXT ? _FILEXT[f] : "")))
+ if (f in _FILEROOT) {
+ return _FILEROOT[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))
+ if (((dd = dd ? dd : _FILEIO_RD), f) in _FILEROOT) {
+ return _FILEROOT[dd, f]
}
+ return (_FILEROOT[dd, f] = fileri(dd))
+}
- function _filerd(f, dd)
- {
- if ((f = _filerdnehnd(f)) == "") {
- return ""
- }
- return filegetrootdir(f, dd)
+#_________________________________________________________________
+function _filerd(f, dd)
+{
+ ############################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
+ return filegetrootdir(f, dd)
+}
- function _filerdn(f, dd)
- {
- if ((f = _filerdnehnd(f)) == "") {
- return ""
- }
- return ((f in _FILENAM ? filegetrootdir(f, dd) _FILENAM[f] : ""))
+#_________________________________________________________________
+function _filerdn(f, dd)
+{
+ ###########################################
+ if ((f = _filerdnehnd(f)) == "") {
+ return ""
}
+ return (f in _FILENAM ? (filegetrootdir(f, dd) _FILENAM[f]) : "")
+}
- 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])
- }
+#_________________________________________________________________
+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 _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]
+#___________________________________________________________
+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[5] A[6]) d (n = A[14]))) in _FILECACHE) {
+ 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
- if (A[8]) {
- _FILEDIRFL[c]
- }
- if (r) {
- _FILEROOT[c] = r
- }
+ _FILEDIRFL[c]
+ _FILEROOT[c] = r
+ } else {
+ FLENGTH = 0
+ _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 (! (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
}
- 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 _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)
+ if (n) {
+ if (match(n, /\.[^\.]*$/)) {
+ _FILEXT[c] = substr(n, RSTART)
+ _FILENAM[c] = substr(n, 1, RSTART - 1)
} else {
- _gen(D, @f(A[i], p0, p1, p2))
+ _FILENAM[c] = n
}
}
+ return c
}
+ return ""
+}
- function _foreach_i1(p, f, D, p0, p1, p2)
- {
- _gen(D, @f(p, p0, p1, p2))
- }
-
- 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 _filexist(f, a)
+{
+ ################################################
+ if (f == "") {
+ return ""
}
-
- function _formatstrs_init()
- {
- _defescarr(_FORMATSTRSESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC)
- _defescarr(_FORMATSTRSESC, "[\\\\']", "\\")
- _FORMATSTRSESC["\t"] = "\\t"
+ if ((a = _filepath(f)) == "") {
+ ERRNO = "Filepath error `" f "'"
+ return ""
}
-
- function _fpp(q, D, S)
- {
- _conl()
- _conline(q)
- _conl()
- q = _patharr0(S, q)
- _conl(_dumparr(S))
- _conl()
- return q
+ _cmd("if exist \"" a "\" exit 1 2>NUL")
+ if (_exitcode == 1) {
+ return a
}
-
- function _fthru(A, c, p, B)
- {
- return _fthru_i0(A, c, p, B, A[""])
+ 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))
+ }
+ }
+}
+
+#_____________________________________________________
+function _foreach_i1(p, f, D, p0, p1, p2)
+{
+ _gen(D, @f(p, p0, p1, p2))
+}
+
+#_____________________________________________________________________________
+function _formatrexp(t)
+{
+ _formatstrq0 = split(t, _FORMATSTRA, /[\/\x00-\x1F\x80-\xFF]/, _FORMATSTRB)
+ _formatstrs0 = ""
+ for (t = 1; t < _formatstrq0; t++) {
+ _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATREXPESC[_FORMATSTRB[t]]
+ }
+ return (_formatstrs0 _FORMATSTRA[t])
+}
+
+#___________________________________________________________
+function _formatrexp_init()
+{
+ _defescarr(_FORMATREXPESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC)
+ _defescarr(_FORMATREXPESC, "\\/", "\\")
+ _FORMATREXPESC["\t"] = "\\t"
+}
+
+#_____________________________________________________________________________
+function _formatstrd(t)
+{
+ _formatstrq0 = split(t, _FORMATSTRA, /["\x00-\x1F\x80-\xFF]/, _FORMATSTRB)
+ _formatstrs0 = ""
+ for (t = 1; t < _formatstrq0; t++) {
+ _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRDESC[_FORMATSTRB[t]]
+ }
+ return (_formatstrs0 _FORMATSTRA[t])
+}
+
+#___________________________________________________________
+function _formatstrd_init()
+{
+ _defescarr(_FORMATSTRDESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC)
+ _defescarr(_FORMATSTRDESC, "[\\\\\"]", "\\")
+ _FORMATSTRDESC["\t"] = "\\t"
+}
+
+#__________________________________________________________________________________
+function _formatstrs(t)
+{
+ ####################################################################################
+
+
+
+
+ #___________________________________________________________________________________
+ _formatstrq0 = split(t, _FORMATSTRA, /['\x00-\x1F\x80-\xFF]/, _FORMATSTRB)
+ _formatstrs0 = ""
+ for (t = 1; t < _formatstrq0; t++) {
+ _formatstrs0 = _formatstrs0 _FORMATSTRA[t] _FORMATSTRSESC[_FORMATSTRB[t]]
+ }
+ return (_formatstrs0 _FORMATSTRA[t])
+}
+
+#___________________________________________________________
+function _formatstrs_init()
+{
+ _defescarr(_FORMATSTRSESC, "[\\x00-\\x1F\\x80-\\xFF]", _QASC)
+ _defescarr(_FORMATSTRSESC, "[\\\\']", "\\")
+ _FORMATSTRSESC["\t"] = "\\t"
+}
+
+function _fpp(q, D, S)
+{
+ _conl()
+ _conline(q)
+ _conl()
+ q = _patharr0(S, q)
+ #_arregpath(D,S)
+ #_conl(_dumparr(D))
+ _conl(_dumparr(S))
+ _conl()
+ return q
+}
+
+#_______________________________________________________________________
+########################################################################
+function _fthru(A, c, p, B)
+{
+ return _fthru_i0(A, c, p, B, A[""])
+}
+
+#_________________________________________________________________
+function _fthru_i0(A, c, p, B, f)
+{
+ return (f ? @f(c, _fthru_i0(A, c, p, B, A[f]), B) : "")
+}
+
+function _gen(D, t)
+{
+ if (length(D[D[_ARRLEN]] = D[D["."]] t) > _datablock_length) {
+ D[++D[_ARRLEN]] = ""
+ }
+}
+
+#_____________________________________________________________________________
+function _gensubfn(t, r, f, p0, A)
+{
+ ###############################################
+ if (match(t, r, A)) {
+ return (substr(t, 1, RSTART - 1) (@f(_th0(substr(t, RSTART, RLENGTH), t = substr(t, RSTART + RLENGTH)), A, p0)) _gensubfn(t, r, f, p0))
+ }
+ return t
+}
+
+#_____________________________________________________________________________
+function _get_errout(p)
+{
+ #######################################################
+ return _tframe("_get_errout_i0", p)
+}
+
+#_______________________________________________________________________
+function _get_errout_i0(p, t, n, a)
+{
+ return (p in _tLOG ? (_get_errout_i1(p) _get_errout_i3(p)) : "")
+}
+
+#_________________________________________________________________
+function _get_errout_i1(p, t, n, a)
+{
+ if (p in _tLOG) {
+ n = ""
+ if (_tLOG[p]["TYPE"]) {
+ n = _tLOG[p]["TYPE"] ": " _get_errout_i2(p)
+ if (match(_tLOG[p]["TEXT"], /\x1F/)) {
+ t = n
+ gsub(/[^\t]/, " ", t)
+ return (_ln(n substr(_tLOG[p]["TEXT"], 1, RSTART - 1)) _ln(t substr(_tLOG[p]["TEXT"], RSTART + 1)))
+ }
+ }
+ return _ln(n _tLOG[p]["TEXT"])
+ }
+}
+
+#_______________________________________________________________________
+function _get_errout_i2(p)
+{
+ return ("FILE" in _tLOG[p] ? (_tLOG[p]["FILE"] ("LINE" in _tLOG[p] ? ("(" _tLOG[p]["LINE"] ")") : "") ": ") : "")
+}
+
+#_______________________________________________________________________
+function _get_errout_i3(p, t, ts, cl, cp, cr, a, b)
+{
+ if ("LSTR" in _tLOG[p]) {
+ t = _tLOG[p]["FULLSTR"]
+ ts = _tLOG[p]["TS"]
+ cp = "^"
+ if ("CSTR" in _tLOG[p]) {
+ cr = _tLOG[p]["CSTR"]
+ cl = _tLOG[p]["CLSTR"]
+ if ("CPSTR" in _tLOG[p]) {
+ cp = _tLOG[p]["CPSTR"]
+ }
+ }
+ cr = substr(cr, length(cl) + length(cp) + 1)
+ return (_ln(_tabtospc(t, ts)) _ln(_getchrln(" ", a = length(_tabtospc(_tLOG[p]["LSTR"], ts))) _getchrln("-", b = length(_tabtospc(cl, ts, a))) _getchrln("^", b = length(_tabtospc(cp, ts, a = a + b))) _getchrln("-", length(_tabtospc(cr, ts, a + b)))))
+ }
+}
+
+#_____________________________________________________________________________
+function _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
}
-
- function _fthru_i0(A, c, p, B, f)
- {
- return ((f ? @f(c, _fthru_i0(A, c, p, B, A[f]), B) : ""))
+ #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 _gen(D, t)
- {
- if (length(D[D[_ARRLEN]] = D[D["."]] t) > _datablock_length) {
- D[++D[_ARRLEN]] = ""
- }
+ 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 _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))
+}
+
+#_________________________________________________________________________________________
+##########################################################################################
+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++
+ }
+ }
+ IGNORECASE = a
+ if (rc > 0) {
+ return rc
+ }
+}
+
+#_________________________________________________________________
+function _getsecond()
+{
+ #############################################
+ return systime()
+}
+
+#___________________________________________________________
+function _getsecondsync(a, c, b, c2)
+{
+ ##########################
+ a = systime()
+ while (a == systime()) {
+ ++c
+ }
+ return (a + 1)
+}
+
+#_______________________________________________________________________
+function _getuid(p)
+{
+ ################################################# 1 #
+ if (p in _UIDOBL) {
+ for (_tptr in _UIDOBLV[_getuida0 = _UIDOBL[p]]) {
+ 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
+}
+
+#_____________________________________________________
+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 _handle8494(t)
+{
+ return gensub(/(.)/, ".\\1", "G", t)
+}
+
+#_____________________________________________________________________________
+function _hexnum(n, l)
+{
+ #########################################################
+ if (l + 0 < 1) {
+ l = 2
+ }
+ return sprintf("%." (l + 0 < 1 ? 2 : l) "X", n)
+}
+
+#_________________________________________________________________
+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)
}
- return t
- }
-
- function _get_errout(p)
- {
- return _tframe("_get_errout_i0", p)
+ _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 _get_errout_i0(p, t, n, a)
- {
- return ((p in _tLOG ? _get_errout_i1(p) _get_errout_i3(p) : ""))
+ 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 _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)))
+ _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]
}
- return _ln(n _tLOG[p]["TEXT"])
- }
+ 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 _get_errout_i2(p)
- {
- return (("FILE" in _tLOG[p] ? _tLOG[p]["FILE"] (("LINE" in _tLOG[p] ? "(" _tLOG[p]["LINE"] ")" : "")) ": " : ""))
+ is = p
+ if (p == 0 && p == "") {
+ it = "-"
+ return 0
}
-
- 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)))))
- }
+ if (p in _CLASSPTR) {
+ return (it = "P")
}
+ it = "S"
+ return 0
+}
- function _get_logout(p)
- {
- return _tframe("_get_logout_i0", p)
+#_______________________________________________________________________
+function _istr(p)
+{
+ ################################################### 1 #
+ if (isarray(p)) {
+ is = _NOP
+ it = "A"
+ return 0
}
-
- 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"])
+ 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 _getchrln(s, w)
- {
- if (s == "") {
- return
+#_________________________________________________________________
+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 (length(s) < w) {
- if (s in _GETCHRLN) {
- if (length(_getchrlnt0 = _GETCHRLN[s]) >= w) {
- return substr(_getchrlnt0, 1, w)
- }
- } else {
- _getchrlnt0 = s s
+ if (A[2]) {
+ if ((l1 = int(A[2, "length"] / ts)) >= (l2 = l - A[1, "length"])) {
+ return (substr(A[2], l2 * ts + 1) A[3])
}
- while (length(_getchrlnt0) < w) {
- _getchrlnt0 = _getchrlnt0 _getchrlnt0
+ if (! A[4]) {
+ return A[5]
}
- _GETCHRLN[s] = _getchrlnt0
- return substr(_getchrlnt0, 1, w)
+ t = A[1] _getchrln("\t", l1) A[3]
} 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]
+ return t
}
}
-
- function _getime()
- {
- return strftime("%H:%M:%S")
- }
-
- function _getmpdir(f, dd)
- {
- if (! dd || ! (dd = _filerd(dd))) {
- dd = _FILEIO_TMPRD
+}
+
+function _mac_init()
+{
+ _MACPFX["\204"] = "_macpfx84"
+ _MACPFX[""] = "_mpupfxsubret"
+ _MACPFX84SFX["\204"] = "_macpfx84"
+ _MACPFX84SFX["\224"] = "_macsfx94"
+ _MACPFX84SFX[""] = "_mpusfxsubret"
+ _VLDMAXSTRING = 1000000
+}
+
+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
+}
+
+#
+# /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 _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 {
+ _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
}
- if (f = (f ? _filerd(f, dd) : _filerd("_" ++_FILEIO_TMPCNTR "\\", dd))) {
- _FILEIO_RDTMP[toupper(f)]
+ } else if (! (F == 0 && F == "")) {
+ if (isarray(v)) {
+ _[p][F][""]
+ delete _[p][F][""]
+ _copyarr(_[p][F], v)
+ } else if (v == 0 && v == "") {
+ _mpu(F, p)
+ } else {
+ _[p][F] = v
}
- return f
}
+ return p
+}
- 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 _newclrdir(f)
+{
+ ############################################
+ if ((f = _filerd(f)) == "") {
+ return
}
-
- 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
+ _cmd("rd " f " /S /Q 2>NUL")
+ _cmd("md " f " 2>NUL")
+ _WFILEROOTDIR[f]
+ return f
+}
+
+#_______________________________________________________________________
+function _newdir(f)
+{
+ #####################################################
+ if ((f = _filerd(f)) == "") {
+ return
}
-
- 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
+ if (! (f in _WFILEROOTDIR)) {
+ _cmd("md " f " 2>NUL")
+ _WFILEROOTDIR[f]
}
-
- 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 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
}
- return 1
- }
-
- function _getperf_noenot(o, t, a)
- {
- return 1
+ _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 _getperf_not(o, t, a)
- {
- if (a < _getperf_end) {
- return 1
+ _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)
}
+ } else {
+ _ARRSTR = v
}
-
- function _getreg_i1(D, r, R, a, i, il, ir, rc, B)
- {
- a = IGNORECASE
+ 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
- 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++
- }
- }
- IGNORECASE = a
- if (rc > 0) {
- return rc
- }
- }
-
- function _getsecond()
- {
- return systime()
- }
-
- 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]]) {
- delete _UIDOBLV[_getuida0][_tptr]
- _CLASSPTR[_tptr] = p
- return _tptr
+ 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
}
+ 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)
}
- _CLASSPTR[_tptr = _UIDPFX[p] _getuid_i0(_UIDCNT[p], _UIDCHRL[_tptr = _UIDCHR[p]], _UIDCHRH[_tptr]) _UIDSFX[p]] = p
- return _tptr
+ return _patharr0_i1(D, A, 3, q)
}
+}
- 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")
+#_____________________________________________________
+function _patharr0_i0(t, D, l, r, d, i)
+{
+ if (i = index(t, ":")) {
+ if (d) {
+ D["type"] = d
}
- return (_UIDCNTH[p] (_UIDCNTL[p] = _tptr))
- }
-
- function _handle8494(t)
- {
- return gensub(/(.)/, ".\\1", "G", t)
- }
-
- function _hexnum(n, l)
- {
- if (l + 0 < 1) {
- l = 2
+ if (i > 1) {
+ D[l] = substr(t, 1, i - 1)
}
- return sprintf("%." ((l + 0 < 1 ? 2 : l)) "X", n)
- }
-
- function _igetperf(t, s, o)
- {
- if (t == 0 && t == "" && s == 0 && s == "" && o == 0 && o == "") {
- if (_getperf_fn !~ /not$/ && _constatstr == _getperf_stat) {
- _constat(_getperf_statstr)
- }
- _getperf_fn = "_nop"
- return ("[TIME=" (_getperf_last - _getperf_start) " sec(" _getperf_opsec " ops/sec)]")
- }
- _conl("initiate _getperf")
- _getperf_opstart = _getperf_opcurr = o + 0
- _getperf_opsec = _getperf_opsecp = _getperf_stat = _getperf_statstr = ""
- _getperf_end = t + (_getperf_start = _getperf_last = _getsecondsync())
- _getperf_fn = ((t + 0 > 0 ? "_getperf_" : "_getperf_noe")) ((s ? "" : "not"))
- return _getperf_start
- }
-
- function _import_data(t, p, p2, a)
- {
- if (match(t, /^_DATA: /)) {
- _tDATA[a = _wLCHLD(p, _N())][""]
- delete _tDATA[a][""]
- _Zimparr(_tDATA[a], substr(t, 8))
- _conl("DATA: `" _tDATA[a]["ID"] "':`" _tDATA[a]["DATA"] "'")
- return ""
+ if ((t = substr(t, i + 1)) && r) {
+ D[r] = t
}
return t
- }
-
- function _info(t, d, A)
- {
- if (_ERRLOG_IF) {
- A["TYPE"] = "INFO"
- A["TEXT"] = t
- _log(A, d)
+ } else if (t && r) {
+ D[l] = t
+ }
+ 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
}
}
-
- 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()
+ while (i < q) {
+ D[0] = D[0] (D[++c] = A[i++]) "/"
}
-
- function _initsys()
- {
+ 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 _inituid(p, cs, dptr, pfx, sfx, hstr, lstr, A)
- {
- if (cs == 0 && cs == "") {
- cs = p
- p = _getuid()
- }
- _conl()
- _conl()
- _conl(cs)
- if (match(cs, /^(([^:]*):)?(([^'\xB4]*\xB4.)*[^'\xB4]*)[']/, A)) {
- pfx = A[3]
- dptr = A[2]
- }
- if (match(cs = substr(cs, 1 + RLENGTH), /'(([^'\xB4]*\xB4.)*[^'\xB4]*)$/, A)) {
- sfx = A[1]
- cs = substr(cs, 1, RSTART - 1)
- }
- if (match(cs, /^(([`\^])(.*))/, A)) {
- if (A[2] == "`") {
- hstr = A[3] "~"
- lstr = ""
- } else {
- lstr = A[3] "+"
- hstr = ""
+#############################################################################
+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 _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
}
- } else if (match(cs, /^(([^'\xB4\|]*\xB4.)*[^'\xB4\|]*)(\|(.*))?/, A)) {
- hstr = A[1]
- lstr = A[4]
} else {
- ERRNO = "_inituid(): bad parameters"
- return
+ for (i in A) {
+ isarray(A[i]) ? ++a : ""
+ }
+ }
+ if (length(_dumparrd = _dumparrd t (a > 0 ? " ... (x" a ")" : "") _CHR["EOL"]) > 262144) {
+ _conl(_dumparrd)
+ _dumparrd = ""
}
- _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])
+ 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 = ""
}
- delete D[df]
}
- D[df][""]
- delete D[df][""]
- return _extarr(D[df], S[sf])
- } else {
- if (isarray(D[df])) {
- delete D[df]
- }
- D[df] = S[sf] D[df]
}
}
}
-
- function _insf(A, f)
- {
- A["F"][""] = A["B"][A["F"][f] = A["F"][""]] = f
- }
-
- function _insframe(A, f)
- {
- A[f] = A[""]
- A[""] = f
- }
-
- function _inspass(A, f)
- {
- A[f] = A[""]
- A[""] = f
- }
-
- function _isptr(p)
- {
- if (isarray(p)) {
- is = _NOP
- it = "A"
- return 0
- }
- is = p
- if (p == 0 && p == "") {
- it = "-"
- return 0
- }
- if (p in _CLASSPTR) {
- return (it = "P")
+ 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 "]")
+ }
}
- it = "S"
- return 0
}
-
- function _istr(p)
- {
- if (isarray(p)) {
- is = _NOP
- it = "A"
- return 0
- }
- is = p
- if (p == 0 && p == "") {
- it = "-"
- return 0
+ if (! f) {
+ if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) {
+ _conl(_dumparrd)
+ _dumparrd = ""
}
- 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 _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 _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")
+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 {
- B["TEXT"] = A
- B["TYPE"] = ""
- return _log(B, p)
- }
+ _qparama0 = "S"
+ }
+ 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 _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 _rFBRO(p)
+{
+ ######################################################
+ if (p) {
+ if (p in _tPARENT) {
+ return _tFCHLD[_tPARENT[p]]
}
- }
-
- function _mac_init()
- {
- _MACPFX["\204"] = "_macpfx84"
- _MACPFX[""] = "_mpupfxsubret"
- _MACPFX84SFX["\204"] = "_macpfx84"
- _MACPFX84SFX["\224"] = "_macsfx94"
- _MACPFX84SFX[""] = "_mpusfxsubret"
- _VLDMAXSTRING = 1000000
- }
-
- 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
+ while (p in _tPREV) {
+ p = _tPREV[p]
}
- return t
- }
-
- function _mpudefaulthnd(F, D, C, p1, p2, p3)
- {
- _mpuretsub(D, _mpucc0)
- }
-
- function _mpupfxsubret(F, D, C, p1, p2, p3)
- {
- return 1
- }
-
- function _mpuretsub(D, t)
- {
- _mpuacc = D[_mpuptr++]
- _accmpu(D, t)
- return 1
+ return p
}
+ return p
+}
- function _mpusfxsubret(F, D, C, p1, p2, p3)
- {
- return -1
+#_______________________________________________________________________
+function _rFCHLD(p)
+{
+ #####################################################
+ if ((p) && (p in _tFCHLD)) {
+ return _tFCHLD[p]
}
+ return ""
+}
- 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 {
- _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
+######################## p="", !v
+function _rLBRO(p)
+{
+ #_______________________________________________________________________
+ if (p) { ######################################################
+ if (p in _tPARENT) {
+ return _tLCHLD[_tPARENT[p]]
}
- _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]
- if (isarray(v)) {
- F[p][""]
- delete F[p][""]
- _copyarr(F[p], 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)
- } else if (v == 0 && v == "") {
- _mpu(F, p)
- } else {
- _[p][F] = v
- }
+ while (p in _tNEXT) {
+ p = _tNEXT[p]
}
return p
}
-
- function _newclrdir(f)
- {
- if ((f = _filerd(f)) == "") {
- return
+ 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]]
}
- _cmd("rd " f " /S /Q 2>NUL")
- _cmd("md " f " 2>NUL")
- _WFILEROOTDIR[f]
- return f
- }
-
- function _newdir(f)
- {
- if ((f = _filerd(f)) == "") {
- return
+ c = 1
+ p1 = p
+ while (p1 in _tPREV) {
+ c++
+ p1 = _tPREV[p1]
}
- if (! (f in _WFILEROOTDIR)) {
- _cmd("md " f " 2>NUL")
- _WFILEROOTDIR[f]
+ while (p in _tNEXT) {
+ c++
+ p = _tNEXT[p]
}
- return f
+ return c
}
+ 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 _nop(p0, p1, p2, p3)
- {
+#_______________________________________________________________________
+function _rSQNEXT(g, p, A)
+{
+ ################################################
+ if (isarray(A)) {
+ return _rSQNEXTA(g, p, A)
}
+ return _rsqnext_i0(g, p)
+}
- function _nretarr(A, i, v, r, q)
- {
- if ((i = (i == "" ? 1 : i + 0)) <= (q = A[_ARRLEN])) {
- if (i <= (r = q - 16)) {
- _ARRSTR = A[i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i]
- while (i < r) {
- _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i]
- }
- _ARRSTR = _ARRSTR A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] A[++i] v _retarr_i0(A, q, i)
- return
- }
- _ARRSTR = A[i] A[++i] A[++i] A[++i] 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 _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)
}
- _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)
- }
- } else {
- _ARRSTR = v
+ while (p in _tNEXT) {
+ if ((p = _rsqgetptr(g, _tNEXT[p])) in A) {
+ return p
}
- delete A
- A[""]
- delete A[""]
}
+ return (p in _tPARENT ? _rSQNEXTA(g, _tPARENT[p], 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 _rconl(t)
+{
+ _rprt = _rprt _ln(t)
+}
- 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 _rconline(t)
+{
+ _rprt = _rprt _ln((t = " " t " ") _getchrln("_", _CON_WIDTH - length(t) - 1))
+}
- 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 _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 _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 _rdfile(f, i, A)
+{
+ ################################################
+ if (((f = _filerdne(f)) == "") || (_filene(f) == "")) {
+ ERRNO = "Filename error"
+ return
}
-
- 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)
+ _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)
}
-
- 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
+ if (ERRNO == "") {
+ return RT
}
-
- 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
+ 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 {
+ break
+ }
+ } else if (_rdregp0 ~ /^HK/) {
+ ++_rdregkey
+ return D[_rdregp0 = _rdregp0 "\\"]
+ }
+ }
+ 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 _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))
}
- D["host"] = i
- A[3] = _patharr0_i0(A[3], D, "drive", "", "FILE")
+ } else if (_VAR[_[p]["REGPATH"]] == _REG[_[p]["REGPATH"]]) {
+ _creport(p, substr("OK: REGPATH MATCH(==" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126))
} else {
- D["type"] = "FILE"
- A[1] = _patharr0_i0(A[1], D, "drive")
- return _patharr0_i1(D, A, 1, q)
+ _dllerr(p, substr("REGPATH NOT MATCH(!=" _VAR[_[p]["REGPATH"]] "): " _[p]["REGPATH"], 1, 126))
}
- return _patharr0_i1(D, A, 3, q)
+ } else {
+ _dllerr(p, substr("REGPATH NOT FOUND: " _[p]["REGPATH"], 1, 126))
}
}
+}
- 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 _registryinit()
+{
+ _registrytmpfile = _getmpfile()
+}
- 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
- }
+# _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"]
}
- while (i < q) {
- D[0] = D[0] (D[++c] = A[i++]) "/"
+ if ("ext" in S) {
+ D["ext"] = S["ext"]
}
- 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
- }
+ 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]) "\\"
}
- return 1
- }
-
- 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 _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 = "")
+ if (s != "") {
+ D[0] = s
}
- }
-
- 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 : "")
- }
+ 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 (length(_dumparrd = _dumparrd t ((a > 0 ? " ... (x" a ")" : "")) _CHR["EOL"]) > 262144) {
- _conl(_dumparrd)
- _dumparrd = ""
+ if (tt == "") {
+ continue
}
- 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 = ""
+ 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"
}
}
- }
- }
- 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 "]")
- }
- }
- }
- if (! f) {
- if (length(_dumparrd = _dumparrd t _CHR["EOL"]) > 262144) {
- _conl(_dumparrd)
- _dumparrd = ""
- }
- }
- }
-
- 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 (_isptr(p0)) {
- _qparama0 = "P"
+ DD[gensub(/(\\)\\+/, "\\1", "G", p "\\" _unstr(D[3] (D[5] ? "(Default)" : "")) "." t)] = v
} else {
- _qparama0 = "S"
+ _fatal("regedit: unknown output format(" c "): `" C[c] "'")
}
- 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 _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 _rFBRO(p)
- {
- if (p) {
- if (p in _tPARENT) {
- return _tFCHLD[_tPARENT[p]]
- }
- while (p in _tPREV) {
- p = _tPREV[p]
- }
- return p
- }
- return p
+ if (p in _tFCHLD) {
+ return _rsqgetptr(g, _tFCHLD[p])
}
+ return p
+}
- function _rFCHLD(p)
- {
- if (p && p in _tFCHLD) {
- return _tFCHLD[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 ""
+ return
}
-
- function _rLBRO(p)
- {
- if (p) {
- if (p in _tPARENT) {
- return _tLCHLD[_tPARENT[p]]
- }
- while (p in _tNEXT) {
- p = _tNEXT[p]
+ 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 p
- }
- return p
- }
-
- function _rLCHLD(p)
- {
- if (p && p in _tLCHLD) {
- return _tLCHLD[p]
}
- return ""
}
+ return _rexpfnend(t)
+}
- function _rLINK(p)
- {
- return ((p in _tLINK ? _tLINK[p] : ""))
- }
-
- function _rNEXT(p)
- {
- if (p && p in _tNEXT) {
- return _tNEXT[p]
- }
- return ""
+##############################################################
+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 _rPARENT(p)
- {
- if (p && p in _tPARENT) {
- return _tPARENT[p]
- }
- 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 _rPREV(p)
- {
- if (p && p in _tPREV) {
- return _tPREV[p]
- }
- return ""
- }
+#_______________________________________________________________________
+function _serv_check(p)
+{
+ _tframe("_serv_check_i0", p, 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]
+#_______________________________________________
+function _serv_check_i0(p, p0, p1, p2, p3, i, q, c)
+{
+ if (_[p]["TYPE"] == "defsrv") {
+ i = IGNORECASE
+ IGNORECASE = 1
+ if (match(_servoutput, roi = "\\012DISPLAY_NAME: " _torexp(_[p]["SERVNAME"]))) {
+ _creport(p, "OK: SERVICE DETECTED: " substr(_[p]["SERVNAME"], 1, 112))
+ } else {
+ _dllerr(p, "service " _[p]["SERVNAME"] " not detected")
+ }
+ }
+ IGNORECASE = i
+}
+
+#_______________________________________________________________________
+function _setarrsort(f, a)
+{
+ ##############################################
+ a = PROCINFO["sorted_in"]
+ if (! f) {
+ delete PROCINFO["sorted_in"]
+ } else {
+ PROCINFO["sorted_in"] = f
+ }
+ return a
+}
+
+#_______________________________________________________________________
+function _setmpath(p, a)
+{
+ ################################################
+ ERRNO = ""
+ if ((p) && (a = _filerd(p))) {
+ if (_FILEIO_TMPRD) {
+ _FILEIO_TMPATHS[_FILEIO_TMPRD]
+ }
+ #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 _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 c
- }
- return p
- }
-
- function _rQCHLD(p)
- {
- if (p && p in _tQCHLD) {
- return _tQCHLD[p]
- }
- return ""
- }
-
- function _rSQFIRST(g, p, A)
- {
- if (isarray(A)) {
- return _rSQFIRSTA(g, p, A)
}
- _SQTOPTR[g] = p
- _SQSTACK[g][0] = 0
- return _rsqgetptr(g, p)
- }
-
- function _rSQFIRSTA(g, p, A)
- {
- _SQTOPTR[g] = p
- _SQSTACK[g][0] = 0
- if ((p = _rsqgetptr(g, p)) in A) {
- return p
- }
- return _rSQNEXTA(g, p, A)
+ return q
}
+ return _rmtsharerr(h, c)
+}
- function _rSQNEXT(g, p, A)
- {
- if (isarray(A)) {
- return _rSQNEXTA(g, p, A)
- }
- return _rsqnext_i0(g, p)
+#_____________________________________________________________________________
+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 _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)
- }
+function _shortcut(D, S)
+{
+ #############################################################
+ if (isarray(D)) {
+ if (isarray(S)) {
+ _addarrmask(D, S, _SHORTCUTWSTRUC)
+ } else if (S == 0 && S == "") { # array,array2* - copy from array2 to array shorcut-specific elements
+ _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC)
+ } else if (_isnotfileptr(S)) { # array* - define shortcut-specific elements in array by default values
+ _addarrmask(D, _[S], _SHORTCUTWSTRUC)
+ } else if (_rd_shortcut(D, S)) {
+ return # array,ptr* - copy from array _[ptr] to array shorcut-specific elements
+ }
+ } else if (D == 0 && D == "") {
+ return _NOP # array,filepath* - define in array shortcut-specific elements by reading its from shortcut file filepath(load shortcut)
+ # -* - no action(return -)
+ } else if (_isnotfileptr(D)) {
+ if (isarray(S)) {
+ _addarrmask(_[D], S, _SHORTCUTWSTRUC)
+ } else if (S == 0 && S == "") { # ptr,array* - copy from array to array _[ptr] shorcut-specific elements
+ _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC)
+ } else if (_isnotfileptr(S)) { # ptr* - define shortcut-specifc elements in array _[ptr] by default values
+ _addarrmask(_[D], _[S], _SHORTCUTWSTRUC)
+ } else if (_rd_shortcut(_[D], S)) {
+ return # ptr,ptr2* - copy from array _[ptr2] to array _[ptr] shorcut-specific elements
+ }
+ } else { # ptr,filepath* - define in array _[ptr] shortcut-specific elements by reading its from shortcut file filepath(load shortcut)
+ if (isarray(S) && _wr_shortcut(D, S)) {
+ return # filepath,array* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array(save shortcut)
+ } else if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) {
+ return # filepath* - [over]write shorcut file filepath; shortcut parameters will be defined by default values
+ } else if (_isnotfileptr(S) && _wr_shortcut(D, _[S])) {
+ return # filepath,ptr* - [over]write shorcut file filepath; shortcut parameters will be defined by shortcut-specific elements in array _[ptr](save shortcut)
+ } else if (_rd_shortcut(_SHRTCUTA1, S) || _wr_shortcut(D, _SHRTCUTA1)) {
return
- }
- while (p in _tNEXT) {
- if ((p = _rsqgetptr(g, _tNEXT[p])) in A) {
- return p
+ } } # 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 {
+ _SHORTCUTWSTRUC[_SHORTCUTRSTRUC[B[4]] = B[1]] = B[2]
+ _SHORTCUTDEFAULT[B[1]] = B[6]
}
+ } else {
+ _fatal("_shortcut.init: _shortcut_struc: syntax error: `" _SHRTCUTA0[q] "'")
}
- return ((p in _tPARENT ? _rSQNEXTA(g, _tPARENT[p], A) : ""))
- }
-
- function _rconl(t)
- {
- _rprt = _rprt _ln(t)
}
+ _SHRTCUTA1[""]
+ delete _SHRTCUTA1[""]
+ _shortcut_fpath = "\\\\localhost\\eGAWK\\LIB\\_shortcut\\_shortcut.exe"
+}
- function _rconline(t)
- {
- _rprt = _rprt _ln((t = " " t " ") _getchrln("_", _CON_WIDTH - length(t) - 1))
+#_____________________________________________________
+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 _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)
- }
- }
+}
+
+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(t) > 0) {
+ _movarr(A, t)
+ return (0 - length(A))
}
}
- return ((ERRNO ? ERRNO = "read shortcut: " ERRNO : _NOP))
+ _istr(r)
}
-
- function _rdfile(f, i, A)
- {
- if ((f = _filerdne(f)) == "" || _filene(f) == "") {
- ERRNO = "Filename error"
- return
+ if (it == "A") {
+ if (length(r) > 0) {
+ _movarr(A, r)
+ return (0 - length(A))
}
- _fio_cmda = RS
- RS = ".{1,}"
- _fio_cmdb = BINMODE
- BINMODE = "rw"
- ERRNO = RT = _NUL
- getline RS < f
- BINMODE = _fio_cmdb
- RS = _fio_cmda
- if (ERRNO == "") {
- close(f)
- }
- if (ERRNO == "") {
- return RT
- }
- return (RT = _NOP)
}
+}
- function _rdreg(D, p)
- {
- _rdregp0 = "reg query \"" p "\" /S /reg:64 2>NUL"
- _rdregfld = _rdregkey = 0
- _rdregq0 = split(gensub(/[\x0D?\x0A]{2,}/, _CHR["EOL"], "G", _cmd(_rdregp0)), _RDREGA0, /\x0D?\x0A/)
- while (_rdregq0 > 0) {
- _rdreg_i0(D)
- }
- return (_rdregfld + _rdregkey)
+#_____________________________________________________
+function _splitstr_i0(A, t, C)
+{
+ if (2 > (_splitstrq0 = patsplit(t, _SPLITSTRA0, /([^,\xB4]*\xB4.)*[^,\xB4]*/))) {
+ _splitstrq0 = split(gensub(/\xB4(.)/, "\\1", "G", t), _SPLITSTRA0, "")
}
-
- 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 {
- break
- }
- } else if (_rdregp0 ~ /^HK/) {
- ++_rdregkey
- return D[_rdregp0 = _rdregp0 "\\"]
- }
+ delete A
+ _splitstri0 = _splitstrp0 = 0
+ while (_splitstri0++ < _splitstrq0) {
+ if ((t = gensub(/\xB4(.)/, "\\1", "G", _SPLITSTRA0[_splitstri0])) in C || t == "") {
+ continue
}
- return 1
+ C[A[++_splitstrp0] = t]
}
+ return _splitstrp0
+}
- function _rdsafe(A, i, d)
- {
- if (i in A) {
- return A[i]
- }
- return d
+#_______________________________________________
+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 _reg_check(p)
- {
- _tframe("_reg_check_i0", p, p)
- }
+function _subseqoff(r, B)
+{
+ patsplit(r, B, /\x84[^\x94]*\x94/)
+ return gensub(/\x84[^\x94]*\x94/, "\204", "G", r)
+}
- 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))
- }
- } else 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))
- }
- }
+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 _registryinit()
- {
- _registrytmpfile = _getmpfile()
- }
+#_____________________________________________________________________________
+# _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 _regpath0(D, i, s, q, S)
- {
- if (i = _patharr0(S, i)) {
- if ("name" in S) {
- D["name"] = S["name"]
- }
- if ("ext" in S) {
- D["ext"] = S["ext"]
- }
- s = ((toupper(s = (i in S ? S[i] : "")) in _REGPATH0REGDIR ? D[++q] = _REGPATH0REGDIR[toupper(s)] : (D[++q] = _REGPATH0REGDIR[""]) "\\" (D[++q] = s))) "\\"
- while (++i in S) {
- s = s (D[++q] = S[i]) "\\"
- }
- if (s != "") {
- D[0] = s
- }
- IGNORECASE = 1
- D["hostdir"] = "\\\\" (D["host"] = ("host" in S && ("" == (i = S["host"]) || "." == i || "?" == i || "localhost" == i) ? ENVIRON["COMPUTERNAME"] : i)) "\\" s
- IGNORECASE = 0
- }
- }
- function _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)
- }
+# HKCR HKEY_CLASSES_ROOT
+# HKCU HKEY_CURRENT_USER
+# HKLM HKEY_LOCAL_MACHINE
+# HKU HKEY_USERS
+# HKCC HKEY_CURRENT_CONFIG
+# HKPD HKEY_PERFORMANCE_DATA
- 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
- }
- 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(_ln("DEST:") _dumparr(D))
- _conl()
- return q
- }
- function _rrdreg(DD, p, k, t, v, c, i, q, tT, A, B, C, D)
- {
- if (! _registrytmpfile) {
- _registryinit()
- }
- _cmd("regedit /E \"" _registrytmpfile "\" \"" p "\" 2>&1")
- q = patsplit(gensub(/[\x00\xFF\xFE]+/, "", "G", _rdfile(_registrytmpfile)), A, /\x0D?\x0A\[[^\]]+\]\x0D?\x0A/, B)
- for (i = 1; i <= q; i++) {
- p = gensub(/(^[ \t\x0D\x0A]*\[)|((\\)\\+)|(\][ \t\x0D\x0A]*$)/, "\\3", "G", A[i])
- DD[p "\\"]
- delete C[split(B[i], C, /[\x0D\x0A]+/)]
- for (c = 1; c in C; c++) {
- tt = tt C[c]
- if (gsub(/\\$/, "", tt)) {
- continue
- }
- if (tt == "") {
- continue
- }
- if (match(_th0(tt, tt = ""), /((^"(([^\\"]|\\.)*)")|(@))=(("(([^\\"]|\\.)*)")|(dword:([[:xdigit:]]{8}))|(hex(\(([27b])\))?:(.*)))$/, D)) {
- if (D[7]) {
- t = "STR"
- v = _unstr(D[8])
- } else if (D[10]) {
- t = "W32"
- v = D[11]
- } else {
- v = D[15]
- if (D[13]) {
- switch (D[14]) {
- case "2":
- t = "XSZ"
- break
- case "7":
- t = "MSZ"
- break
- default:
- t = "W64"
- }
- } else {
- t = "BIN"
- }
- }
- DD[gensub(/(\\)\\+/, "\\1", "G", p "\\" _unstr(D[3] ((D[5] ? "(Default)" : ""))) "." t)] = v
- } else {
- _fatal("regedit: unknown output format(" c "): `" C[c] "'")
- }
- }
- }
- }
- function _rsqgetptr(g, p, A)
- {
- if (p in _tLINK) {
- _SQSTACK[g][++_SQSTACK[g][0]] = p
- _SQSTACK[g][++_SQSTACK[g][0]] = _SQTOPTR[g]
- while ((p = _tLINK[p]) in _tLINK) {
- _con(".")
- }
- _SQTOPTR[g] = p
- }
- if (p in _tFCHLD) {
- return _rsqgetptr(g, _tFCHLD[p])
- }
- return p
- }
- function _rsqnext_i0(g, p)
- {
- if (p == _SQTOPTR[g]) {
- if (_SQSTACK[g][0] > 0) {
- _SQTOPTR[g] = _SQSTACK[g][_SQSTACK[g][0]--]
- return _rsqnext_i0(g, _SQSTACK[g][_SQSTACK[g][0]--])
- }
- return
- }
- if (p in _tNEXT) {
- return _rsqgetptr(g, _tNEXT[p])
- }
- return _rsqnext_i0(g, _tPARENT[p])
- }
-
- function _rtn(v, A)
- {
- _conl()
- _conline(_val(v) " : " _val(A))
- _conl()
- _rtn2(v, A)
- _conl()
- }
-
- function _rtn2(v, A, r, t)
- {
- r = (isarray(A) ? _typa(v, A) : _typ(v))
- if ("`" > _t0 && _t0) {
- _conl("ggggg")
- }
- t = ((r ? "TRUE" : "FALSE")) " / " ((r > 0 ? r ">0" : r "!>0")) " / " ((r + 0 > 0 ? r "+0>0" : r "+0!>0")) " / " ((r + 0 != r ? r "+0!=" r : r "+0==" r)) " / " ((r && "`" > r ? "'`'>" r " && " r : "!('`'>" r " && " r ")"))
- _conl("`" r "' : " t)
- return r
- }
- function _rxpfn(R, t, p, i, f, A)
- {
- for (i in R) {
- if (match(t, i, A)) {
- f = R[i]
- if (t != (t = @f(A, substr(t, RLENGTH + 1), p))) {
- return t
- }
- }
- }
- return _rexpfnend(t)
- }
-
- function _sHARE(c, t, P, a, A)
- {
- switch (c) {
- case "_lib_CMDLN":
- return t
- case "_lib_APPLY":
- return
- case "_lib_HELP":
- return
- case "_lib_NAMEVER":
- return _ln("_share 1.000")
- case "_lib_BEGIN":
- return
- case "_lib_END":
- return
- }
- }
- function _sYS(c, t, P, a, A)
- {
- switch (c) {
- case "_lib_CMDLN":
- return t
- case "_lib_APPLY":
- return
- case "_lib_HELP":
- return
- case "_lib_NAMEVER":
- return
- case "_lib_BEGIN":
- return
- case "_lib_END":
- return
- }
- }
- function _serv_check(p)
- {
- _tframe("_serv_check_i0", p, p)
- }
- function _serv_check_i0(p, p0, p1, p2, p3, i, q, c)
- {
- if (_[p]["TYPE"] == "defsrv") {
- i = IGNORECASE
- IGNORECASE = 1
- if (match(_servoutput, roi = "\\012DISPLAY_NAME: " _torexp(_[p]["SERVNAME"]))) {
- _creport(p, "OK: SERVICE DETECTED: " substr(_[p]["SERVNAME"], 1, 112))
- } else {
- _dllerr(p, "service " _[p]["SERVNAME"] " not detected")
- }
- }
- IGNORECASE = i
- }
- function _setarrsort(f, a)
- {
- a = PROCINFO["sorted_in"]
- if (! f) {
- delete PROCINFO["sorted_in"]
- } else {
- PROCINFO["sorted_in"] = f
- }
- return a
- }
- function _setmpath(p, a)
- {
- ERRNO = ""
- if (p && (a = _filerd(p))) {
- if (_FILEIO_TMPRD) {
- _FILEIO_TMPATHS[_FILEIO_TMPRD]
- }
- return (_FILEIO_TMPRD = a)
- } else {
- return _warning("`" p "': cannot set temporary folder" ((ERRNO ? ": " ERRNO : "")))
- }
- }
- function _sharelist(D, h, q, c, l, A, B)
- {
- delete D
- c = _sharextool " \\\\" ((h == "" ? h = ENVIRON["COMPUTERNAME"] : h)) " 2>&1"
- if (match(c = _cmd(c), /\x0AShare[^\x0A]*Remark/)) {
- gsub(/(^[^-]*\x0D?\x0A-+\x0D?\x0A[ \t]*)|(\x0D?\x0AThe command completed successfully.*$)/, "", c)
- l = RLENGTH - 7
- split(c, A, /([ \t]*\x0D?\x0A)+[ \t]*/)
- for (c in A) {
- if (match(A[c], /((([^ \t:]+[ \t]+)*[^ \t:]+)[ \t]+)([A-Za-z])[ \t]*:/, B) && ++q) {
- D[B[2]] = (A[c] ~ /\.\.\.$/ ? _sharepath(h, B[2]) : gensub(/[ \t\\\/]*$/, "\\\\", 1, substr(A[c], 1 + B[1, "length"], l - B[1, "length"])))
- }
- }
- 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 _shortcut(D, S)
- {
- if (isarray(D)) {
- if (isarray(S)) {
- _addarrmask(D, S, _SHORTCUTWSTRUC)
- } else if (S == 0 && S == "") {
- _addarrmask(D, _SHORTCUTDEFAULT, _SHORTCUTWSTRUC)
- } else if (_isnotfileptr(S)) {
- _addarrmask(D, _[S], _SHORTCUTWSTRUC)
- } else if (_rd_shortcut(D, S)) {
- return
- }
- } else if (D == 0 && D == "") {
- return _NOP
- } else if (_isnotfileptr(D)) {
- if (isarray(S)) {
- _addarrmask(_[D], S, _SHORTCUTWSTRUC)
- } else if (S == 0 && S == "") {
- _addarrmask(_[D], _SHORTCUTDEFAULT, _SHORTCUTWSTRUC)
- } else if (_isnotfileptr(S)) {
- _addarrmask(_[D], _[S], _SHORTCUTWSTRUC)
- } else if (_rd_shortcut(_[D], S)) {
- return
- }
- } else if (isarray(S) && _wr_shortcut(D, S)) {
- return
- } else if (S == 0 && S == "" && _wr_shortcut(D, _SHORTCUTDEFAULT)) {
- return
- } else if (_isnotfileptr(S) && _wr_shortcut(D, _[S])) {
- 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]
- } 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]
- }
- } 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
- }
- }
- 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)
- {
- if (_istr(t)) {
- if (_splitstr_i0(A, t) > 0) {
- return _splitstrp0
- }
- if (_istr(r)) {
- return _splitstr_i0(A, r)
- }
- } else {
- if (it == "A") {
- if (length(t) > 0) {
- _movarr(A, t)
- return (0 - length(A))
- }
- }
- _istr(r)
- }
- if (it == "A") {
- if (length(r) > 0) {
- _movarr(A, r)
- return (0 - length(A))
- }
- }
- }
- 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++) {
- s = substr(e = B[i], 2, 1)
- s = (s in F ? F[s] : F[""])
- r = r (@f(A[i])) (@s(substr(e, 3, length(e) - 3)))
- }
- return (r (@f(A[i])))
- }
- function _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 _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]
+#___________________________________________________________________________________
+####################################################################################
+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 ((p in _tLCHLD ? _tmbpassx(f, _tLCHLD[p], p0, p1) : @f(p, p0, p1)))
+ return (_sysinfoq1 - 1)
}
+}
- function _tbrochld(p, f, pp)
- {
- if (p) {
- if (p in _tFCHLD) {
- f = _tFCHLD[p]
- delete _tFCHLD[p]
- delete _tLCHLD[p]
- if (p in _tPARENT) {
- pp = _tPARENT[p]
- delete _tPARENT[p]
- if (p in _tPREV) {
- _tNEXT[_tPREV[f] = _tPREV[p]] = f
- delete _tPREV[p]
- } else {
- _tFCHLD[pp] = f
- }
- for (; f in _tNEXT; f = _tNEXT[f]) {
- _tPARENT[f] = pp
- }
- _tPARENT[f] = pp
- if (p in _tNEXT) {
- _tPREV[_tNEXT[f] = _tNEXT[p]] = f
- delete _tNEXT[p]
- } else {
- _tLCHLD[pp] = f
- }
- _tQCHLD[pp] = _tQCHLD[pp] + _tQCHLD[p] - 1
- delete _tQCHLD[p]
- return f
- } else {
- delete _tQCHLD[p]
- if (p in _tPREV) {
- _tNEXT[_tPREV[f] = _tPREV[p]] = f
- delete _tPREV[p]
- }
- for (; f in _tNEXT; f = _tNEXT[f]) {
- delete _tPARENT[f]
- }
- delete _tPARENT[f]
- if (p in _tNEXT) {
- _tPREV[_tNEXT[f] = _tNEXT[p]] = f
- delete _tNEXT[p]
- }
- return f
- }
- } else if (p in _tPARENT) {
+#########################################################
+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) {
- if (p in _tNEXT) {
- _tNEXT[_tPREV[f] = _tPREV[p]] = f = _tNEXT[p]
- delete _tNEXT[p]
- } else {
- delete _tNEXT[_tLCHLD[pp] = _tPREV[p]]
- }
+ _tNEXT[_tPREV[f] = _tPREV[p]] = f
delete _tPREV[p]
- _tQCHLD[pp]--
- } else if (p in _tNEXT) {
- delete _tPREV[_tFCHLD[pp] = _tNEXT[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]
- _tQCHLD[pp]--
} else {
- delete _tFCHLD[pp]
- delete _tLCHLD[pp]
- delete _tQCHLD[pp]
+ _tLCHLD[pp] = f
}
- } else if (p in _tPREV) {
+ _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[_tPREV[p]]
+ delete _tNEXT[_tLCHLD[pp] = _tPREV[p]]
}
delete _tPREV[p]
+ _tQCHLD[pp]--
} else if (p in _tNEXT) {
- delete _tPREV[_tNEXT[p]]
+ delete _tPREV[_tFCHLD[pp] = _tNEXT[p]]
delete _tNEXT[p]
+ _tQCHLD[pp]--
+ } else {
+ delete _tFCHLD[pp]
+ delete _tLCHLD[pp]
+ delete _tQCHLD[pp]
}
- }
- 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)
+ } 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 _[p]
- _UIDSDEL[p]
+ delete _tPREV[p]
+ } else if (p in _tNEXT) {
+ delete _tPREV[_tNEXT[p]]
+ delete _tNEXT[p]
}
}
-
- function _tdel_i0(p, i)
- {
+ 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]) {
+ } 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)
+ 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 _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)
}
}
-
- function _tdelete(p, v)
- {
- if (p) {
- _wLCHLD(_tDELPTR, p)
- }
- return v
- }
-
- function _tdelitem(p)
- {
- if (p) {
- if ("HOST" in _PTR[p] && "ITEMNAME" in _[p]) {
- return _wLCHLD(_PTR[_PTR[p]["HOST"]]["ITEM"][_[p]["ITEMNAME"]], p)
- }
- _tdelete(p)
- return p
- }
+ 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 _tend(a, b)
+{
+ #####################################################
+ if (b == "") {
+ return (_t_ENDF[_t_ENDF[0]] = a)
+ } else {
+ return (_t_ENDF[_t_ENDF[0] + a] = b)
}
+}
- function _texclude(p, v, pp)
- {
- 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
- }
- --_tQCHLD[pp]
- } else if (p in _tPREV) {
+#_____________________________________________________________________________
+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[_tPREV[p]]
+ delete _tNEXT[_tLCHLD[pp] = _tPREV[p]]
}
delete _tPREV[p]
} else if (p in _tNEXT) {
- delete _tPREV[_tNEXT[p]]
+ delete _tPREV[_tFCHLD[pp] = _tNEXT[p]]
delete _tNEXT[p]
+ } else {
+ delete _tFCHLD[pp]
+ delete _tLCHLD[pp]
+ delete _tQCHLD[pp]
+ return p
}
- return p
- }
- }
-
- function _tframe(fF, p, p0, p1, p2)
- {
- delete _t_ENDF[++_t_ENDF[0]]
- p = (_isptr(p) ? (isarray(fF) ? _tframe_i1(fF, p, p0, p1, p2) : _tframe_i0(fF, p, p0, p1, p2)) : "")
- --_t_ENDF[0]
- return p
- }
-
- function _tframe0(f, p, p0, p1, p2, p3, A)
- {
- if (_isptr(p)) {
- if (isarray(f)) {
- return _tframe0_i0(f, p)
+ --_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]]
}
- _tframex_p0(A, f, 0)
- return _th0(_tframe0_i0(A, p), --_TEND[_ARRLEN])
+ delete _tPREV[p]
+ } else if (p in _tNEXT) {
+ delete _tPREV[_tNEXT[p]]
+ delete _tNEXT[p]
}
+ return p
}
-
- 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])
- }
- } else {
- while (p in _tLINK) {
- p = _tLINK[p]
- }
+}
+
+# _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
+ if ("`" in A) {
+ f = A["`"]
+ while (p in _tLINK) {
+ @f(p = _tLINK[p])
}
} else {
- _tframe_link = ""
- }
- if (p in _tFCHLD) {
- return (_tframe0_i2(A, "^", p) _tframe0_i1(A, _tFCHLD[p]))
- }
- return _tframe0_i2(A, ".", 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]))
- }
- 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
- }
+ while (p in _tLINK) {
+ p = _tLINK[p]
}
- m = A[m]
- return @m(p)
}
+ } else {
+ _tframe_link = ""
}
-
- 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])
- }
+ if (p in _tFCHLD) {
+ return (_tframe0_i2(A, "^", p) _tframe0_i1(A, _tFCHLD[p]))
}
+ return _tframe0_i2(A, ".", p)
+}
- function _tframe1_i0(A, p, p0)
- {
- _tframe_link = p
- while (p in _tLINK) {
- p = _tLINK[p]
- }
- if (p in _tFCHLD) {
- return (_tframe1_i2(A, "^", p, p0) _tframe1_i1(A, _tFCHLD[p], p0))
- }
- return _tframe1_i2(A, ".", p, p0)
+#_______________________________________________
+function _tframe0_i1(A, p)
+{
+ if (_TEND[_ARRLEN] in _TEND) {
+ return
}
-
- 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)
+ if (p in _tNEXT) {
+ return (_tframe0_i0(A, p) _tframe0_i1(A, _tNEXT[p]))
}
+ return _tframe0_i0(A, p)
+}
- 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
- }
- }
- m = A[m]
- return @m(p, p0)
- }
+#_______________________________________________
+function _tframe0_i2(A, m, p)
+{
+ _tframe_dlink = p
+ while (p in _tDLINK) {
+ p = _tDLINK[p]
}
-
- function _tframe2(f, p, p0, p1, p2, p3, A)
- {
- if (_isptr(p)) {
- if (isarray(f)) {
- return _tframe2_i0(f, p, p0, p1)
+ if (m in A) {
+ if ((m "~") in A) {
+ if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) {
+ return
}
- _tframex_p0(A, f, 2)
- return _th0(_tframe2_i0(A, p, p0, p1), --_TEND[_ARRLEN])
}
+ m = A[m]
+ return @m(p)
}
+}
- function _tframe2_i0(A, p, p0, p1)
- {
- _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))
+#_________________________________________________________________
+function _tframe1(f, p, p0, p1, p2, p3, A)
+{
+ #############################
+ if (_isptr(p)) {
+ if (isarray(f)) {
+ return _tframe1_i0(f, p, p0)
}
- return _tframe2_i2(A, ".", p, p0, p1)
+ _tframex_p0(A, f, 1)
+ return _th0(_tframe1_i0(A, p, p0), --_TEND[_ARRLEN])
}
+}
- 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)
+#_______________________________________________
+function _tframe1_i0(A, p, p0)
+{
+ _tframe_link = p
+ while (p in _tLINK) {
+ p = _tLINK[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)
- }
+ if (p in _tFCHLD) {
+ return (_tframe1_i2(A, "^", p, p0) _tframe1_i1(A, _tFCHLD[p], p0))
}
+ return _tframe1_i2(A, ".", p, p0)
+}
- 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 _tframe1_i1(A, p, p0)
+{
+ if (_TEND[_ARRLEN] in _TEND) {
+ return
}
-
- function _tframe3_i0(A, p, p0, p1, p2)
- {
- _tframe_link = p
- while (p in _tLINK) {
- p = _tLINK[p]
- }
- if (p in _tFCHLD) {
- return (_tframe3_i2(A, "^", p, p0, p1, p2) _tframe3_i1(A, _tFCHLD[p], p0, p1, p2))
- }
- return _tframe3_i2(A, ".", p, p0, p1, p2)
+ if (p in _tNEXT) {
+ return (_tframe1_i0(A, p, p0) _tframe1_i1(A, _tNEXT[p], p0))
}
+ return _tframe1_i0(A, p, p0)
+}
- 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_i2(A, m, p, p0)
+{
+ _tframe_dlink = p
+ while (p in _tDLINK) {
+ p = _tDLINK[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
- }
+ 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)
}
+ m = A[m]
+ return @m(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 _tframe2(f, p, p0, p1, p2, p3, A)
+{
+ #############################
+ if (_isptr(p)) {
+ if (isarray(f)) {
+ return _tframe2_i0(f, p, p0, p1)
}
+ _tframex_p0(A, f, 2)
+ return _th0(_tframe2_i0(A, p, p0, p1), --_TEND[_ARRLEN])
}
+}
- 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 _tframe2_i0(A, p, p0, p1)
+{
+ _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))
+ }
+ return _tframe2_i2(A, ".", p, p0, p1)
+}
- 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 _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)
+}
- 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
- }
+#_______________________________________________
+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, p2, p3)
}
+ m = A[m]
+ return @m(p, p0, p1)
}
+}
- function _tframe_i0(f, p, p0, p1, p2, a)
- {
- while (p in _tLINK) {
- p = _tLINK[p]
+#_________________________________________________________________
+function _tframe3(f, p, p0, p1, p2, p3, A)
+{
+ #############################
+ if (_isptr(p)) {
+ if (isarray(f)) {
+ return _tframe3_i0(f, p, p0, p1, p2)
}
- 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))))
+ _tframex_p0(A, f, 3)
+ return _th0(_tframe3_i0(A, p, p0, p1, p2), --_TEND[_ARRLEN])
}
+}
- 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 _tframe3_i0(A, p, p0, p1, p2)
+{
+ _tframe_link = p
+ while (p in _tLINK) {
+ p = _tLINK[p]
}
-
- 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
+ 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 _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
+#_______________________________________________
+function _tframe3_i1(A, p, p0, p1, p2)
+{
+ 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 (_tframe3_i0(A, p, p0, p1, p2) _tframe3_i1(A, _tNEXT[p], p0, p1, p2))
}
+ return _tframe3_i0(A, p, p0, p1, p2)
+}
- 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 _tframe3_i2(A, m, p, p0, p1, p2)
+{
+ _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, p2)
}
+}
- 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 _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 _tgetsp(p)
- {
- return _tSTACK[p][0]
+#_______________________________________________
+function _tframe4_i0(A, p, p0, p1, p2, p3)
+{
+ _tframe_link = p
+ while (p in _tLINK) {
+ p = _tLINK[p]
}
-
- function _th0(p, p1, p2, p3)
- {
- return p
- }
-
- function _th1(p0, p, p2, p3)
- {
- return p
+ 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 _th10(p0, p1)
- {
- return (p1 p0)
- }
-
- function _th2(p0, p1, r, p3)
- {
- return p
+#_______________________________________________
+function _tframe4_i1(A, p, p0, p1, p2, p3)
+{
+ if (_TEND[_ARRLEN] in _TEND) {
+ return
}
-
- function _th3(p0, p1, p2, r)
- {
- return p
+ 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 _tifend(l)
- {
- return ((_t_ENDF[0] + l in _t_ENDF ? (_t_ENDF[_t_ENDF[0] + l] ? _t_ENDF[_t_ENDF[0] + l] : 1) : ""))
+#_______________________________________________
+function _tframe4_i2(A, m, p, p0, p1, p2, p3)
+{
+ _tframe_dlink = p
+ while (p in _tDLINK) {
+ p = _tDLINK[p]
}
-
- function _tinit_i0(D, S, i)
- {
- for (i in S) {
- if (isarray(S[i])) {
- if (! isarray(D[i][""])) {
- delete D[i]
- D[i][""]
- delete D[i][""]
- }
- _N_i0(D[i], S[i])
- } else {
- if (isarray(D[i])) {
- delete D[i]
- }
- D[i] = S[i]
+ if (m in A) {
+ if ((m "~") in A) {
+ if (! (_TYPEWORD in _[p]) || A[m "~"] !~ _[p][_TYPEWORD]) {
+ return
}
}
- }
-
- function _tlist(L, p, f)
- {
- _tlisti1 = _tlisti0 = L[_ARRLEN] + 0
- if (f == 0 && f == "") {
- _tlist_i0(L, 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 {
- _tlistf0 = (f in _TAPI ? _TAPI[f] : f)
- _tlist_i1(L, p)
- }
- return (_tlisti0 - _tlisti1)
- }
-
- 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 _tlist_i1(L, p)
- {
- if (isarray(p)) {
- q = p[_ARRLEN]
- i = 0
- while (i++ < q) {
- _tlist_i1(L, p[i])
- }
- return
- }
- if (p in _) {
- while (p in _tLINK) {
- p = _tLINK[p]
- }
- if (_tlistf0 in _[p]) {
- L[++_tlisti0] = p
+ a = _PTR[p]["ITEM"][n] = _N()
+ }
+ if (! (b = _rFCHLD(a))) {
+ b = _wLCHLD(a, _N())
+ _PTR[b]["HOST"] = p
+ _[b]["ITEMNAME"] = n
+ }
+ return b
+ }
+}
+
+#_________________________________________________________________
+function _tgetsp(p)
+{
+ ###############################################
+ return _tSTACK[p][0]
+}
+
+####################################################################################
+
+#_____________________________________________________________________________
+function _th0(p, p1, p2, p3)
+{
+ return p
+}
+
+##########################################
+function _th1(p0, p, p2, p3)
+{
+ #_________________________________________________________________
+ return p
+}
+
+##############################
+function _th10(p0, p1)
+{
+ #_________________________________________________________________
+ return (p1 p0)
+}
+
+##############################
+function _th2(p0, p1, r, p3)
+{
+ #_________________________________________________________________
+ return p
+}
+
+##############################
+function _th3(p0, p1, p2, r)
+{
+ #_________________________________________________________________
+ return p
+}
+
+#_________________________________________________________________
+function _tifend(l)
+{
+ ###############################################
+ return (_t_ENDF[0] + l) in _t_ENDF ? (_t_ENDF[_t_ENDF[0] + l] ? _t_ENDF[_t_ENDF[0] + l] : 1) : ""
+}
+
+# test _tbrochld fn; develope tOBJ r\w func specification for brochld func
+
+#_________________________________________________________________
+function _tinit_i0(D, S, i)
+{
+ for (i in S) {
+ if (isarray(S[i])) {
+ if (! isarray(D[i][""])) {
+ delete D[i]
+ D[i][""]
+ delete D[i][""]
}
- if (p in _tFCHLD) {
- for (p = _tFCHLD[p]; p; p = (p in _tNEXT ? _tNEXT[p] : "")) {
- _tlist_i1(L, p)
- }
+ _N_i0(D[i], S[i])
+ } else {
+ if (isarray(D[i])) {
+ delete D[i]
}
+ D[i] = S[i]
}
}
+}
- function _tmbframe(f, p, p0, p1, t)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- t = t _tbframe_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : ""))
- }
- return t
- }
-
- function _tmbframex(f, p, p0, p1, t)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- t = t _tbframex_i0(f, p, p0, p1)
- p = (p in _tPREV ? _tPREV[p] : "")
- }
- return t
- }
-
- function _tmbpass(f, p, p0, p1)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tPREV ? _tPREV[p] : ""))
- }
- return p0
- }
-
- function _tmbpassx(f, p, p0, p1)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- p0 = _tbpassx_i0(f, p, p0, p1)
- p = (p in _tPREV ? _tPREV[p] : "")
- }
- return p0
- }
-
- function _tmframe(f, p, p0, p1, p2)
- {
- delete _t_ENDF[++_t_ENDF[0]]
- f = (p ? _tmframe_i0(f, p, p0, p1, p2) : "")
- --_t_ENDF[0]
- return f
- }
-
- function _tmframe_i0(f, p, p0, p1, p2, t)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- t = t _tframe_i0(f, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : ""))
- }
- return t
- }
-
- function _tmframe_i1(F, p, p0, p1, p2, t)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- t = t _tframe_i1(F, p, p0, p1, p2, p = (p in _tNEXT ? _tNEXT[p] : ""))
- }
- return t
- }
-
- function _tmframex(f, p, p0, p1, t)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- t = t _tframex_i0(f, p, p0, p1)
- p = (p in _tNEXT ? _tNEXT[p] : "")
- }
- return t
- }
-
- function _tmpass(f, p, p0, p1)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- p0 = _tbpass_i0(f, p, p0, p1, p = (p in _tNEXT ? _tNEXT[p] : ""))
- }
- return p0
- }
-
- function _tmpassx(f, p, p0, p1)
- {
- while (p && ! (_t_ENDF[0] in _t_ENDF)) {
- p0 = _tbpassx_i0(f, p, p0, p1)
- p = (p in _tNEXT ? _tNEXT[p] : "")
- }
- return p0
- }
-
- function _torexp(r)
- {
- return _subseqon(_TOREXPB0, gensub(/(^[ \t]+)|(([ \t]*(\\)+)+[ \t]*)|([ \t]+$)/, "\\4", "G", _subseqoff(r, _TOREXPB0)), _TOREXPFN)
- }
-
- function _torexp_cmdstr(t)
- {
- return _strtorexp(gensub(/\^(.)/, "\\1", "G", t))
- }
+#_______________________________________________________________________
+########################################################################
- function _torexp_fmask(t)
- {
- return gensub(/\\\*/, ".*", "G", gensub(/\\\?/, ".?", "G", _strtorexp(t)))
- }
- function _torexp_init()
- {
- _TOREXPFN[""] = "_strtorexp"
- _TOREXPFN["~"] = "_torexp_rexp"
- _TOREXPFN["="] = "_strtorexp"
- _TOREXPFN[">"] = "_torexp_cmdstr"
- _TOREXPFN["#"] = "_torexp_fmask"
- _TOREXPFN["\""] = "_torexp_dqstr"
- _TOREXPFN["'"] = "_torexp_sqstr"
- }
- function _torexp_rexp(t)
- {
- return t
- }
- function _tpass(f, p, p0, p1)
- {
- delete _t_ENDF[++_t_ENDF[0]]
- f = (p ? _tpass_i0(f, p, p0, p1) : "")
- --_t_ENDF[0]
- return f
- }
- function _tpass_i0(f, p, p0, p1, a)
- {
- while (p in _tLINK) {
- p = _tLINK[p]
- }
- return ((p in _tFCHLD ? _tmpass(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1)))
- }
- function _tpassx(f, p, p0, p1)
- {
- delete _t_ENDF[++_t_ENDF[0]]
- f = (p ? _tpassx_i0(f, p, p0, p1) : "")
- --_t_ENDF[0]
- return f
- }
- function _tpassx_i0(f, p, p0, p1)
- {
- while (p in _tLINK) {
- p = _tLINK[p]
- }
- return ((p in _tFCHLD ? _tmpassx(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1)))
- }
- function _tpop(p, aA, a)
- {
- if ((a = _tSTACK[p][0]) > 0) {
- _tSTACK[p][0]--
- if (isarray(_tSTACK[p][a])) {
- delete aA
- _movarr(aA, _tSTACK[p][a])
- return
- }
- return _tSTACK[p][a]
- }
- _fatal("^" p ": Out of tSTACK")
- }
- function _tpush(p, aA, a)
- {
- if (isarray(aA)) {
- delete _tSTACK[p][a = ++_tSTACK[p][0]]
- _tSTACK[p][a][""]
- delete _tSTACK[p][a][""]
- _movarr(_tSTACK[p][a], aA)
- return
- }
- delete _tSTACK[p][a = ++_tSTACK[p][0]]
- return (_tSTACK[p][a] = aA)
- }
-
- function _tr(n, cs, H)
- {
- _rconline(n ": " cs)
- _rconl()
- if (match(cs, /^((([^\xB4:\[\|\]]*\xB4.)*[^\xB4:\[\|\]]*):)?((([^\xB4\[\|\]]*\xB4.)*[^\xB4\[\|\]]*)\[)?(([^\xB4\|\]]*\xB4.)*[^\xB4\|\]]*)?(\|(\.)?(([^\xB4\]]*\xB4.)*[^\xB4\]]*))?(\](.*))?$/, H)) {
- _rconl("delptr: " _une(H[2]) "'")
- _rconl("pfxstr: " _une(H[5]) "'")
- _rconl("hichr: " _une(H[7]) "'")
- _rconl("lochr: " _une((H[10] ? H[7] "' and " H[11] "'" : H[11] "'")))
- _rconl("sfxstr: " _une(H[14]) "'")
- } else {
- _rconl("NOT MATCH!")
- }
- _rconl()
- }
- function _trace(t, d, A)
- {
- if (_ERRLOG_TF) {
- A["TYPE"] = "TRACE"
- A["TEXT"] = t
- _log(A, d)
- }
- }
- function _trunframe(f, p, p0, p1, p2)
- {
- return _tframe((f ? f : "_trunframe_i0"), p, p0, p1, p2)
- }
- 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()
- {
- _ini("uidel:pfx'hstr|lstr'sfx")
- _ini("uidel:pfx'hstr|lstr'")
- _ini("uidel:'hstr|lstr'sfx")
- _ini("uidel:'hstr|lstr'")
- _ini("uidel:pfx'hstr'sfx")
- _ini("uidel:pfx'hstr'")
- _ini("uidel:'hstr'sfx")
- _ini("uidel:'hstr'")
- _conl()
- _conl("########################################################################################")
- _conl()
- _ini("pfx'hstr|lstr'sfx")
- _ini("pfx'hstr|lstr'")
- _ini("'hstr|lstr'sfx")
- _ini("'hstr|lstr'")
- _ini("pfx'hstr'sfx")
- _ini("pfx'hstr'")
- _ini("'hstr'sfx")
- _ini("'hstr'")
- _conl()
- _conl("########################################################################################")
- _conl()
- _ini("uidel:pfx'`cntptr'sfx")
- _ini("uidel:pfx'`cntptr'")
- _ini("uidel:'`cntptr'sfx")
- _ini("uidel:'`cntptr'")
- _conl()
- _conl("########################################################################################")
- _conl()
- _ini("pfx'`cntptr'sfx")
- _ini("pfx'`cntptr'")
- _ini("'`cntptr'sfx")
- _ini("'`cntptr'")
- _conl()
- _conl("########################################################################################")
- _conl()
- _ini("uidel:pfx'^chrptr'sfx")
- _ini("uidel:pfx'^chrptr'")
- _ini("uidel:'^chrptr'sfx")
- _ini("uidel:'^chrptr'")
- _conl()
- _conl("########################################################################################")
- _conl()
- _ini("pfx'^chrptr'sfx")
- _ini("pfx'^chrptr'")
- _ini("'^chrptr'sfx")
- _ini("'^chrptr'")
- _conl()
- _conl("########################################################################################")
- _conl()
- }
- function _tstv(p, A, r, f)
- {
- if (f == "") {
- f = "tst_splitstr"
- }
- @f(_NOP, A, p)
- @f(AA0, A, p)
- @f(AB0, A, p)
- @f(AC0, A, p)
- @f("", A, p)
- @f("a", A, p)
- @f("\264a", A, p)
- @f("\264", A, p)
- @f("a\264\264\264,ba\264\264\264,", A, p)
- @f("\264,", A, p)
- @f(",", A, p)
- @f("\264a,", A, p)
- @f("ab,", A, p)
- @f("ab,\264", A, p)
- @f("\264a\264,,ba", A, p)
- @f(",a,,b\264,c,,\264a,,\264,,,", A, p)
- }
- function _typ(p)
- {
- return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in _CLASSPTR ? "`" : (p ? 3 : 4))) : (p in _CLASSPTR ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2))))))
- }
- function _typa(p, A)
- {
- return (_t0 = (isarray(p) ? "#" : (p == 0 ? (p == "" ? 0 : (p in A ? "`" : (p ? 3 : 4))) : (p in A ? "`" : (p + 0 == p ? 5 : (p ? 3 : 2))))))
- }
- function _tzend(a, b)
- {
- if (b == 0 && b == "") {
- return (_TEND[_TEND[_ARRLEN]] = a)
- } else {
- return (_TEND[_TEND[_ARRLEN] + a] = b)
- }
- }
- function _uidcyc(p, i)
- {
- _dumpuidgen(p)
- for (i = 1; i < 64 * 8 * 6 - 1; i++) {
- _conl(i ":" _var(_getuid(p)))
- }
- _dumpuidgen(p)
- }
+#_______________________________________________________________________
+# _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 _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]
- }
+#_________________________________________________________________
+#
+# 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 _tlist(L, p, f)
+{
+ _tlisti1 = _tlisti0 = L[_ARRLEN] + 0
+ if (f == 0 && f == "") {
+ _tlist_i0(L, p)
+ } else {
+ _tlistf0 = f in _TAPI ? _TAPI[f] : f
+ _tlist_i1(L, p)
}
+ return (_tlisti0 - _tlisti1)
+}
- function _unformatstr(t)
- {
- _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB)
- _formatstrs0 = ""
- for (t = 1; t < _formatstrq0; t++) {
- _formatstrs0 = _formatstrs0 _FORMATSTRA[t] ((_FORMATSTRB[t] in _QESCHR ? _QESCHR[_FORMATSTRB[t]] : _QESCHR[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))]))
+function _tlist_i0(L, p, q, i)
+{
+ if (isarray(p)) {
+ q = p[_ARRLEN]
+ i = 0
+ while (i++ < q) {
+ _tlist_i0(L, p[i])
}
- return (_formatstrs0 _FORMATSTRA[t])
+ return
}
-
- function _unformatstr_init(i)
- {
- for (i = 0; i < 256; i++) {
- _QESCHR["\\" _CHR[i]] = _CHR[i]
- }
- for (i = 0; i < 256; i++) {
- _QESCHR[sprintf("%.2X", i)] = _CHR[i]
- _QESCHR["\\" sprintf("%.3o", i)] = _CHR[i]
- if (i < 8) {
- _QESCHR["\\" sprintf("%.1o", i)] = _CHR[i]
- }
- if (i < 64) {
- _QESCHR["\\" sprintf("%.2o", i)] = _CHR[i]
- }
- if (i < 16) {
- _QESCHR["\\x" sprintf("%.1X", i)] = _QESCHR["\\x" sprintf("%.1x", i)] = _CHR[i]
- }
- }
- i = "a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11
- patsplit(i, _FORMATSTRA, /[^0-9]/, _FORMATSTRB)
- for (i in _FORMATSTRA) {
- _QESCHR["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0]
+ if (p in _) {
+ while (p in _tLINK) {
+ p = _tLINK[p]
}
- }
-
- function _uninit_del(A, i, p0)
- {
- _del(i)
- }
-
- function _unstr(t)
- {
- return gensub(/\\(.)/, "\\1", "G", t)
- }
-
- function _untmp(f, a)
- {
- if (f = filepath(f)) {
- if (match(f, /\\$/)) {
- _deletepfx(_FILEIO_RDTMP, a = toupper(f))
- _deletepfx(_FILEIO_RDNETMP, a)
- } else {
- delete _FILEIO_RDNETMP[toupper(f)]
+ L[++_tlisti0] = p
+ if (p in _tFCHLD) {
+ for (p = _tFCHLD[p]; p; p = p in _tNEXT ? _tNEXT[p] : "") {
+ _tlist_i0(L, p)
}
- return f
}
- return ""
}
+}
- function _val(v, t)
- {
- if (isarray(v)) {
- return (_dumparr(v) _ln(t))
- }
- if (v == 0 && v == "") {
- return (_ln("- (ERRNO=" ERRNO ")") _ln(t))
+function _tlist_i1(L, p)
+{
+ if (isarray(p)) {
+ q = p[_ARRLEN]
+ i = 0
+ while (i++ < q) {
+ _tlist_i1(L, p[i])
}
- return (_ln(v "'") _ln(t))
+ return
}
-
- function _val0(v)
- {
- if (isarray(v)) {
- return _dumparr(v)
- }
- if (v == 0 && v == "") {
- return "-"
+ if (p in _) {
+ while (p in _tLINK) {
+ p = _tLINK[p]
}
- return ("\"" v "\"")
- }
-
- function _var(v, t)
- {
- if (isarray(v)) {
- return (_dumparr(v) _ln(t))
+ if (_tlistf0 in _[p]) {
+ L[++_tlisti0] = p
}
- if (v == 0 && v == "") {
- return (_ln("- (ERRNO=" ERRNO ")") _ln(t))
+ if (p in _tFCHLD) {
+ for (p = _tFCHLD[p]; p; p = p in _tNEXT ? _tNEXT[p] : "") {
+ _tlist_i1(L, p)
+ }
+ }
+ }
+}
+
+#_________________________________________________________________
+function _tmbframe(f, p, p0, p1, t)
+{
+ ##################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ t = t _tbframe_i0(f, p, p0, p1, p = p in _tPREV ? _tPREV[p] : "")
+ }
+ return t
+}
+
+#_________________________________________________________________
+function _tmbframex(f, p, p0, p1, t)
+{
+ #################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ t = t _tbframex_i0(f, p, p0, p1)
+ p = p in _tPREV ? _tPREV[p] : ""
+ }
+ return t
+}
+
+#_________________________________________________________________
+function _tmbpass(f, p, p0, p1)
+{
+ ######################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ p0 = _tbpass_i0(f, p, p0, p1, p = p in _tPREV ? _tPREV[p] : "")
+ }
+ return p0
+}
+
+#_________________________________________________________________
+function _tmbpassx(f, p, p0, p1)
+{
+ #####################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ p0 = _tbpassx_i0(f, p, p0, p1)
+ p = p in _tPREV ? _tPREV[p] : ""
+ }
+ return p0
+}
+
+#_________________________________________________________________
+function _tmframe(f, p, p0, p1, p2)
+{
+ ###################################
+ delete _t_ENDF[++_t_ENDF[0]]
+ f = p ? _tmframe_i0(f, p, p0, p1, p2) : ""
+ --_t_ENDF[0]
+ return f
+}
+
+#___________________________________________________________
+function _tmframe_i0(f, p, p0, p1, p2, t)
+{
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ t = t _tframe_i0(f, p, p0, p1, p2, p = p in _tNEXT ? _tNEXT[p] : "")
+ }
+ return t
+}
+
+#___________________________________________________________
+function _tmframe_i1(F, p, p0, p1, p2, t)
+{
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ t = t _tframe_i1(F, p, p0, p1, p2, p = p in _tNEXT ? _tNEXT[p] : "")
+ }
+ return t
+}
+
+#_________________________________________________________________
+function _tmframex(f, p, p0, p1, t)
+{
+ ##################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ t = t _tframex_i0(f, p, p0, p1)
+ p = p in _tNEXT ? _tNEXT[p] : ""
+ }
+ return t
+}
+
+#_________________________________________________________________
+function _tmpass(f, p, p0, p1)
+{
+ #######################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ p0 = _tbpass_i0(f, p, p0, p1, p = p in _tNEXT ? _tNEXT[p] : "")
+ }
+ return p0
+}
+
+#_________________________________________________________________
+function _tmpassx(f, p, p0, p1)
+{
+ ######################################
+ while ((p) && (! (_t_ENDF[0] in _t_ENDF))) {
+ p0 = _tbpassx_i0(f, p, p0, p1)
+ p = p in _tNEXT ? _tNEXT[p] : ""
+ }
+ return p0
+}
+
+function _torexp(r)
+{
+ return _subseqon(_TOREXPB0, gensub(/(^[ \t]+)|(([ \t]*(\\)+)+[ \t]*)|([ \t]+$)/, "\\4", "G", _subseqoff(r, _TOREXPB0)), _TOREXPFN)
+}
+
+function _torexp_cmdstr(t)
+{
+ return _strtorexp(gensub(/\^(.)/, "\\1", "G", t))
+}
+
+function _torexp_fmask(t)
+{
+ return gensub(/\\\*/, ".*", "G", gensub(/\\\?/, ".?", "G", _strtorexp(t)))
+}
+
+#_______________________________________________
+function _torexp_init()
+{
+ _TOREXPFN[""] = "_strtorexp"
+ _TOREXPFN["~"] = "_torexp_rexp"
+ _TOREXPFN["="] = "_strtorexp"
+ _TOREXPFN[">"] = "_torexp_cmdstr"
+ _TOREXPFN["#"] = "_torexp_fmask"
+ _TOREXPFN["\""] = "_torexp_dqstr"
+ _TOREXPFN["'"] = "_torexp_sqstr"
+}
+
+#_______________________________________________
+function _torexp_rexp(t)
+{
+ return t
+}
+
+#_____________________________________________________________________________
+function _tpass(f, p, p0, p1)
+{
+ ####################################################
+ delete _t_ENDF[++_t_ENDF[0]]
+ f = p ? _tpass_i0(f, p, p0, p1) : ""
+ --_t_ENDF[0]
+ return f
+}
+
+#___________________________________________________________
+function _tpass_i0(f, p, p0, p1, a)
+{
+ while (p in _tLINK) {
+ p = _tLINK[p]
+ }
+ return (p in _tFCHLD ? _tmpass(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))
+}
+
+#_____________________________________________________________________________
+function _tpassx(f, p, p0, p1)
+{
+ ###################################################
+ delete _t_ENDF[++_t_ENDF[0]]
+ f = p ? _tpassx_i0(f, p, p0, p1) : ""
+ --_t_ENDF[0]
+ return f
+}
+
+#___________________________________________________________
+function _tpassx_i0(f, p, p0, p1)
+{
+ while (p in _tLINK) {
+ p = _tLINK[p]
+ }
+ return (p in _tFCHLD ? _tmpassx(f, _tFCHLD[p], p0, p1) : @f(p, p0, p1))
+}
+
+#_________________________________________________________________
+function _tpop(p, aA, a)
+{
+ ###########################################
+ if ((a = _tSTACK[p][0]) > 0) {
+ _tSTACK[p][0]--
+ if (isarray(_tSTACK[p][a])) {
+ delete aA
+ _movarr(aA, _tSTACK[p][a])
+ return
}
- return (_ln(v "'") _ln(t))
+ return _tSTACK[p][a]
}
+ _fatal("^" p ": Out of tSTACK")
+}
- function _verb(t, d, A)
- {
- if (_ERRLOG_VF) {
- A["TYPE"] = "VERB"
- A["TEXT"] = t
- _log(A, d)
- }
+#_____________________________________________________________________________
+function _tpush(p, aA, a)
+{
+ ######################################################
+ if (isarray(aA)) {
+ delete _tSTACK[p][a = ++_tSTACK[p][0]]
+ _tSTACK[p][a][""]
+ delete _tSTACK[p][a][""]
+ _movarr(_tSTACK[p][a], aA)
+ return
}
-
- function _wFBRO(p, v, a)
- {
- if (p) {
- if (v) {
- for (a = p; a in _tPARENT; ) {
- if ((a = _tPARENT[a]) == v) {
- return v
- }
- }
- if (p in _tPARENT) {
- p = _tPARENT[p]
- if (v in _tNEXT) {
- if (v in _tPREV) {
- _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v]
- delete _tPREV[v]
- if (v in _tPARENT) {
- if (p == (a = _tPARENT[v])) {
- return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v)
- }
- --_tQCHLD[a]
- }
- } else if (v in _tPARENT) {
- if (p == (a = _tPARENT[v])) {
- return v
- }
- delete _tPREV[_tFCHLD[a] = _tNEXT[v]]
- --_tQCHLD[a]
- } else {
- delete _tPREV[_tNEXT[v]]
- }
- ++_tQCHLD[p]
- return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v)
- } else {
- if (v in _tPREV) {
- if (v in _tPARENT) {
- delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]]
- if (p == a) {
- delete _tPREV[v]
- return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v)
- }
- --_tQCHLD[a]
- } else {
- delete _tNEXT[_tPREV[v]]
- }
- delete _tPREV[v]
- } else if (v in _tPARENT) {
- if (p == (a = _tPARENT[v])) {
- return v
- }
- delete _tFCHLD[a]
- delete _tLCHLD[a]
- delete _tQCHLD[a]
- }
- ++_tQCHLD[p]
- return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v)
- }
- } else {
- while (p in _tPREV) {
- p = _tPREV[p]
- }
- if (v in _tPREV) {
- if (v in _tPARENT) {
- --_tQCHLD[a = _tPARENT[v]]
- delete _tPARENT[v]
- if (v in _tNEXT) {
- _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v]
- } else {
- delete _tNEXT[_tLCHLD[a] = _tPREV[v]]
- }
- } else if (v in _tNEXT) {
- _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v]
- } else {
- delete _tNEXT[_tPREV[v]]
- }
- delete _tPREV[v]
- } else {
- if (p == v) {
- return v
- }
- if (v in _tPARENT) {
- if (v in _tNEXT) {
- delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]]
- --_tQCHLD[a]
- } else {
- delete _tLCHLD[a = _tPARENT[v]]
- delete _tFCHLD[a]
- delete _tQCHLD[a]
- }
- delete _tPARENT[v]
- } else if (v in _tNEXT) {
- delete _tPREV[_tNEXT[v]]
- }
- }
- return (_tPREV[_tNEXT[v] = p] = v)
- }
- } else {
- if (v == 0) {
- return v
- }
- return v
- }
+ delete _tSTACK[p][a = ++_tSTACK[p][0]]
+ return (_tSTACK[p][a] = aA)
+}
+
+# prefix -
+# prichr - aware character `{', `^',`]'
+# sechr - aware character `.' as the first char of sechr, and character `}'
+# suffix - aware character `]'
+# cntptr - aware character `]'
+function _tr(n, cs, H)
+{
+ #_tuidinitcs[p]=cs
+ #2 uidel, 5 pfx, 7 hichr,11(10) lochr,14 suffix
+ _rconline(n ": " cs)
+ _rconl()
+ if (match(cs, /^((([^\xB4:\[\|\]]*\xB4.)*[^\xB4:\[\|\]]*):)?((([^\xB4\[\|\]]*\xB4.)*[^\xB4\[\|\]]*)\[)?(([^\xB4\|\]]*\xB4.)*[^\xB4\|\]]*)?(\|(\.)?(([^\xB4\]]*\xB4.)*[^\xB4\]]*))?(\](.*))?$/, H)) {
+ _rconl("delptr: " _une(H[2]) "'")
+ _rconl("pfxstr: " _une(H[5]) "'")
+ _rconl("hichr: " _une(H[7]) "'")
+ _rconl("lochr: " _une(H[10] ? H[7] "' and " H[11] "'" : H[11] "'"))
+ _rconl("sfxstr: " _une(H[14]) "'")
+ } else {
+ _rconl("NOT MATCH!")
+ }
+ _rconl()
+}
+
+#_______________________________________________________________________
+function _trace(t, d, A)
+{
+ #################################################
+ if (_ERRLOG_TF) {
+ A["TYPE"] = "TRACE"
+ A["TEXT"] = t
+ _log(A, d)
+ }
+}
+
+#_________________________________________________________________
+function _trunframe(f, p, p0, p1, p2)
+{
+ #################################
+ return _tframe(f ? f : "_trunframe_i0", p, p0, p1, p2)
+}
+
+#_________________________________________________________________
+function _trunframe_i0(p, p0, p1, p2, f)
+{
+ if (p in _tFN) {
+ f = _tFN[p]
+ return @f(p, p0, p1, p2)
+ }
+}
+
+#_________________________________________________________________
+function _trunframex(f, p, p0, p1)
+{
+ ###################################
+ return _tframex(f ? f : "_trunframe_i0", p, p0, p1)
+}
+
+#_________________________________________________________________
+function _trunpass(f, p, p0, p1)
+{
+ #####################################
+ return _tpass(f ? f : "_trunframe_i0", p, p0, p1)
+}
+
+#_________________________________________________________________
+function _trunpassx(f, p, p0, p1)
+{
+ ####################################
+ return _tpassx(f ? f : "_trunframe_i0", p, p0, p1)
+}
+
+#_________________________________________________________________
+function _tsetsp(p, v)
+{
+ #############################################
+ return (_tSTACK[p][0] = v)
+}
+
+# dptr - morg ptr; in case if object deleted then _CLASSPTR[ptr] will be deleted(object is death), but
+# _tUIDEL[_CLASSPTR[ptr]] will be created that object can be resurrected from morg
+# dptr can be any string containing any characters except `:'. It's not verified
+# pfx,sfx - uid prefix str, and uid suffix str; this strings specifies string that can be inserted before/after
+# uid generated by uid generator:
+#
+# class uid: pfx uidgen sfx
+#
+# Both can be any string(including ""), and can contains any character with B4-escaping feature.
+# Note: that this strings cannot contains "'" character: it's should be escaped by B4-escaper.
+# hstr,lstr - this values configure uid-generator itself. ther is a 3 combinations regarding its:
+#
+# hstr lstr function
+#
+# `ptr * - specify pointer to external uid-generator
+# All uids and chars will be generated by external uid-generator
+# * ^ptr - class will have it's own uid generator using external character set
+# str str - class will have it's own uid generator with it's own character set
+# character set inmplemented in hstr(high-charset) and in lstr(low-charset) in 2 ways:
+# 1) "AB" "AB01" - this mean that high-charset contain chars: `A' and `B'
+# low-charset contains chars: `A', `B', `0', `1'
+#
+# 2) "Az,By" "Ax,Bw,0v,1u" - this mean that high-charset contain chars: `Az' and `By'
+# low-charset contains chars: `Ax', `Bw', `0v', `1u'
+# Note: both: hstr and lstr cannot contain char `,' directly, but it's can uses
+# B4-escaper to escape any char including `,'
+
+
+
+# !!!! in case of using `,' in hstr/lstr - the escaped `,' will leads to interpretate hstr and lstr as divided by `,'
+# if parameters error then i should be more specific about what error in parameters detected
+# document _inituid(): parameters; document cs: uid initialization string format
+# test with escape char
+# adv hstr and lstr splitting?
+# chk if hstr len==0 ?
+# return _tclass & report error?
+# _tapi thru function
+
+# additional syntax checking ???
+# implement syntax and uid srv in docs
+# add _dumpuid() ????
+# make performance measurement
+# protection against badchar list
+# additional feature to specify _getuid() to not resurrect uid; and informative that uid was ressurected or not
+# build _defclass fn
+
+# _tuidinitcs ????
+# _tuidchrh[p]
+# _tuidchrl[p]
+# _tuidchr[p]
+# _tuidcnt[p]
+# _tUIDPFX[p]
+# _tUIDSFX[p]
+# _tUIDEL
+# _tUIDCNTH
+# _tUIDCNTL
+# _tUIDCHRL
+# _tUIDCHRH
+
+# create default class basic `new' and `del' functions
+function _tstini()
+{
+ _ini("uidel:pfx'hstr|lstr'sfx")
+ _ini("uidel:pfx'hstr|lstr'")
+ _ini("uidel:'hstr|lstr'sfx")
+ _ini("uidel:'hstr|lstr'")
+ _ini("uidel:pfx'hstr'sfx")
+ _ini("uidel:pfx'hstr'")
+ _ini("uidel:'hstr'sfx")
+ _ini("uidel:'hstr'")
+ _conl()
+ _conl("########################################################################################")
+ _conl()
+ _ini("pfx'hstr|lstr'sfx")
+ _ini("pfx'hstr|lstr'")
+ _ini("'hstr|lstr'sfx")
+ _ini("'hstr|lstr'")
+ _ini("pfx'hstr'sfx")
+ _ini("pfx'hstr'")
+ _ini("'hstr'sfx")
+ _ini("'hstr'")
+ _conl()
+ _conl("########################################################################################")
+ _conl()
+ _ini("uidel:pfx'`cntptr'sfx")
+ _ini("uidel:pfx'`cntptr'")
+ _ini("uidel:'`cntptr'sfx")
+ _ini("uidel:'`cntptr'")
+ _conl()
+ _conl("########################################################################################")
+ _conl()
+ _ini("pfx'`cntptr'sfx")
+ _ini("pfx'`cntptr'")
+ _ini("'`cntptr'sfx")
+ _ini("'`cntptr'")
+ _conl()
+ _conl("########################################################################################")
+ _conl()
+ _ini("uidel:pfx'^chrptr'sfx")
+ _ini("uidel:pfx'^chrptr'")
+ _ini("uidel:'^chrptr'sfx")
+ _ini("uidel:'^chrptr'")
+ _conl()
+ _conl("########################################################################################")
+ _conl()
+ _ini("pfx'^chrptr'sfx")
+ _ini("pfx'^chrptr'")
+ _ini("'^chrptr'sfx")
+ _ini("'^chrptr'")
+ _conl()
+ _conl("########################################################################################")
+ _conl()
+}
+
+function _tstv(p, A, r, f)
+{
+ if (f == "") {
+ f = "tst_splitstr"
+ }
+ @f(_NOP, A, p)
+ @f(AA0, A, p)
+ @f(AB0, A, p)
+ @f(AC0, A, p)
+ @f("", A, p)
+ @f("a", A, p)
+ @f("\264a", A, p)
+ @f("\264", A, p)
+ @f("a\264\264\264,ba\264\264\264,", A, p)
+ @f("\264,", A, p)
+ @f(",", A, p)
+ @f("\264a,", A, p)
+ @f("ab,", A, p)
+ @f("ab,\264", A, p)
+ @f("\264a\264,,ba", A, p)
+ @f(",a,,b\264,c,,\264a,,\264,,,", A, p)
+}
+
+function _typ(p)
+{
+ return (_t0 = isarray(p) ? "#" : p == 0 ? p == "" ? 0 : p in _CLASSPTR ? "`" : p ? 3 : 4 : p in _CLASSPTR ? "`" : p + 0 == p ? 5 : p ? 3 : 2)
+}
+
+function _typa(p, A)
+{
+ return (_t0 = isarray(p) ? "#" : p == 0 ? p == "" ? 0 : p in A ? "`" : p ? 3 : 4 : p in A ? "`" : p + 0 == p ? 5 : p ? 3 : 2)
+}
+
+#_____________________________________________________
+# _tframe0(hndstr,ptr)
+#
+#
+# IN:
+# MOD:
+# OUT:
+# RETURN:
+#
+# handler string:
+# Handler-string divides to words. Word splitter is char ";"
+#
+# Note that handler-string processed left to right. This mean that next word(more rightly) will overwrite fields implemented before(leftmost).
+# Note that if word-string contains more than one rexp-field then only last rexp-field(most rightly) will be applied.
+#_______________________________________________
+# TO DESIGN:
+#
+# 0-4: complete design of tlink handler call
+# 1-4: add new tlink handler call
+# 1-4: add new run fn (changed rexp to different for each type: see _tframe0)
+#
+# hndstr:
+# may be add rexp for each type of handler and also total rexp for all ??? ADDED (test)
+# may be add separator char ";" ??? ADDED (test)
+#_______________________________________________________________________
+function _tzend(a, b)
+{
+ #####################################################
+ if (b == 0 && b == "") {
+ return (_TEND[_TEND[_ARRLEN]] = a)
+ } else {
+ return (_TEND[_TEND[_ARRLEN] + a] = b)
+ }
+}
+
+function _uidcyc(p, i)
+{
+ _dumpuidgen(p)
+ for (i = 1; i < (64 * 8 * 6 - 1); i++) {
+ _conl(i ":" _var(_getuid(p)))
+ }
+ _dumpuidgen(p)
+}
+
+function _une(t)
+{
+ return gensub(/\xB4(.)/, "\\1", "G", t)
+}
+
+#___________________________________________________________________________________
+function _unformatrexp(t)
+{
+ _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB)
+ _formatstrs0 = ""
+ for (t = 1; t < _formatstrq0; t++) {
+ _formatstrs0 = _formatstrs0 _FORMATSTRA[t] (_FORMATSTRB[t] in _QESCHR ? _QESCREXP[_FORMATSTRB[t]] : _QESCREXP[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])
+ }
+ return (_formatstrs0 _FORMATSTRA[t])
+}
+
+#___________________________________________________________
+function _unformatrexp_init(i, a)
+{
+ _formatstrs0 = "\\^$.[]|()*+?{}-sSwW<>yB`'"
+ delete _FORMATSTRB
+ for (i = 0; i < 256; i++) {
+ _QESCREXP["\\" _CHR[i]] = index(_formatstrs0, _CHR[i]) ? "\\" _CHR[i] : _CHR[i]
+ }
+ for (i = 0; i < 256; i++) {
+ a = index(_formatstrs0, _CHR[i]) ? "\\" : ""
+ _QESCREXP[sprintf("%.2X", i)] = a _CHR[i]
+ _QESCREXP["\\" sprintf("%.3o", i)] = a _CHR[i]
+ if (i < 8) {
+ _QESCREXP["\\" sprintf("%.1o", i)] = a _CHR[i]
+ }
+ if (i < 64) {
+ _QESCREXP["\\" sprintf("%.2o", i)] = a _CHR[i]
+ }
+ if (i < 16) {
+ _QESCREXP["\\x" sprintf("%.1X", i)] = _QESCREXP["\\x" sprintf("%.1x", i)] = a _CHR[i]
+ }
+ }
+ patsplit("a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11, _FORMATSTRA, /[^0-9]/, _FORMATSTRB)
+ for (i in _FORMATSTRA) {
+ _QESCREXP["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0]
+ }
+}
+
+#___________________________________________________________________________________
+function _unformatstr(t)
+{
+ _formatstrq0 = split(t, _FORMATSTRA, /(\\[0-9]{1,3})|(\\x[[:xdigit:]]+)|(\\.)/, _FORMATSTRB)
+ _formatstrs0 = ""
+ for (t = 1; t < _formatstrq0; t++) {
+ _formatstrs0 = _formatstrs0 _FORMATSTRA[t] (_FORMATSTRB[t] in _QESCHR ? _QESCHR[_FORMATSTRB[t]] : _QESCHR[toupper(substr(_FORMATSTRB[t], length(_FORMATSTRB[t]) - 1))])
+ }
+ return (_formatstrs0 _FORMATSTRA[t])
+}
+
+#___________________________________________________________
+function _unformatstr_init(i)
+{
+ for (i = 0; i < 256; i++) {
+ _QESCHR["\\" _CHR[i]] = _CHR[i]
+ }
+ for (i = 0; i < 256; i++) {
+ _QESCHR[sprintf("%.2X", i)] = _CHR[i]
+ _QESCHR["\\" sprintf("%.3o", i)] = _CHR[i]
+ if (i < 8) {
+ _QESCHR["\\" sprintf("%.1o", i)] = _CHR[i]
+ }
+ if (i < 64) {
+ _QESCHR["\\" sprintf("%.2o", i)] = _CHR[i]
+ }
+ if (i < 16) {
+ _QESCHR["\\x" sprintf("%.1X", i)] = _QESCHR["\\x" sprintf("%.1x", i)] = _CHR[i]
+ }
+ }
+ i = "a" 7 "b" 8 "f" 12 "n" 10 "r" 13 "t" 9 "v" 11
+ patsplit(i, _FORMATSTRA, /[^0-9]/, _FORMATSTRB)
+ for (i in _FORMATSTRA) {
+ _QESCHR["\\" _FORMATSTRA[i]] = _CHR[_FORMATSTRB[i] + 0]
+ }
+}
+
+#_____________________________________________________________________________
+function _uninit_del(A, i, p0)
+{
+ _del(i)
+}
+
+####################################################################################
+# PUBLIC:
+#_____________________________________________________________________________
+# var _SYS_STDOUT - (by default = "/dev/stdout") standart output pipe filename
+# var _SYS_STDERR - (by default = "/dev/stderr") standart error output pipe filename
+# var _SYS_STDCON - (by default = "CON") standart console output device
+#_____________________________________________________________________________
+# var _CHR["CR"] - return cursor to the position 0 without newline(normally ="\x0D")
+# var _CHR["EOL"] - return cursor to the position 0 & newline (MS:="\x0D\x0A" / UX:="\x0D")
+# var _CON_WIDTH - console width(columns number)
+#_____________________________________________________________________________
+# fn _cmd(c) - execute shell command c and return output
+# fn _err - output string w\o any addition into _SYS_STDERR device
+# fn _errnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDERR device
+# fn _out - output string w\o any addition into _SYS_STDOUT device
+# fn _outnl - output string with addition _CHR["EOL"] at the end of the string into _SYS_STDOUT device
+#_____________________________________________________________________________
+# fn _con(text[,tabspace])
+# fn _conl(text[,tabspace])
+# fn _conline(text[,tabspace])
+# fn _constat(status[,tabspace])
+# fn _constatpush([status[,tabspace]])
+# fn _constatpop()
+#_______________________________________________________________________
+# var _constatstr
+####################################################################################
+function _unstr(t)
+{
+ return gensub(/\\(.)/, "\\1", "G", t)
+}
+
+#_________________________________________________________________
+function _untmp(f, a)
+{
+ #############################################
+ if ((f = filepath(f))) {
+ if (match(f, /\\$/)) {
+ _deletepfx(_FILEIO_RDTMP, a = toupper(f))
+ _deletepfx(_FILEIO_RDNETMP, a)
} else {
- if (p == 0) {
- return v
- }
- if (v) {
- return _texclude(v)
- }
- return v
+ delete _FILEIO_RDNETMP[toupper(f)]
}
+ return f
}
-
- function _wFCHLD(p, v, a)
- {
- if (p) {
- if (v) {
- if (p == v) {
+ return ""
+}
+
+#_____________________________________________________________________________
+function _val(v, t)
+{
+ if (isarray(v)) {
+ return (_dumparr(v) _ln(t))
+ }
+ if (v == 0 && v == "") {
+ return (_ln("- (ERRNO=" ERRNO ")") _ln(t))
+ }
+ return (_ln(v "'") _ln(t))
+}
+
+#_____________________________________________________________________________
+function _val0(v)
+{
+ if (isarray(v)) {
+ return _dumparr(v)
+ }
+ if (v == 0 && v == "") {
+ return "-"
+ }
+ return ("\"" v "\"")
+}
+
+#_____________________________________________________________________________
+function _var(v, t)
+{
+ if (isarray(v)) {
+ return (_dumparr(v) _ln(t))
+ }
+ if (v == 0 && v == "") {
+ return (_ln("- (ERRNO=" ERRNO ")") _ln(t))
+ }
+ return (_ln(v "'") _ln(t))
+}
+
+#_______________________________________________________________________
+function _verb(t, d, A)
+{
+ ##################################################
+ if (_ERRLOG_VF) {
+ A["TYPE"] = "VERB"
+ A["TEXT"] = t
+ _log(A, d)
+ }
+}
+
+#_________________________________________________________________
+function _wFBRO(p, v, a)
+{
+ ###########################################
+ if (p) {
+ if (v) {
+ for (a = p; a in _tPARENT; ) {
+ if ((a = _tPARENT[a]) == v) {
return v
}
- for (a = p; a in _tPARENT; ) {
- if ((a = _tPARENT[a]) == v) {
- return v
- }
- }
+ } ######################## v is parentesis of p
+ if (p in _tPARENT) {
+ p = _tPARENT[p]
if (v in _tNEXT) {
if (v in _tPREV) {
_tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v]
@@ -5819,11 +7163,8 @@
} 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]
+ ++_tQCHLD[p]
+ return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v)
} else {
if (v in _tPREV) {
if (v in _tPARENT) {
@@ -5845,159 +7186,166 @@
delete _tLCHLD[a]
delete _tQCHLD[a]
}
- if (p in _tFCHLD) {
- ++_tQCHLD[p]
- return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v)
- }
+ ++_tQCHLD[p]
+ return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v)
}
- _tQCHLD[p] = 1
- return (_tFCHLD[_tPARENT[v] = p] = _tLCHLD[p] = v)
} else {
- if (v == 0) {
- if (p in _tFCHLD) {
- v = _tFCHLD[p]
- delete _tFCHLD[p]
- delete _tLCHLD[p]
- delete _tQCHLD[p]
- do {
- delete _tPARENT[v]
- } while (v in _tNEXT && (v = _tNEXT[v]))
+ while (p in _tPREV) {
+ p = _tPREV[p]
+ }
+ if (v in _tPREV) {
+ if (v in _tPARENT) {
+ --_tQCHLD[a = _tPARENT[v]]
+ delete _tPARENT[v]
+ if (v in _tNEXT) {
+ _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v]
+ } else {
+ delete _tNEXT[_tLCHLD[a] = _tPREV[v]]
+ }
+ } else if (v in _tNEXT) {
+ _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v]
+ } else {
+ delete _tNEXT[_tPREV[v]]
+ }
+ delete _tPREV[v]
+ } else {
+ if (p == v) {
+ return v
+ }
+ if (v in _tPARENT) {
+ if (v in _tNEXT) {
+ delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]]
+ --_tQCHLD[a]
+ } else {
+ delete _tLCHLD[a = _tPARENT[v]]
+ delete _tFCHLD[a]
+ delete _tQCHLD[a]
+ }
+ delete _tPARENT[v]
+ } else if (v in _tNEXT) {
+ delete _tPREV[_tNEXT[v]]
}
}
- return v
+ return (_tPREV[_tNEXT[v] = p] = v)
}
} else {
- if (p == 0) {
+ if (v == 0) {
return v
- }
+ } ######################## p=ptr, v=0
return v
}
+ } else { ######################## p=ptr, v=""
+ if (p == 0) {
+ return v ######################## p=0
+ }
+ if (v) {
+ return _texclude(v) ######################## p="", v=ptr - exclude v
+ }
+ return v
}
+}
- function _wLBRO(p, v, a)
- {
- if (p) {
- if (v) {
- for (a = p; a in _tPARENT; ) {
- if ((a = _tPARENT[a]) == v) {
- return v
- }
+#_________________________________________________________________
+function _wFCHLD(p, v, a)
+{
+ ##########################################
+ if (p) {
+ if (v) {
+ if (p == v) {
+ return v
+ } ######################## p=v=ptr
+ for (a = p; a in _tPARENT; ) {
+ if ((a = _tPARENT[a]) == v) {
+ return v
}
- if (p in _tPARENT) {
- p = _tPARENT[p]
- if (v in _tPREV) {
- if (v in _tNEXT) {
- _tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v]
- delete _tNEXT[v]
- if (v in _tPARENT) {
- if (p == (a = _tPARENT[v])) {
- return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v)
- }
- --_tQCHLD[a]
- }
- } else if (v in _tPARENT) {
- if (p == (a = _tPARENT[v])) {
- return v
- }
- delete _tNEXT[_tLCHLD[a] = _tPREV[v]]
- --_tQCHLD[a]
- } else {
- delete _tNEXT[_tPREV[v]]
- }
- ++_tQCHLD[p]
- return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v)
- } else {
- if (v in _tNEXT) {
- if (v in _tPARENT) {
- delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]]
- if (p == a) {
- delete _tNEXT[v]
- return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[p]] = v)
- }
- --_tQCHLD[a]
- } else {
- delete _tPREV[_tNEXT[v]]
- }
- delete _tNEXT[v]
- } else if (v in _tPARENT) {
- if (p == (a = _tPARENT[v])) {
- return v
- }
- delete _tLCHLD[a]
- delete _tFCHLD[a]
- delete _tQCHLD[a]
+ } ######################## v is parentesis of p
+ if (v in _tNEXT) {
+ if (v in _tPREV) {
+ _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v]
+ delete _tPREV[v]
+ if (v in _tPARENT) {
+ if (p == (a = _tPARENT[v])) {
+ return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[p]] = v)
}
- ++_tQCHLD[p]
- return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v)
+ --_tQCHLD[a]
}
- } else {
- while (p in _tNEXT) {
- p = _tNEXT[p]
+ } else if (v in _tPARENT) {
+ if (p == (a = _tPARENT[v])) {
+ return 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]]
+ delete _tPREV[_tFCHLD[a] = _tNEXT[v]]
+ --_tQCHLD[a]
+ } 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) {
- 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 _tNEXT[_tPREV[v]]
}
- return (_tNEXT[_tPREV[v] = p] = 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]
}
- } else {
- if (v == 0) {
- return v
+ if (p in _tFCHLD) {
+ ++_tQCHLD[p]
+ return (_tFCHLD[p] = _tPREV[_tNEXT[v] = _tFCHLD[_tPARENT[v] = p]] = v)
}
- return v
}
+ _tQCHLD[p] = 1
+ return (_tFCHLD[_tPARENT[v] = p] = _tLCHLD[p] = v)
} else {
- if (p == 0) {
- return v
- }
- if (v) {
- return _texclude(v)
+ if (v == 0) {
+ if (p in _tFCHLD) { ######################## p=ptr, v=0 > delete all chld
+ v = _tFCHLD[p]
+ delete _tFCHLD[p]
+ delete _tLCHLD[p]
+ delete _tQCHLD[p]
+ do {
+ delete _tPARENT[v]
+ } while ((v in _tNEXT) && (v = _tNEXT[v]))
+ }
}
return v
}
+ } else { ######################## p=ptr, v="" > ignore action
+ if (p == 0) {
+ return v ######################## p=0
+ }
+ return v
}
+}
- function _wLCHLD(p, v, a)
- {
- if (p) {
- if (v) {
- if (p == v) {
+#_________________________________________________________________
+function _wLBRO(p, v, a)
+{
+ ###########################################
+ if (p) {
+ if (v) {
+ for (a = p; a in _tPARENT; ) {
+ if ((a = _tPARENT[a]) == v) {
return v
}
- for (a = p; a in _tPARENT; ) {
- if ((a = _tPARENT[a]) == v) {
- return v
- }
- }
+ } ######################## v is parentesis of p
+ if (p in _tPARENT) {
+ p = _tPARENT[p]
if (v in _tPREV) {
if (v in _tNEXT) {
_tNEXT[_tPREV[a] = _tPREV[v]] = a = _tNEXT[v]
@@ -6017,11 +7365,8 @@
} else {
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) {
@@ -6043,588 +7388,759 @@
delete _tFCHLD[a]
delete _tQCHLD[a]
}
- if (p in _tLCHLD) {
- ++_tQCHLD[p]
- return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v)
- }
+ ++_tQCHLD[p]
+ return (_tLCHLD[p] = _tNEXT[_tPREV[v] = _tLCHLD[_tPARENT[v] = p]] = v)
}
- _tQCHLD[p] = 1
- return (_tLCHLD[_tPARENT[v] = p] = _tFCHLD[p] = v)
} else {
- if (v == 0) {
- if (p in _tFCHLD) {
- v = _tFCHLD[p]
- delete _tFCHLD[p]
- delete _tLCHLD[p]
- delete _tQCHLD[p]
- do {
- delete _tPARENT[v]
- } while (v in _tNEXT && (v = _tNEXT[v]))
+ while (p in _tNEXT) {
+ p = _tNEXT[p]
+ }
+ if (v in _tNEXT) {
+ if (v in _tPARENT) {
+ --_tQCHLD[a = _tPARENT[v]]
+ delete _tPARENT[v]
+ if (v in _tPREV) {
+ _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v]
+ } else {
+ delete _tPREV[_tFCHLD[a] = _tNEXT[v]]
+ }
+ } else if (v in _tPREV) {
+ _tPREV[_tNEXT[a] = _tNEXT[v]] = a = _tPREV[v]
+ } else {
+ delete _tPREV[_tNEXT[v]]
+ }
+ delete _tNEXT[v]
+ } else {
+ if (p == v) {
+ return v
+ }
+ if (v in _tPARENT) {
+ if (v in _tPREV) {
+ delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]]
+ --_tQCHLD[a]
+ } else {
+ delete _tFCHLD[a = _tPARENT[v]]
+ delete _tLCHLD[a]
+ delete _tQCHLD[a]
+ }
+ delete _tPARENT[v]
+ } else if (v in _tPREV) {
+ delete _tNEXT[_tPREV[v]]
}
}
- return v
+ return (_tNEXT[_tPREV[v] = p] = v)
}
} else {
- if (p == 0) {
+ if (v == 0) {
return v
- }
+ } ######################## p=ptr, v=0
return v
}
+ } else { ######################## p=ptr, v=""
+ if (p == 0) {
+ return v ######################## p=0
+ }
+ if (v) {
+ return _texclude(v) ######################## p="", v=ptr - exclude v
+ }
+ return v
}
+}
- function _wLINK(p, v)
- {
- return (_tLINK[p] = v)
- }
-
- function _wNEXT(p, v, a, b)
- {
- if (p) {
- if (v) {
- if (p == v) {
+#_________________________________________________________________
+function _wLCHLD(p, v, a)
+{
+ ##########################################
+ if (p) {
+ if (v) {
+ if (p == v) {
+ return v
+ } ######################## p=v=ptr
+ for (a = p; a in _tPARENT; ) {
+ if ((a = _tPARENT[a]) == v) {
return v
}
- for (a = p; a in _tPARENT; ) {
- if ((a = _tPARENT[a]) == v) {
- return v
+ } ######################## 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]
}
- }
- if (v in _tPREV) {
- if (p == (a = _tPREV[v])) {
+ } else if (v in _tPARENT) {
+ if (p == (a = _tPARENT[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]
- }
- }
- } else if (v in _tNEXT) {
+ delete _tNEXT[_tLCHLD[a] = _tPREV[v]]
+ --_tQCHLD[a]
+ } else {
+ delete _tNEXT[_tPREV[v]]
+ }
+ 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 _tPREV[_tNEXT[v]]
}
+ delete _tNEXT[v]
} else if (v in _tPARENT) {
- delete _tFCHLD[a = _tPARENT[v]]
+ if (p == (a = _tPARENT[v])) {
+ return v
+ }
delete _tLCHLD[a]
+ delete _tFCHLD[a]
delete _tQCHLD[a]
}
- if (p in _tNEXT) {
- _tPREV[_tNEXT[v] = _tNEXT[p]] = v
- if (p in _tPARENT) {
- ++_tQCHLD[_tPARENT[v] = _tPARENT[p]]
- } else {
+ if (p in _tLCHLD) {
+ ++_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]))
+ }
+ }
+ return v
+ }
+ } else { ######################## p=ptr, v="" > ignore action
+ if (p == 0) {
+ return v ######################## p=0
+ }
+ return 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
+ 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[v]
- if (p in _tPARENT) {
- ++_tQCHLD[_tPARENT[_tLCHLD[a] = v] = a = _tPARENT[p]]
- } else {
- delete _tPARENT[v]
+ delete _tNEXT[a]
+ if (v in _tPARENT) {
+ _tLCHLD[b = _tPARENT[v]] = a
+ --_tQCHLD[b]
}
}
- return (_tNEXT[_tPREV[v] = p] = v)
+ } else if (v in _tNEXT) {
+ if (v in _tPARENT) {
+ delete _tPREV[_tFCHLD[a = _tPARENT[v]] = _tNEXT[v]]
+ --_tQCHLD[a]
+ } else {
+ delete _tPREV[_tNEXT[v]]
+ }
+ } else if (v in _tPARENT) {
+ delete _tFCHLD[a = _tPARENT[v]]
+ delete _tLCHLD[a]
+ delete _tQCHLD[a]
+ }
+ if (p in _tNEXT) {
+ _tPREV[_tNEXT[v] = _tNEXT[p]] = v
+ if (p in _tPARENT) {
+ ++_tQCHLD[_tPARENT[v] = _tPARENT[p]]
+ } else {
+ delete _tPARENT[v]
+ }
} else {
- if (v == 0) {
- return v
+ delete _tNEXT[v]
+ if (p in _tPARENT) {
+ ++_tQCHLD[_tPARENT[_tLCHLD[a] = v] = a = _tPARENT[p]]
+ } else {
+ delete _tPARENT[v]
}
- return v
}
+ return (_tNEXT[_tPREV[v] = p] = v)
} else {
- if (p == 0) {
+ if (v == 0) {
return v
- }
- if (v) {
- return _texclude(v)
- }
+ } ######################## p=ptr, v=0
return v
}
- }
-
- function _wPARENT(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 _wPREV(p, v, a, b)
- {
- if (p) {
- if (v) {
- if (p == 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
}
- 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 _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]
- }
+ if (v in _tPREV) {
+ _tNEXT[_tPREV[a] = _tPREV[v]] = a
+ if (v in _tPARENT) {
+ --_tQCHLD[_tPARENT[v]]
}
- } else if (v in _tPREV) {
+ } else {
+ delete _tPREV[a]
if (v in _tPARENT) {
- delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]]
- --_tQCHLD[a]
- } else {
- delete _tNEXT[_tPREV[v]]
+ _tFCHLD[b = _tPARENT[v]] = a
+ --_tQCHLD[b]
}
- } else if (v in _tPARENT) {
- delete _tLCHLD[a = _tPARENT[v]]
- delete _tFCHLD[a]
- delete _tQCHLD[a]
}
- if (p in _tPREV) {
- _tNEXT[_tPREV[v] = _tPREV[p]] = v
- if (p in _tPARENT) {
- ++_tQCHLD[_tPARENT[v] = _tPARENT[p]]
- } else {
- delete _tPARENT[v]
- }
+ } else if (v in _tPREV) {
+ if (v in _tPARENT) {
+ delete _tNEXT[_tLCHLD[a = _tPARENT[v]] = _tPREV[v]]
+ --_tQCHLD[a]
} else {
- delete _tPREV[v]
- if (p in _tPARENT) {
- ++_tQCHLD[_tPARENT[_tFCHLD[a] = v] = a = _tPARENT[p]]
- } else {
- delete _tPARENT[v]
- }
+ delete _tNEXT[_tPREV[v]]
+ }
+ } else if (v in _tPARENT) {
+ delete _tLCHLD[a = _tPARENT[v]]
+ delete _tFCHLD[a]
+ delete _tQCHLD[a]
+ }
+ if (p in _tPREV) {
+ _tNEXT[_tPREV[v] = _tPREV[p]] = v
+ if (p in _tPARENT) {
+ ++_tQCHLD[_tPARENT[v] = _tPARENT[p]]
+ } else {
+ delete _tPARENT[v]
}
- return (_tPREV[_tNEXT[v] = p] = v)
} else {
- if (v == 0) {
- return v
+ delete _tPREV[v]
+ if (p in _tPARENT) {
+ ++_tQCHLD[_tPARENT[_tFCHLD[a] = v] = a = _tPARENT[p]]
+ } else {
+ delete _tPARENT[v]
}
- return v
}
+ return (_tPREV[_tNEXT[v] = p] = v)
} else {
- if (p == 0) {
+ if (v == 0) {
return v
- }
- if (v) {
- return _texclude(v)
- }
+ } ######################## p=ptr, v=0
return v
}
- }
-
- function _wQBRO(p, v)
- {
+ } else { ######################## p=ptr, v=""
+ if (p == 0) {
+ return v ######################## p=0
+ }
+ if (v) {
+ return _texclude(v) ######################## p="", v=ptr - exclude v
+ }
return v
}
-
- function _wQCHLD(p, v)
- {
- if (p) {
- if (v) {
- } else {
- if (v == 0) {
- if (p in _tFCHLD) {
- v = _tFCHLD[p]
- delete _tFCHLD[p]
- delete _tLCHLD[p]
- delete _tQCHLD[p]
- do {
- delete _tPARENT[v]
- } while (v in _tNEXT && (v = _tNEXT[v]))
- }
+}
+
+#_________________________________________________________________
+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
- }
- } else {
- if (p == 0) {
- return v
}
return v
}
+ } else { ######################## p=ptr, v="" > ignore action
+ if (p == 0) {
+ return v
+ } ######################## p=0
+ return v
}
+}
- function _warning(t, d, A)
- {
- if (_ERRLOG_WF) {
- A["TYPE"] = "WARNING"
- A["TEXT"] = t
- _log(A, d)
- }
+#_______________________________________________________________________
+function _warning(t, d, A)
+{
+ ###############################################
+ if (_ERRLOG_WF) {
+ A["TYPE"] = "WARNING"
+ A["TEXT"] = t
+ _log(A, d)
}
+}
- function _wfilerdnehnd(f, t)
- {
- if ((f = _filerdne(f)) == "") {
- return ""
- }
- if (! ((t = _filerd(f)) in _WFILEROOTDIR)) {
- _cmd("md \"" t "\" 2>NUL")
- _WFILEROOTDIR[t]
- }
- return f
+#___________________________________________________________
+function _wfilerdnehnd(f, t)
+{
+ if ((f = _filerdne(f)) == "") {
+ return ""
}
-
- function _wonl(t)
- {
- wonl = wonl _ln(t)
+ if (! ((t = _filerd(f)) in _WFILEROOTDIR)) {
+ _cmd("md \"" t "\" 2>NUL")
+ _WFILEROOTDIR[t]
}
+ return f
+}
- function _wonline(t)
- {
- wonl = wonl _ln(substr(" _ " t " _____________________________________________________________________________________________________________________________________", 1, 126))
- }
+function _wonl(t)
+{
+ wonl = wonl _ln(t)
+}
- 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))
- }
+function _wonline(t)
+{
+ wonl = wonl _ln(substr(" _ " t " _____________________________________________________________________________________________________________________________________", 1, 126))
+}
- function _wrfile(f, d, a, b)
- {
- if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") {
- ERRNO = "Filename error"
- return
- }
- a = BINMODE
- BINMODE = "rw"
- b = ORS
- ORS = ""
+#___________________________________________________________
+function _wr_shortcut(f, S)
+{
+ if ((_shrtcutf0 = _filepath(f))) {
ERRNO = ""
- print(d) > f
- if (ERRNO) {
- return ""
- }
- close(f)
- BINMODE = a
- ORS = b
- 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])) "\""
+ }
}
- return f
- }
-
- function _wrfile1(f, d, a, b)
- {
- if ((f = _wfilerdnehnd(f)) == "" || _filene(f) == "") {
- ERRNO = "Filename error"
+ if (_shortcut_nerr(_cmd(_shrtcuta0), _shrtcutf0)) {
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
}
+ 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)
+ if (((dd = dd ? dd : _FILEIO_RD), f) in _FILEROOT) {
+ return (_FILEROOT[dd, f] _FILEDIR[f])
}
+ return (_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[f]
+ }
+ if (f in _FILEROOT) {
+ if ((d = filegetdrvdir(_FILEROOT[f]))) {
+ _FILEDIRFL[f]
+ return (_FILEROOT[f] (_FILEDIR[f] = d _FILEDIR[f]))
+ } else {
+ return (_FILEROOT[f] _FILEDIR[f])
+ }
+ }
+ if (((dd = dd ? dd : _FILEIO_RD), f) in _FILEROOT) {
if ((dd, f) in _FILEDIR) {
- return ((_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[dd, f])
+ return (_FILEROOT[dd, f] _FILEDIR[dd, f])
}
if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) {
- return ((_FILEROOT[dd, f] = fileri(dd)) (_FILEDIR[dd, f] = d))
+ return (_FILEROOT[dd, f] (_FILEDIR[dd, f] = d))
}
- return ((_FILEROOT[dd, f] = fileri(dd)) d)
+ return (_FILEROOT[dd, f] d)
+ }
+ if ((dd, f) in _FILEDIR) {
+ return (_FILEROOT[dd, f] = fileri(dd)) _FILEDIR[dd, f]
}
+ if ((d = filedi(dd) _FILEDIR[f]) ~ /^\\/) {
+ return (_FILEROOT[dd, f] = fileri(dd)) (_FILEDIR[dd, f] = d)
+ }
+ return (_FILEROOT[dd, f] = fileri(dd)) d
+}
- function filerdnehndi(st, a, c, r, d, n, A)
- {
- if (st) {
- if ((c = toupper(st)) in _FILECACHE) {
- return _FILECACHE[c]
- }
- if (match(st, /^[ \t]*\\[ \t]*\\/)) {
- if (match(substr(st, a = RLENGTH + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)*[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) {
- a = a + RLENGTH
- d = ((A[3] ? "\\" A[3] "$" : "")) "\\" A[5]
- gsub(/[ \t]*\\[ \t]*/, "\\", d)
- if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) {
- return (_FILECACHE[substr(c, 1, a)] = _FILECACHE[st])
- }
- _FILEDIR[c = _FILECACHE[substr(c, 1, a)] = _FILECACHE[st] = ++_file_rootcntr] = d
- _FILEDIRFL[c]
- _FILEROOT[c] = r
- } else {
- _filepath_err = "UNC"
- return ""
- }
- } else {
- match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)
- if (! RLENGTH) {
- return ""
- }
- d = A[8] A[10]
+#___________________________________________________________
+function filerdnehndi(st, a, c, r, d, n, A)
+{
+ if (st) {
+ if ((c = toupper(st)) in _FILECACHE) {
+ return _FILECACHE[c]
+ }
+ if (match(st, /^[ \t]*\\[ \t]*\\/)) {
+ if (match(substr(st, a = RLENGTH + 1), /^[ \t]*([0-9A-Za-z\-]+)[ \t]*(\\[ \t]*([A-Za-z])[ \t]*\$[ \t]*)?(\\[ \t]*([0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)*[ \t]*)?(([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)) {
+ a = a + RLENGTH
+ d = (A[3] ? ("\\" A[3] "$") : "") "\\" A[5]
gsub(/[ \t]*\\[ \t]*/, "\\", d)
- if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) {
- return (_FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st])
- }
- _FILEDIR[c = _FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d
- if (A[8]) {
- _FILEDIRFL[c]
- }
- if (r) {
- _FILEROOT[c] = r
+ if ((st = toupper((r = "\\\\" A[1]) d (n = A[8]))) in _FILECACHE) {
+ return (_FILECACHE[substr(c, 1, a)] = _FILECACHE[st])
}
+ _FILEDIR[c = _FILECACHE[substr(c, 1, a)] = _FILECACHE[st] = ++_file_rootcntr] = d
+ _FILEDIRFL[c]
+ _FILEROOT[c] = r
+ } else {
+ _filepath_err = "UNC"
+ return ""
}
- if (n) {
- if (match(n, /\.[^\.]*$/)) {
- _FILEXT[c] = substr(n, RSTART)
- _FILENAM[c] = substr(n, 1, RSTART - 1)
- } else {
- _FILENAM[c] = n
- }
+ } else {
+ match(st, /^(([ \t]*\.[ \t]*\\[ \t]*)|(([ \t]*([A-Za-z])[ \t]*(\:)[ \t]*)?([ \t]*(\\)[ \t]*)?))([ \t]*(([ \t]*[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+( +[0-9A-Za-z_\!\+\-\[\]\(\)\{\}\~\.]+)*[ \t]*\\)+)[ \t]*)?([ \t]*([0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+( +[0-9A-Za-z_\!\+\.\~\-\[\]\{\}\(\)]+)*)[ \t]*)?/, A)
+ if (! RLENGTH) {
+ return ""
+ }
+ d = A[8] A[10]
+ gsub(/[ \t]*\\[ \t]*/, "\\", d)
+ if ((st = toupper((r = A[5] A[6]) d (n = A[14]))) in _FILECACHE) {
+ return (_FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st])
+ }
+ _FILEDIR[c = _FILECACHE[substr(c, 1, RLENGTH)] = _FILECACHE[st] = ++_file_rootcntr] = d
+ if (A[8]) {
+ _FILEDIRFL[c]
+ }
+ if (r) {
+ _FILEROOT[c] = r
}
- return c
- }
- return ""
- }
-
- function fileri(f)
- {
- if ((f = filerdnehndi(f)) == "") {
- return _FILEIO_R
- }
- if (f in _FILEROOT) {
- return _FILEROOT[f]
- }
- if ((_FILEIO_RD, f) in _FILEROOT) {
- return _FILEROOT[_FILEIO_RD, f]
}
- return (_FILEROOT[_FILEIO_RD, f] = _FILEIO_R)
- }
-
- function hujf(a, b, c)
- {
- _conl("hujf(" a "," b "," c ")")
- }
-
- function ncmp_str_idx(i1, v1, i2, v2)
- {
- return ((i1 < i2 ? 1 : -1))
- }
-
- function test_cfg(p, z, AA0, a)
- {
- AA0[1]
- _fclass = _cfguid(p = _getuid(_classys), _NOP, _NOP, _NOP, _NOP, _classys)
- _conl()
- _conline()
- _conl()
- _drawuid(p)
- _fclass = _cfguid(p = _getuid(_classys), AA0, AA0, AA0, AA0, _classys)
- _conl()
- _conline()
- _conl()
- _drawuid(p)
- a = _getuid(z = _fclass = _cfguid(p = _getuid(_classys), p, "<", ">", "ab", "cd"))
- _conl("### " a "########")
- _conline()
- _conl()
- _drawuid(p)
- a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, 0, 0, _NOP, z))
- _conl("### " a "########")
- _conline()
- _conl()
- _drawuid(p)
- a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, "^", "$", z, _classys))
- _conl("### " a "########")
- _conline()
- _conl()
- _drawuid(p)
- _fclass = _cfguid(p = _getuid(_classys), "oblptr", "pfx", "sfx", "abcd")
- _conl()
- _conline()
- _conl()
- _drawuid(p)
- _conl("```````````````````" z "'''''''''" ((_isptr(z) ? " ptr" : " not ptr")))
- _drawuid(z)
- }
-
- function test_splitstr(A)
- {
- AA0[-1] = "huj"
- AA0["A"] = "pizda"
- AA0[1] = "zhopa"
- delete AB0[AB0[""] = ""]
- AC0[-1] = "HUJ"
- AC0["A"] = "PIZDA"
- AC0[1] = "ZHOPA"
- _SPLITSTRB0["1"]
- wonl = ""
- _tstv(0, A, 0, "_tstv")
- _conl(wonl)
- _wrfile("wonl.out", wonl)
- }
-
- function test_uid(p, i)
- {
- _fclass = _cfguid(p = _getuid(_classys), p, "pfx", "sfx", "abc")
- _conl("_fclass uid: " _getuid(_fclass))
- _drawuid(_fclass)
- _conl("_classys uid: " _getuid(_classys)) _drawuid(_classys)
- for (i = 1; i < 81; i++) {
- _conl(i ": " _getuid(_fclass))
- }
- _drawuid(_fclass)
- }
-
- function tst_splitstr(t, A, R, r)
- {
- delete A
- A["not cleared"]
- _wonl()
- _wonline("_splitstr(" ((isarray(t) ? "ARR" ((length(t) > 0 ? "#" ((t[1] != "zhopa" ? "U" : "l")) : "")) : _val0(t))) ",A" ((isarray(R) ? ", ARR" ((length(R) > 0 ? "#" ((R[1] != "zhopa" ? "U" : "l")) : "")) : ", " _val0(R))) "):")
- _wonl(_val0(r = _splitstr(t, A, R)))
- _wonl("arrary A:")
- _wonl(_dumparr(A))
- return r
- }
-
- function tts(p, uidel, psfx, cnt, chr, p5, p6, p7, im)
- {
- im = " "
- im = ".. .."
- _conl("ret: " _qparam(im, p, uidel, psfx, cnt, chr, p5, p6, p7) "'")
- _conl("mask: `" _qparamask "'")
- }
-
- function zorr(A, i, r)
- {
- if (i in A) {
- _conl("`" i "' in A")
- } else {
- _conl("`" i "' not in A")
+ if (n) {
+ if (match(n, /\.[^\.]*$/)) {
+ _FILEXT[c] = substr(n, RSTART)
+ _FILENAM[c] = substr(n, 1, RSTART - 1)
+ } else {
+ _FILENAM[c] = n
+ }
}
- r = A[i] == "" && A[i] == 0
- _conl("A[" i "] status is " r)
- return
- a = a + -a
- _conl("``````````````" a "''''''''''''''''")
- }
-
- function zzer()
- {
+ return c
}
+ return ""
+}
+
+#_____________________________________________________
+function fileri(f)
+{
+ if ((f = filerdnehndi(f)) == "") {
+ return _FILEIO_R
+ }
+ if (f in _FILEROOT) {
+ return _FILEROOT[f]
+ }
+ if ((_FILEIO_RD, f) in _FILEROOT) {
+ return _FILEROOT[_FILEIO_RD, f]
+ }
+ return (_FILEROOT[_FILEIO_RD, f] = _FILEIO_R)
+}
+
+function hujf(a, b, c)
+{
+ _conl("hujf(" a "," b "," c ")")
+}
+
+#___________________________________________________________
+function ncmp_str_idx(i1, v1, i2, v2)
+{
+ #######################
+ return (i1 < i2 ? 1 : -1)
+}
+
+function test_cfg(p, z, AA0, a)
+{
+ AA0[1]
+ _fclass = _cfguid(p = _getuid(_classys), _NOP, _NOP, _NOP, _NOP, _classys)
+ _conl()
+ _conline()
+ _conl()
+ _drawuid(p)
+ _fclass = _cfguid(p = _getuid(_classys), AA0, AA0, AA0, AA0, _classys)
+ _conl()
+ _conline()
+ _conl()
+ _drawuid(p)
+ a = _getuid(z = _fclass = _cfguid(p = _getuid(_classys), p, "<", ">", "ab", "cd"))
+ _conl("### " a "########")
+ _conline()
+ _conl()
+ _drawuid(p)
+ a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, 0, 0, _NOP, z))
+ _conl("### " a "########")
+ _conline()
+ _conl()
+ _drawuid(p)
+ a = _getuid(_fclass = _cfguid(p = _getuid(_classys), z, "^", "$", z, _classys))
+ _conl("### " a "########")
+ _conline()
+ _conl()
+ _drawuid(p)
+ _fclass = _cfguid(p = _getuid(_classys), "oblptr", "pfx", "sfx", "abcd")
+ _conl()
+ _conline()
+ _conl()
+ _drawuid(p)
+ _conl("```````````````````" z "'''''''''" (_isptr(z) ? " ptr" : " not ptr"))
+ _drawuid(z)
+}
+
+function test_splitstr(A)
+{
+ AA0[-1] = "huj"
+ AA0["A"] = "pizda"
+ AA0[1] = "zhopa"
+ delete AB0[AB0[""] = ""]
+ AC0[-1] = "HUJ"
+ AC0["A"] = "PIZDA"
+ AC0[1] = "ZHOPA"
+ _SPLITSTRB0["1"]
+ wonl = ""
+ _tstv(0, A, 0, "_tstv")
+ _conl(wonl)
+ _wrfile("wonl.out", wonl)
+}
+
+function test_uid(p, i)
+{
+ #test_cfg()
+ #return
+ _fclass = _cfguid(p = _getuid(_classys), p, "pfx", "sfx", "abc")
+ #_fclass=_cfguid(p=_getuid(_classys),_NOP,_NOP,_NOP,"",_classys)
+ _conl("_fclass uid: " _getuid(_fclass))
+ _drawuid(_fclass)
+ _conl("_classys uid: " _getuid(_classys)) _drawuid(_classys)
+ for (i = 1; i < 81; i++) {
+ _conl(i ": " _getuid(_fclass))
+ }
+ _drawuid(_fclass)
+}
+
+function tst_splitstr(t, A, R, r)
+{
+ delete A
+ A["not cleared"]
+ _wonl()
+ _wonline("_splitstr(" (isarray(t) ? "ARR" (length(t) > 0 ? "#" (t[1] != "zhopa" ? "U" : "l") : "") : _val0(t)) ",A" (isarray(R) ? ", ARR" (length(R) > 0 ? "#" (R[1] != "zhopa" ? "U" : "l") : "") : ", " _val0(R)) "):")
+ _wonl(_val0(r = _splitstr(t, A, R)))
+ _wonl("arrary A:")
+ _wonl(_dumparr(A))
+ return r
+}
+
+function tts(p, uidel, psfx, cnt, chr, p5, p6, p7, im)
+{
+ im = " "
+ im = ".. .."
+ _conl("ret: " _qparam(im, p, uidel, psfx, cnt, chr, p5, p6, p7) "'")
+ _conl("mask: `" _qparamask "'")
+}
+
+# # - p is array
+# ` - p is ptr detected in array _CLASSPTR(for _typ); or p is ptr detected in array A(for _typa)
+# 0 - p is undefined
+
+# 2 - p is string==""
+# 3 - p is string!=""
+# 4 - p is number 0
+# 5 - p is any number except 0(positive and negative)
+
+# str: _typ(p)+0 !_typ(p)+0
+# str/ptr _typ(p)>0 _typ(p)<1
+# str/arr "`">_typ(p0) && _t0
+# str/ptr/arr _typ(p) !_typ(p)
+# ptr _typ(p)=="`" _typ(p)<"`" ?
+# ptr/arr _typ(p)+0!=_t0
+# arr _typ(p)=="#" _typ(p)>"#" ?
+function zorr(A, i, r)
+{
+ if (i in A) {
+ _conl("`" i "' in A")
+ } else {
+ _conl("`" i "' not in A")
+ }
+ r = A[i] == "" && A[i] == 0
+ _conl("A[" i "] status is " r)
+ return
+ a = a + -a
+ _conl("``````````````" a "''''''''''''''''")
+}
+
+#_____________________________________________________________________________
+function zzer()
+{
+ ################################################################
+}
diff --git a/test/profile7.awk b/test/profile7.awk
index 454694f9..815aebb8 100644
--- a/test/profile7.awk
+++ b/test/profile7.awk
@@ -5,6 +5,8 @@ BEGIN {
print 1 % (10 * 10)
print (10 * 5) / 2
print 10 * (5 / 2)
+ print 10 - (1 + 3 * 3)
+ print 10 - (3 * 2 + 1)
a = 5
b = 3
print a - 1 - b
diff --git a/test/profile7.ok b/test/profile7.ok
index d65afa86..10da2eb4 100644
--- a/test/profile7.ok
+++ b/test/profile7.ok
@@ -5,8 +5,10 @@
1 print 1 / (10 * 10)
1 print 1 % 10 * 10
1 print 1 % (10 * 10)
- 1 print 10 * 5 / 2
- 1 print 10 * 5 / 2
+ 1 print (10 * 5) / 2
+ 1 print 10 * (5 / 2)
+ 1 print 10 - (1 + 3 * 3)
+ 1 print 10 - (3 * 2 + 1)
1 a = 5
1 b = 3
1 print a - 1 - b
diff --git a/test/profile8.ok b/test/profile8.ok
index 763c6fef..2b9c156f 100644
--- a/test/profile8.ok
+++ b/test/profile8.ok
@@ -1,23 +1,21 @@
- # Rule(s)
-
- {
- if (0) {
- } else {
- }
+{
+ if (0) {
+ } else {
}
+}
- {
- while (0) {
- }
+{
+ while (0) {
}
+}
- {
- do {
- } while (0)
- }
+{
+ do {
+ } while (0)
+}
- {
- for (;;) {
- }
+{
+ for (;;) {
}
+}
diff --git a/test/profile9.awk b/test/profile9.awk
new file mode 100644
index 00000000..16252cea
--- /dev/null
+++ b/test/profile9.awk
@@ -0,0 +1,9 @@
+# Some
+# header
+# comments
+
+# Add up
+{ sum += $1 }
+
+# Print sum
+END { print sum }
diff --git a/test/profile9.ok b/test/profile9.ok
new file mode 100644
index 00000000..34f7a96b
--- /dev/null
+++ b/test/profile9.ok
@@ -0,0 +1,14 @@
+# Some
+# header
+# comments
+
+# Add up
+{
+ sum += $1
+}
+
+# Print sum
+END {
+ print sum
+}
+
diff --git a/test/rand.ok b/test/rand.ok
index 60432b95..4ec90dd6 100644
--- a/test/rand.ok
+++ b/test/rand.ok
@@ -1 +1 @@
- 62 67 88 6 35 77 3 68 30 96 90 26 35 8 88 93 49 53 37
+ 90 23 5 64 38 61 72 5 82 80 33 71 33 34 55 60 90 88 7
diff --git a/test/randtest.ok b/test/randtest.ok
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/randtest.ok
diff --git a/test/randtest.sh b/test/randtest.sh
new file mode 100755
index 00000000..b17fda73
--- /dev/null
+++ b/test/randtest.sh
@@ -0,0 +1,113 @@
+# THIS PURPOSELY DOES NOT HAVE A !# LINE !!!!
+#
+# Date: Mon, 9 Sep 2013 14:49:43 -0700
+# From: Bob Jewett <jewett@bill.scs.agilent.com>
+# Message-Id: <201309092149.r89Lnh94010909@bill.scs.agilent.com>
+# To: arnold@skeeve.com
+# Subject: Re: [bug-gawk] Bug in random() in builtin.c
+#
+# Hi Arnold,
+#
+# Attached below is a script that tests gawk for this particular
+# rand() problem. The pair-wise combinations show a strong
+# autocorrelation for a delay of 31 pairs of rand() samples.
+#
+# The script prints out the measured autocorrelation for a record
+# of NSAMPLES pairs. It also prints a fail message at the end if
+# it fails.
+#
+# If you want to see the autocorrelation values, there is a print
+# statement that if uncommented will save them to a file.
+#
+# Please let me know if the mailer screws up the transfer or
+# if you have any questions about the test.
+#
+# Best regards,
+# Bob
+#
+# -------------- test_pair_power_autocorrelation -----------------------
+#
+#!/bin/ksh
+
+#GAWK=/bin/gawk
+
+# ADR: Get GAWK from the environment.
+# Additional note: This wants ksh/bash for the use of $RANDOM below to
+# seed the generator. However, shells that don't provide it won't be
+# a problem since gawk will then seed the generator with the time of day,
+# as srand() will be called without an argument.
+
+# large NSAMPLES and NRUNS will bring any correlation out of the noise better
+NSAMPLES=1024; MAX_ALLOWED_SIGMA=5; NRUNS=50;
+
+$GAWK 'BEGIN{
+ srand('$RANDOM');
+ nsamples=('$NSAMPLES');
+ max_allowed_sigma=('$MAX_ALLOWED_SIGMA');
+ nruns=('$NRUNS');
+ for(tau=0;tau<nsamples/2;tau++) corr[tau]=0;
+
+ for(run=0;run<nruns;run++) {
+ sum=0;
+
+ # Fill an array with a sequence of samples that are a
+ # function of pairs of rand() values.
+
+ for(i=0;i<nsamples;i++) {
+ samp[i]=((rand()-0.5)*(rand()-0.5))^2;
+ sum=sum+samp[i];
+ }
+
+ # Subtract off the mean of the sequence:
+
+ mean=sum/nsamples;
+ for(i=0;i<nsamples;i++) samp[i]=samp[i]-mean;
+
+ # Calculate an autocorrelation function on the sequence.
+ # Because the values of rand() should be independent, there
+ # should be no peaks in the autocorrelation.
+
+ for(tau=0;tau<nsamples/2;tau++) {
+ sum=0;
+ for(i=0;i<nsamples/2;i++) sum=sum+samp[i]*samp[i+tau];
+ corr[tau]=corr[tau]+sum;
+ }
+
+ }
+ # Normalize the autocorrelation to the tau=0 value.
+
+ max_corr=corr[0];
+ for(tau=0;tau<nsamples/2;tau++) corr[tau]=corr[tau]/max_corr;
+
+ # OPTIONALLY Print out the autocorrelation values:
+
+ # for(tau=0;tau<nsamples/2;tau++) print tau, corr[tau] > "pairpower_corr.data";
+
+ # Calculate the sigma for the non-zero tau values:
+
+ power_sum=0;
+
+ for(tau=1;tau<nsamples/2;tau++) power_sum=power_sum+(corr[tau])^2;
+
+ sigma=sqrt(power_sum/(nsamples/2-1));
+
+ # See if any of the correlations exceed a reasonable number of sigma:
+
+ passed=1;
+ for(tau=1;tau<nsamples/2;tau++) {
+ if ( abs(corr[tau])/sigma > max_allowed_sigma ) {
+ print "Tau=", tau ", Autocorr=", corr[tau]/sigma, "sigma";
+ passed=0;
+ }
+ }
+ if(!passed) {
+ print "Test failed."
+ exit(1);
+ }
+ else exit (0);
+ }
+
+function abs(abs_input) { return(sqrt(abs_input^2)) ; }
+'
+
+exit 0
diff --git a/test/rebuild.awk b/test/rebuild.awk
new file mode 100644
index 00000000..7320f192
--- /dev/null
+++ b/test/rebuild.awk
@@ -0,0 +1,5 @@
+{
+ $1 = "test"
+ print $0
+ print typeof($2)
+}
diff --git a/test/rebuild.in b/test/rebuild.in
new file mode 100644
index 00000000..2f16a825
--- /dev/null
+++ b/test/rebuild.in
@@ -0,0 +1 @@
+a 6.3
diff --git a/test/rebuild.ok b/test/rebuild.ok
new file mode 100644
index 00000000..0fe72e23
--- /dev/null
+++ b/test/rebuild.ok
@@ -0,0 +1,2 @@
+test 6.3
+strnum
diff --git a/test/rwarray.awk b/test/rwarray.awk
index 0cb214ee..86a4b589 100644
--- a/test/rwarray.awk
+++ b/test/rwarray.awk
@@ -4,6 +4,13 @@ BEGIN {
while ((getline word) > 0)
dict[word] = word word
+ re_sub = "/typed-regex/"
+ dict[re_sub] = @/search me/
+
+ strnum_sub = "strnum-sub"
+ split("-2.4", f)
+ dict[strnum_sub] = f[1]
+
n = asorti(dict, dictindices)
for (i = 1; i <= n; i++)
printf("dict[%s] = %s\n", dictindices[i], dict[dictindices[i]]) > "orig.out"
@@ -12,7 +19,6 @@ BEGIN {
ret = writea("orig.bin", dict)
printf "writea() returned %d, expecting 1\n", ret
-
ret = reada("orig.bin", dict)
printf "reada() returned %d, expecting 1\n", ret
@@ -37,4 +43,12 @@ BEGIN {
if (ret == 0 && !("KEEPIT" in ENVIRON))
system("rm -f orig.bin orig.out new.out")
}
+
+ if (typeof(dict[re_sub]) != "regexp")
+ printf("dict[\"%s\"] should be regexp, is %s\n",
+ re_sub, typeof(dict[re_sub]));
+
+ if (typeof(dict[strnum_sub]) != "strnum")
+ printf("dict[\"%s\"] should be strnum, is %s\n",
+ strnum_sub, typeof(dict[strnum_sub]));
}
diff --git a/test/shadowbuiltin.awk b/test/shadowbuiltin.awk
new file mode 100644
index 00000000..3ae21725
--- /dev/null
+++ b/test/shadowbuiltin.awk
@@ -0,0 +1,10 @@
+function foo(gensub)
+{
+ print gensub
+ print lshift(1, 1)
+}
+
+BEGIN {
+ x = 5
+ foo(x)
+}
diff --git a/test/shadowbuiltin.ok b/test/shadowbuiltin.ok
new file mode 100644
index 00000000..47586a86
--- /dev/null
+++ b/test/shadowbuiltin.ok
@@ -0,0 +1,2 @@
+5
+2
diff --git a/test/sourcesplit.ok b/test/sourcesplit.ok
new file mode 100644
index 00000000..7ed6ff82
--- /dev/null
+++ b/test/sourcesplit.ok
@@ -0,0 +1 @@
+5
diff --git a/test/status-close.awk b/test/status-close.awk
new file mode 100644
index 00000000..345bea49
--- /dev/null
+++ b/test/status-close.awk
@@ -0,0 +1,14 @@
+BEGIN {
+ cat = "cat ; exit 3"
+ print system("echo xxx | (cat ; exit 4)")
+
+ print "YYY" | cat
+
+ print close(cat)
+
+ echo = "echo boo ; exit 5"
+ echo | getline boo
+ print "got", boo
+
+ print close(echo)
+}
diff --git a/test/status-close.ok b/test/status-close.ok
new file mode 100644
index 00000000..ad3c0ce1
--- /dev/null
+++ b/test/status-close.ok
@@ -0,0 +1,6 @@
+xxx
+4
+YYY
+3
+got boo
+5
diff --git a/test/strftfld.awk b/test/strftfld.awk
new file mode 100644
index 00000000..26f75a5a
--- /dev/null
+++ b/test/strftfld.awk
@@ -0,0 +1,3 @@
+{
+ print split(strftime($1), f)
+}
diff --git a/test/strftfld.in b/test/strftfld.in
new file mode 100644
index 00000000..c1175143
--- /dev/null
+++ b/test/strftfld.in
@@ -0,0 +1 @@
+%F %T
diff --git a/test/strftfld.ok b/test/strftfld.ok
new file mode 100644
index 00000000..d00491fd
--- /dev/null
+++ b/test/strftfld.ok
@@ -0,0 +1 @@
+1
diff --git a/test/strnum2.awk b/test/strnum2.awk
new file mode 100644
index 00000000..44931d5f
--- /dev/null
+++ b/test/strnum2.awk
@@ -0,0 +1,18 @@
+BEGIN {
+ split(" 1.234 ", f, "|") # create a numeric string (strnum) value
+ OFMT = "%.1f"
+ CONVFMT = "%.2f"
+
+ # Check whether a strnum is displayed the same way before and
+ # after force_number is called. Also, should numeric strings
+ # be formatted with OFMT and CONVFMT or show the original string value?
+
+ print f[1] # OFMT
+ print (f[1] "") # CONVFMT
+
+ # force conversion to NUMBER if it has not happened already
+ x = f[1]+0
+
+ print f[1] # OFMT
+ print (f[1] "") # CONVFMT
+}
diff --git a/test/strnum2.ok b/test/strnum2.ok
new file mode 100644
index 00000000..63898bd4
--- /dev/null
+++ b/test/strnum2.ok
@@ -0,0 +1,4 @@
+ 1.234
+ 1.234
+ 1.234
+ 1.234
diff --git a/test/strtonum1.awk b/test/strtonum1.awk
new file mode 100644
index 00000000..79d6ad13
--- /dev/null
+++ b/test/strtonum1.awk
@@ -0,0 +1,5 @@
+BEGIN {
+ x = "011"
+ print x+0 # trigger NUMCUR
+ print strtonum(x)
+}
diff --git a/test/strtonum1.ok b/test/strtonum1.ok
new file mode 100644
index 00000000..48a9ed43
--- /dev/null
+++ b/test/strtonum1.ok
@@ -0,0 +1,2 @@
+11
+9
diff --git a/test/symtab6.ok b/test/symtab6.ok
index 7de717a0..34c10636 100644
--- a/test/symtab6.ok
+++ b/test/symtab6.ok
@@ -9,7 +9,7 @@ FILENAME: ""
FNR: 0
FPAT: "[^[:space:]]+"
FS: " "
-FUNCTAB: array, 41 elements
+FUNCTAB: array, 42 elements
IGNORECASE: 0
LINT: 0
NF: 0
diff --git a/test/symtab8.ok b/test/symtab8.ok
index da29b585..0cf40fe9 100644
--- a/test/symtab8.ok
+++ b/test/symtab8.ok
@@ -9,7 +9,7 @@ FIELDWIDTHS: ""
FNR: 1
FPAT: "[^[:space:]]+"
FS: " "
-FUNCTAB: array, 41 elements
+FUNCTAB: array, 42 elements
IGNORECASE: 0
LINT: 0
NF: 1
diff --git a/test/testext.ok b/test/testext.ok
index a828ecb2..897a7336 100644
--- a/test/testext.ok
+++ b/test/testext.ok
@@ -23,6 +23,12 @@ var_test() returned 1, test_var = 42
test_errno() returned 1, ERRNO = No child processes
+fubar = 9
+rumpus = -5
+uid matches 1
+api_major matches 1
+test_deferred returns 1
+
length of test_array is 10, should be 10
test_array_size: incoming size is 10
test_array_size() returned 1, length is now 0
@@ -69,6 +75,12 @@ test_scalar_reserved: could not update new_value2 for ARGC - pass
test_indirect_var: sym_lookup of NR passed
test_indirect_var: value of NR is 3
test_indirect_var() return 1
+
+test_get_file returned 0
+File [.test.alias] nr [1]: line 1
+File [.test.alias] nr [2]: line 2
+File [.test.alias] nr [3]: line 3
+
answer_num = 42
message_string = hello, world
new_array["hello"] = "world"
diff --git a/test/timeout.awk b/test/timeout.awk
new file mode 100644
index 00000000..ccf4537d
--- /dev/null
+++ b/test/timeout.awk
@@ -0,0 +1,26 @@
+BEGIN {
+ cmd = "echo hello; sleep 1; echo goodbye"
+
+ print "With timeouts"
+ PROCINFO[cmd, "READ_TIMEOUT"] = 300
+ while ((rc = (cmd | getline x)) > 0)
+ print x
+ if (rc < 0)
+ print rc, (PROCINFO["errno"] != 0), (ERRNO != "")
+ print (close(cmd) != 0)
+
+ PROCINFO[cmd, "RETRY"]
+ print ""
+ print "With timeouts and retries"
+ while (((rc = (cmd | getline x)) > 0) || (rc == -2)) {
+ if (rc > 0) {
+ print x
+ n = 0
+ }
+ else
+ print ++n, "timed out; trying again"
+ }
+ if (rc < 0)
+ print rc, (PROCINFO["errno"] != 0), (ERRNO != "")
+ print (close(cmd) != 0)
+}
diff --git a/test/timeout.ok b/test/timeout.ok
new file mode 100644
index 00000000..a388747b
--- /dev/null
+++ b/test/timeout.ok
@@ -0,0 +1,12 @@
+With timeouts
+hello
+-1 1 1
+1
+
+With timeouts and retries
+hello
+1 timed out; trying again
+2 timed out; trying again
+3 timed out; trying again
+goodbye
+0
diff --git a/test/typedregex1.awk b/test/typedregex1.awk
new file mode 100644
index 00000000..f308a335
--- /dev/null
+++ b/test/typedregex1.awk
@@ -0,0 +1,296 @@
+# This file describes the semantics for hard regex constants
+# As much as possible it's executable code so that it can be used
+# (or split into) test cases for development and regression testing.
+
+function simple_tests( fbre, numresult, strresult)
+{
+ # usable as case value
+ switch ("foobaaar") {
+ case @/fo+ba+r/:
+ print "switch-case: ok"
+ break
+ default:
+ print "switch-case: fail"
+ break
+ }
+
+ # usable with ~ and !~
+ if ("foobaaar" ~ @/fo+ba+r/)
+ print "match ~: ok"
+ else
+ print "match ~: fail"
+
+ if ("quasimoto" !~ @/fo+ba+r/)
+ print "match !~: ok"
+ else
+ print "match !~: fail"
+
+ # assign to variable, use in match
+ fbre = @/fo+ba+r/
+ if ("foobaaar" ~ fbre)
+ print "variable match ~: ok"
+ else
+ print "variable match ~: fail"
+
+ if ("quasimoto" !~ fbre)
+ print "variable match !~: ok"
+ else
+ print "variable match !~: fail"
+
+ # Use as numeric value, should be zero
+ numresult = fbre + 42
+ if (numresult == 42)
+ print "variable as numeric value: ok"
+ else
+ print "variable as numeric value: fail"
+
+ # Use as string value, should be string value of regexp text
+ strresult = "<" fbre ">"
+ if (strresult == "<fo+ba+r>")
+ print "variable as string value: ok"
+ else
+ print "variable as string value: fail", strresult
+
+ # typeof should work
+ if (typeof(@/fo+ba+r/) == "regexp")
+ print "typeof constant: ok"
+ else
+ print "typeof constant: fail"
+
+ if (typeof(fbre) == "regexp")
+ print "typeof variable: ok"
+ else
+ print "typeof variable: fail"
+
+ # conversion to number, works. should it be fatal?
+ fbre++
+ if (fbre == 1)
+ print "conversion to number: ok"
+ else
+ print "conversion to number: fail"
+
+ if (typeof(fbre) == "number")
+ print "typeof variable after conversion: ok"
+ else
+ print "typeof variable after conversion: fail"
+}
+
+function match_tests( fbre, fun)
+{
+ if (match("foobaaar", @/fo+ba+r/))
+ print "match(constant): ok"
+ else
+ print "match(constant): fail"
+
+ fbre = @/fo+ba+r/
+ if (match("foobaaar", fbre))
+ print "match(variable): ok"
+ else
+ print "match(variable): fail"
+
+ fun = "match"
+ if (@fun("foobaaar", @/fo+ba+r/))
+ print "match(constant) indirect: ok"
+ else
+ print "match(constant) indirect: fail"
+
+ if (@fun("foobaaar", fbre))
+ print "match(variable) indirect: ok"
+ else
+ print "match(variable) indirect: fail"
+}
+
+function sub_tests( fbre, count, target, fun)
+{
+ target = "abc foobaar def foobar ghi"
+ count = sub(@/fo+ba+r/, "XX", target)
+ if (count == 1 && target == "abc XX def foobar ghi")
+ print "sub(constant): ok"
+ else
+ print "sub(constant): fail"
+
+ fbre = @/fo+ba+r/
+ target = "abc foobaar def foobar ghi"
+ count = sub(fbre, "XX", target)
+ if (count == 1 && target == "abc XX def foobar ghi")
+ print "sub(variable): ok"
+ else
+ print "sub(variable): fail"
+
+ fun = "sub"
+ $0 = "abc foobaar def foobar ghi"
+ count = @fun(@/fo+ba+r/, "XX")
+ if (count == 1 && $0 == "abc XX def foobar ghi")
+ print "sub(constant) indirect: ok"
+ else
+ print "sub(constant) indirect: fail"
+
+ $0 = "abc foobaar def foobar ghi"
+ count = @fun(fbre, "XX")
+ if (count == 1 && $0 == "abc XX def foobar ghi")
+ print "sub(variable) indirect: ok"
+ else
+ print "sub(variable) indirect: fail"
+}
+
+function gsub_tests( fbre, count, target, fun)
+{
+ target = "abc foobaar def foobar ghi"
+ count = gsub(@/fo+ba+r/, "XX", target)
+ if (count == 2 && target == "abc XX def XX ghi")
+ print "gsub(constant): ok"
+ else
+ print "gsub(constant): fail"
+
+ fbre = @/fo+ba+r/
+ target = "abc foobaar def foobar ghi"
+ count = gsub(fbre, "XX", target)
+ if (count == 2 && target == "abc XX def XX ghi")
+ print "gsub(variable): ok"
+ else
+ print "gsub(variable): fail"
+
+ fun = "gsub"
+ $0 = "abc foobaar def foobar ghi"
+ count = @fun(@/fo+ba+r/, "XX")
+ if (count == 2 && $0 == "abc XX def XX ghi")
+ print "gsub(constant) indirect: ok"
+ else
+ print "gsub(constant) indirect: fail"
+
+ $0 = "abc foobaar def foobar ghi"
+ count = @fun(fbre, "XX")
+ if (count == 2 && $0 == "abc XX def XX ghi")
+ print "gsub(variable) indirect: ok"
+ else
+ print "gsub(variable) indirect: fail"
+}
+
+function gensub_tests( fbre, result, target, fun)
+{
+ target = "abc foobaar def foobar ghi"
+ result = gensub(@/fo+ba+r/, "XX", "g", target)
+ if (result == "abc XX def XX ghi")
+ print "gensub(constant): ok"
+ else
+ print "gensub(constant): fail"
+
+ fbre = @/fo+ba+r/
+ target = "abc foobaar def foobar ghi"
+ result = gensub(fbre, "XX", "g", target)
+ if (result == "abc XX def XX ghi")
+ print "gensub(variable): ok"
+ else
+ print "gensub(variable): fail"
+
+ fun = "gensub"
+ $0 = "abc foobaar def foobar ghi"
+ result = @fun(@/fo+ba+r/, "XX", "g")
+ if (result == "abc XX def XX ghi")
+ print "gensub(constant) indirect: ok"
+ else
+ print "gensub(constant) indirect: fail"
+
+ $0 = "abc foobaar def foobar ghi"
+ result = @fun(fbre, "XX", "g")
+ if (result == "abc XX def XX ghi")
+ print "gensub(variable) indirect: ok"
+ else
+ print "gensub(variable) indirect: fail"
+
+ result = @fun(@/fo+ba+r/, "XX", "g", target)
+ if (result == "abc XX def XX ghi")
+ print "gensub(constant) indirect 2: ok"
+ else
+ print "gensub(constant) indirect 2: fail"
+
+ result = @fun(fbre, "XX", "g", target)
+ if (result == "abc XX def XX ghi")
+ print "gensub(variable) indirect 2: ok"
+ else
+ print "gensub(variable) indirect 2: fail"
+}
+
+function split_tests( fbre, data, seps, fun, b1)
+{
+ delete data
+ delete seps
+ b1 = split("a:b:c:d", data, @/:/, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "split(constant): ok"
+ else
+ print "split(constant): fail"
+
+ delete data
+ delete seps
+ fbre = @/:/
+ b1 = split("a:b:c:d", data, fbre, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "split(variable): ok"
+ else
+ print "split(variable): fail"
+
+ fun = "split"
+ delete data
+ delete seps
+ b1 = @fun("a:b:c:d", data, @/:/, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "split(constant) indirect: ok"
+ else
+ print "split(constant) indirect: fail"
+
+ delete data
+ delete seps
+ b1 = @fun("a:b:c:d", data, fbre, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "split(variable) indirect: ok"
+ else
+ print "split(variable) indirect: fail"
+}
+
+function patsplit_tests( fbre, data, seps, fun, b1)
+{
+ delete data
+ delete seps
+ b1 = patsplit("a:b:c:d", data, @/[a-z]+/, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "patsplit(constant): ok"
+ else
+ print "patsplit(constant): fail"
+
+ delete data
+ delete seps
+ fbre = @/[a-z]+/
+ b1 = patsplit("a:b:c:d", data, fbre, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "patsplit(variable): ok"
+ else
+ print "patsplit(variable): fail"
+
+ fun = "patsplit"
+ delete data
+ delete seps
+ b1 = @fun("a:b:c:d", data, @/[a-z]+/, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "patsplit(constant) indirect: ok"
+ else
+ print "patsplit(constant) indirect: fail"
+
+ delete data
+ delete seps
+ b1 = @fun("a:b:c:d", data, fbre, seps)
+ if (b1 == 4 && data[1] == "a" && seps[1] == ":")
+ print "patsplit(variable) indirect: ok"
+ else
+ print "patsplit(variable) indirect: fail"
+}
+
+BEGIN {
+ simple_tests()
+ match_tests()
+ sub_tests()
+ gsub_tests()
+ gensub_tests()
+ split_tests()
+ patsplit_tests()
+}
diff --git a/test/typedregex1.ok b/test/typedregex1.ok
new file mode 100644
index 00000000..03ef7cfa
--- /dev/null
+++ b/test/typedregex1.ok
@@ -0,0 +1,37 @@
+switch-case: ok
+match ~: ok
+match !~: ok
+variable match ~: ok
+variable match !~: ok
+variable as numeric value: ok
+variable as string value: ok
+typeof constant: ok
+typeof variable: ok
+conversion to number: ok
+typeof variable after conversion: ok
+match(constant): ok
+match(variable): ok
+match(constant) indirect: ok
+match(variable) indirect: ok
+sub(constant): ok
+sub(variable): ok
+sub(constant) indirect: ok
+sub(variable) indirect: ok
+gsub(constant): ok
+gsub(variable): ok
+gsub(constant) indirect: ok
+gsub(variable) indirect: ok
+gensub(constant): ok
+gensub(variable): ok
+gensub(constant) indirect: ok
+gensub(variable) indirect: ok
+gensub(constant) indirect 2: ok
+gensub(variable) indirect 2: ok
+split(constant): ok
+split(variable): ok
+split(constant) indirect: ok
+split(variable) indirect: ok
+patsplit(constant): ok
+patsplit(variable): ok
+patsplit(constant) indirect: ok
+patsplit(variable) indirect: ok
diff --git a/test/typedregex2.awk b/test/typedregex2.awk
new file mode 100644
index 00000000..e17df4be
--- /dev/null
+++ b/test/typedregex2.awk
@@ -0,0 +1,11 @@
+BEGIN {
+ x = @/xxx/
+ y = @/yyy/
+ print typeof(x), typeof(y)
+ print x, y
+
+ x++
+ y = y ""
+ print typeof(x), typeof(y)
+ print x, y
+}
diff --git a/test/typedregex2.ok b/test/typedregex2.ok
new file mode 100644
index 00000000..832ef551
--- /dev/null
+++ b/test/typedregex2.ok
@@ -0,0 +1,4 @@
+regexp regexp
+xxx yyy
+number string
+1 yyy
diff --git a/test/typedregex3.awk b/test/typedregex3.awk
new file mode 100644
index 00000000..ee6bcb69
--- /dev/null
+++ b/test/typedregex3.awk
@@ -0,0 +1,11 @@
+BEGIN {
+ a[1] = @/abc/
+ b[1][2][3] = @/xyz/
+ print typeof(a[1]), typeof(b[1][2][3])
+ print a[1], b[1][2][3]
+
+ a[1]++
+ b[1][2][3] ""
+ print typeof(a[1]), typeof(b[1][2][3])
+ print a[1], b[1][2][3]
+}
diff --git a/test/typedregex3.ok b/test/typedregex3.ok
new file mode 100644
index 00000000..9f8b881a
--- /dev/null
+++ b/test/typedregex3.ok
@@ -0,0 +1,4 @@
+regexp regexp
+abc xyz
+number regexp
+1 xyz
diff --git a/test/typeof1.awk b/test/typeof1.awk
new file mode 100644
index 00000000..c301030e
--- /dev/null
+++ b/test/typeof1.awk
@@ -0,0 +1,9 @@
+BEGIN {
+ a = 5 ; print typeof(a)
+ print typeof(b)
+ print typeof(@/foo/)
+ c = "foo" ; print typeof(c)
+ d[1] = 1 ; print typeof(d), typeof(d[1])
+ e = @/foo/ ; print typeof(e)
+ print typeof(@/bar/)
+}
diff --git a/test/typeof1.ok b/test/typeof1.ok
new file mode 100644
index 00000000..132cc24e
--- /dev/null
+++ b/test/typeof1.ok
@@ -0,0 +1,7 @@
+number
+untyped
+regexp
+string
+array number
+regexp
+regexp
diff --git a/test/typeof2.awk b/test/typeof2.awk
new file mode 100644
index 00000000..25da02e4
--- /dev/null
+++ b/test/typeof2.awk
@@ -0,0 +1,20 @@
+BEGIN {
+ print typeof(x)
+ x[1] = 3
+ print typeof(x)
+}
+
+function test1() {
+}
+
+function test2(p) {
+ p[1] = 1
+}
+
+BEGIN {
+ print typeof(a)
+ test1(a)
+ print typeof(a)
+ test2(a)
+ print typeof(a)
+}
diff --git a/test/typeof2.ok b/test/typeof2.ok
new file mode 100644
index 00000000..cc032a83
--- /dev/null
+++ b/test/typeof2.ok
@@ -0,0 +1,6 @@
+untyped
+array
+untyped
+gawk: typeof2.awk:16: warning: function `test1' called with more arguments than declared
+untyped
+array
diff --git a/test/typeof3.awk b/test/typeof3.awk
new file mode 100644
index 00000000..d148f373
--- /dev/null
+++ b/test/typeof3.awk
@@ -0,0 +1,19 @@
+BEGIN {
+ x = @/xx/
+ print typeof(x)
+ print x
+}
+
+# this set may not really be needed for the test
+BEGIN {
+ x = 4
+ print typeof(@/xxx/)
+ print typeof(3)
+ print x
+}
+
+BEGIN {
+ print typeof(x)
+ print typeof(a[1])
+ a[1][2] # fatals on this
+}
diff --git a/test/typeof3.ok b/test/typeof3.ok
new file mode 100644
index 00000000..a6cd6c4a
--- /dev/null
+++ b/test/typeof3.ok
@@ -0,0 +1,9 @@
+regexp
+xx
+regexp
+number
+4
+number
+unassigned
+gawk: typeof3.awk:18: fatal: attempt to use scalar `a["1"]' as an array
+EXIT CODE: 2
diff --git a/test/typeof4.awk b/test/typeof4.awk
new file mode 100644
index 00000000..62c2905c
--- /dev/null
+++ b/test/typeof4.awk
@@ -0,0 +1,13 @@
+BEGIN{ a["x"]["y"]["z"]="scalar" ; walk_array(a, "a")}
+function walk_array(arr, name, i, r)
+{
+ for (i in arr) {
+ r = typeof(arr[i])
+# printf("typeof(%s[%s]) = %s\n", name, i, r) > "/dev/stderr"
+ if (r == "array") {
+ walk_array(arr[i], name "[" i "]")
+ } else {
+ printf "%s[%s] = %s\n", name, i, arr[i]
+ }
+ }
+}
diff --git a/test/typeof4.ok b/test/typeof4.ok
new file mode 100644
index 00000000..fca0263d
--- /dev/null
+++ b/test/typeof4.ok
@@ -0,0 +1 @@
+a[x][y][z] = scalar
diff --git a/test/typeof5.awk b/test/typeof5.awk
new file mode 100644
index 00000000..30cd6aca
--- /dev/null
+++ b/test/typeof5.awk
@@ -0,0 +1,10 @@
+BEGIN {
+ print typeof($0)
+ print typeof($1)
+}
+
+{
+ $3 = $1
+ print typeof($2)
+ print typeof($3)
+}
diff --git a/test/typeof5.in b/test/typeof5.in
new file mode 100644
index 00000000..9daeafb9
--- /dev/null
+++ b/test/typeof5.in
@@ -0,0 +1 @@
+test
diff --git a/test/typeof5.ok b/test/typeof5.ok
new file mode 100644
index 00000000..80f8cf51
--- /dev/null
+++ b/test/typeof5.ok
@@ -0,0 +1,4 @@
+unassigned
+unassigned
+unassigned
+string
diff --git a/vms/ChangeLog b/vms/ChangeLog
index 2268148c..af9a9539 100644
--- a/vms/ChangeLog
+++ b/vms/ChangeLog
@@ -1,15 +1,24 @@
2017-03-25 John E. Malmberg <wb8tyw@qsl.net>
- * vmstest.com: Fix argarray teset.
+ * vmstest.com: Fix argarray teset.
+
+2016-12-22 John E. Malmberg <wb8tyw@qsl.net>
+
+ * vmsbuild.com, descrip.mms:
+ Update for new [.support] directory.
2016-11-24 John E. Malmberg <wb8tyw@qsl.net>
- * gawk_verb.com: correct location for gawk executable.
+ * gawk_verb.com: correct location for gawk executable.
2016-10-24 John E. Malmberg <wb8tyw@qsl.net>
- * backup_gawk_src.com: Do not backup entire git repository.
- * pcsi_product_gawk.com: Create a ZIP archive of PCSI kit.
+ * backup_gawk_src.com: Do not backup entire git repository.
+ * pcsi_product_gawk.com: Create a ZIP archive of PCSI kit.
+
+2016-10-23 Arnold D. Robbins <arnold@skeeve.com>
+
+ * General: Remove trailing whitespace from all relevant files.
2016-08-25 Arnold D. Robbins <arnold@skeeve.com>
@@ -110,6 +119,11 @@
* remove_old_gawk.com: Look for old gawk images that may
have been installed in the wrong directory.
+2015-07-02 John E. Malmberg <wb8tyw@qsl.net>
+
+ * build_gawk_pcsi_desc.com: Update to support new VMS
+ producer of VSI.
+
2015-05-19 Arnold D. Robbins <arnold@skeeve.com>
* 4.1.3: Release tar ball made.
diff --git a/vms/descrip.mms b/vms/descrip.mms
index 5e83b419..59816898 100644
--- a/vms/descrip.mms
+++ b/vms/descrip.mms
@@ -38,6 +38,7 @@
#
# location of various source files, relative to the 'main' directory
+SUPPORT = [.support]
VMSDIR = [.vms]
DOCDIR = [.doc]
MISSNGD = [.missing_d]
@@ -75,8 +76,9 @@ CFLOAT = /float=ieee/ieee_mode=denorm_results
.endif
CNAME = /NAME=(AS_IS,SHORT)
CC = cc/DECC/Prefix=All/NESTED_INCLUDE=NONE$(CFLOAT)
-CFLAGS = /Incl=([],[.vms])/Obj=[]/Def=($(CDEFS))$(CNAME) $(CCFLAGS)
-CEFLAGS = /Incl=([],[.vms],[.missing_d],[.extension])$(CNAME) $(CCFLAGS)
+CINC1 = [],[.VMS],$(SUPPORT)
+CFLAGS = /Incl=($(CINC1))/Obj=[]/Def=($(CDEFS))$(CNAME) $(CCFLAGS)
+CEFLAGS = /Incl=($(CINC1),[.missing_d],[.extension])$(CNAME) $(CCFLAGS)
LIBS = # DECC$SHR instead of VAXCRTL, no special link option needed
.endif !VAXC
.endif !GNUC
@@ -105,8 +107,8 @@ AWKOBJ1 = array.obj,awkgram.obj,builtin.obj,cint_array.obj,\
command.obj,debug.obj,dfa.obj,ext.obj,field.obj,\
floatcomp.obj,gawkapi.obj,gawkmisc.obj,getopt.obj,getopt1.obj
-AWKOBJ2 = int_array.obj,io.obj,main.obj,mpfr.obj,msg.obj,node.obj,\
- random.obj,re.obj,regex.obj,replace.obj,\
+AWKOBJ2 = int_array.obj,io.obj,localeinfo.obj,main.obj,mpfr.obj,msg.obj,\
+ node.obj,random.obj,re.obj,regex.obj,replace.obj,\
str_array.obj,symbol.obj,version.obj
AWKOBJS = $(AWKOBJ1),$(AWKOBJ2)
@@ -153,8 +155,8 @@ gawk.opt : $(MAKEFILE) config.h # create linker options file
$ @$(VMSDIR)gawk_ident.com
$(VMSCODE) : awk.h config.h $(VMSDIR)redirect.h $(VMSDIR)vms.h
-$(AWKOBJS) : awk.h gettext.h mbsupport.h regex.h dfa.h config.h \
- $(VMSDIR)redirect.h
+$(AWKOBJS) : awk.h gettext.h mbsupport.h $(SUPPORT)regex.h \
+ $(SUPPORT)dfa.h config.h $(VMSDIR)redirect.h
$(GAWKOBJ) : awk.h config.h $(VMSDIR)redirect.h
#-----------------------------------------------------------------------------
@@ -164,30 +166,32 @@ $(GAWKOBJ) : awk.h config.h $(VMSDIR)redirect.h
array.obj : array.c
awkgram.obj : awkgram.c awk.h
-builtin.obj : builtin.c floatmagic.h random.h
+builtin.obj : builtin.c floatmagic.h $(SUPPORT)random.h
cint_array.obj : cint_array.c
command.obj : command.c cmd.h
debug.obj : debug.c cmd.h
-dfa.obj : dfa.c dfa.h
+dfa.obj : $(SUPPORT)dfa.c $(SUPPORT)dfa.h
ext.obj : ext.c
eval.obj : eval.c
field.obj : field.c
floatcomp.obj : floatcomp.c
gawkaoi.obj : gawkapi.c
gawkmisc.obj : gawkmisc.c $(VMSDIR)gawkmisc.vms
-getopt.obj : getopt.c
-getopt1.obj : getopt1.c
+getopt.obj : $(SUPPORT)getopt.c
+getopt1.obj : $(SUPPORT)getopt1.c
int_array.obj : int_array.c
io.obj : io.c
+localeinfo.obj : $(SUPPORT)localeinfo.c
main.obj : main.c
msg.obj : msg.c
mpfr.obj : mpfr.c
node.obj : node.c
profile.obj : profile.c
-random.obj : random.c random.h
+random.obj : $(SUPPORT)random.c $(SUPPORT)random.h
re.obj : re.c
-regex.obj : regex.c regcomp.c regex_internal.c regexec.c regex.h \
- regex_internal.h
+regex.obj : $(SUPPORT)regex.c $(SUPPORT)regcomp.c \
+ $(SUPPORT)regex_internal.c $(SUPPORT)regexec.c \
+ $(SUPPORT)regex.h $(SUPPORT)regex_internal.h
str_array.obj : str_array.c
symbol.obj : symbol.c
version.obj : version.c
diff --git a/vms/vms_gawk.c b/vms/vms_gawk.c
index 4080e1db..0caab21f 100644
--- a/vms/vms_gawk.c
+++ b/vms/vms_gawk.c
@@ -16,7 +16,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-
+
/*
* vms_gawk.c - routines to parse the command line as a native DCL command
diff --git a/vms/vmsbuild.com b/vms/vmsbuild.com
index 984b83f0..9582c01c 100644
--- a/vms/vmsbuild.com
+++ b/vms/vmsbuild.com
@@ -19,7 +19,7 @@ $ then
$! assumes VAX
$ CC = "gcc"
$ if f$type(gcc).eqs."STRING" then CC = gcc
-$ CFLAGS = "/Incl=([],[.vms])/Obj=[]/Def=(''CDEFS')''CCFLAGS'"
+$ CFLAGS = "/Incl=([],[.vms],[.SUPPORT])/Obj=[]/Def=(''CDEFS')''CCFLAGS'"
$ LIBS = "gnu_cc:[000000]gcclib.olb/Library,sys$library:vaxcrtl.olb/Library"
$ if p2.eqs."DO_GNUC_SETUP" then set command gnu_cc:[000000]gcc
$ else !!GNUC
@@ -41,7 +41,8 @@ $ endif
$ CC = "cc/DECC/Prefix=All"
$ CNAME = "/NAME=(AS_IS,SHORT)
$ CINC = "/NESTED_INCLUDE=NONE"
-$ CFLAGS = "/Incl=([],[.vms])/Obj=[]/Def=(''CDEFS')''CINC'''CCFLAGS'"
+$ CINC1 = "[],[.vms],[.support]"
+$ CFLAGS = "/Incl=(''CINC1')/Obj=[]/Def=(''CDEFS')''CINC'''CCFLAGS'"
$ CFLAGS = CNAME + CFLOAT + CFLAGS
$ LIBS = "" ! DECC$SHR instead of VAXCRTL, no special link option needed
$ endif !VAXC
@@ -80,20 +81,21 @@ $ v1 = f$verify(1)
$ cc array.c
$ cc awkgram.c
$ cc builtin.c
-$ cc dfa.c
+$ cc [.support]dfa.c
$ cc ext.c
$ cc field.c
$ cc floatcomp.c
$ cc gawkmisc.c
-$ cc getopt.c
-$ cc getopt1.c
+$ cc [.support]getopt.c
+$ cc [.support]getopt1.c
$ cc io.c
+$ cc [.support]localeinfo.c
$ cc main.c
$ cc msg.c
$ cc node.c
-$ cc random.c
+$ cc [.support]random.c
$ cc re.c
-$ cc regex.c
+$ cc [.support]regex.c
$ cc replace.c
$ cc version.c
$ cc eval.c
@@ -120,7 +122,7 @@ $ close/noLog Fopt
$ create gawk.opt
! GAWK -- GNU awk
array.obj,awkgram.obj,builtin.obj,dfa.obj,ext.obj,field.obj,floatcomp.obj
-gawkmisc.obj,getopt.obj,getopt1.obj,io.obj
+gawkmisc.obj,getopt.obj,getopt1.obj,io.obj,localeinfo.obj
main.obj,msg.obj,node.obj
random.obj,re.obj,regex.obj,replace.obj,version.obj,eval.obj,profile.obj
command.obj,debug.obj,int_array.obj,cint_array.obj,gawkapi.obj,mpfr.obj